mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-05-20 12:49:02 +00:00
Format code according to Ktlint
This commit is contained in:
parent
cfd0559958
commit
e123e4c8af
513 changed files with 6894 additions and 5752 deletions
|
|
@ -3,7 +3,6 @@ apply plugin: 'kotlin-android'
|
|||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
apply plugin: 'com.noveogroup.android.check'
|
||||
apply plugin: 'realm-android'
|
||||
apply plugin: 'androidx.navigation.safeargs'
|
||||
apply plugin: 'com.google.firebase.firebase-perf'
|
||||
|
|
@ -17,11 +16,6 @@ buildscript {
|
|||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.2.2'
|
||||
classpath('com.noveogroup.android:check:1.2.5') {
|
||||
exclude module: 'checkstyle'
|
||||
exclude module: 'pmd-java'
|
||||
}
|
||||
classpath 'com.puppycrawl.tools:checkstyle:7.5'
|
||||
classpath 'net.sourceforge.pmd:pmd-java:5.5.3'
|
||||
}
|
||||
}
|
||||
|
|
@ -52,8 +46,8 @@ dependencies {
|
|||
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
|
||||
|
||||
//Dependency Injection
|
||||
implementation 'com.google.dagger:dagger:2.36'
|
||||
kapt 'com.google.dagger:dagger-compiler:2.36'
|
||||
implementation 'com.google.dagger:dagger:2.38'
|
||||
kapt 'com.google.dagger:dagger-compiler:2.38'
|
||||
compileOnly 'javax.annotation:javax.annotation-api:1.3.2'
|
||||
compileOnly 'com.github.pengrad:jdk9-deps:1.0'
|
||||
//App Compatibility and Material Design
|
||||
|
|
@ -73,13 +67,13 @@ dependencies {
|
|||
// IAP Handling / Verification
|
||||
implementation 'org.solovyev.android:checkout:1.2.3'
|
||||
//Facebook
|
||||
implementation('com.facebook.android:facebook-android-sdk:8.1.0') {
|
||||
implementation('com.facebook.android:facebook-android-sdk:11.3.0') {
|
||||
transitive = true
|
||||
}
|
||||
implementation 'fr.avianey.com.viewpagerindicator:library:2.4.1@aar'
|
||||
//RxJava
|
||||
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
|
||||
implementation 'io.reactivex.rxjava3:rxjava:3.0.13'
|
||||
implementation 'io.reactivex.rxjava3:rxjava:3.1.1'
|
||||
implementation 'io.reactivex.rxjava3:rxkotlin:3.0.1'
|
||||
implementation 'io.reactivex.rxjava2:rxjava:2.2.21'
|
||||
implementation "com.github.akarnokd:rxjava3-bridge:3.0.0"
|
||||
|
|
@ -94,16 +88,16 @@ dependencies {
|
|||
testImplementation 'androidx.test:core:1.4.0'
|
||||
testImplementation "com.google.truth:truth:1.0.1"
|
||||
testImplementation 'org.assertj:assertj-core:2.6.0'
|
||||
testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.2'
|
||||
testImplementation 'org.robolectric:robolectric:4.3'
|
||||
testImplementation 'org.robolectric:shadows-multidex:3.8'
|
||||
testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:2.7'
|
||||
testImplementation 'org.robolectric:robolectric:4.6.1'
|
||||
testImplementation 'org.robolectric:shadows-multidex:4.6.1'
|
||||
testImplementation 'org.mockito:mockito-core:2.25.0'
|
||||
testImplementation 'org.powermock:powermock-api-mockito2:1.7.0'
|
||||
testImplementation 'org.powermock:powermock-module-junit4-rule-agent:1.7.0'
|
||||
testImplementation 'org.powermock:powermock-module-junit4-rule:1.7.0'
|
||||
testImplementation 'org.powermock:powermock-module-junit4:1.7.0'
|
||||
//Leak Detection
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.5'
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
|
||||
//Push Notifications
|
||||
implementation platform('com.google.firebase:firebase-bom:28.3.0')
|
||||
implementation 'com.google.firebase:firebase-crashlytics'
|
||||
|
|
@ -112,7 +106,7 @@ dependencies {
|
|||
implementation 'com.google.firebase:firebase-config'
|
||||
implementation 'com.google.firebase:firebase-perf'
|
||||
implementation 'com.google.android.gms:play-services-auth:19.2.0'
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.20"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30"
|
||||
implementation 'com.nex3z:flow-layout:1.2.2'
|
||||
|
||||
implementation 'androidx.core:core-ktx:1.6.0'
|
||||
|
|
@ -147,8 +141,8 @@ android {
|
|||
buildConfigField "String", "TESTING_LEVEL", "\"production\""
|
||||
resConfigs "en", "bg", "de", "en-rGB", "es", "fr", "hr-rHR", "in", "it", "iw", "ja", "ko", "lt", "nl", "pl", "pt-rBR", "pt-rPT", "ru", "tr", "zh", "zh-rTW"
|
||||
|
||||
versionCode 3036
|
||||
versionName "3.3.1"
|
||||
versionCode 3044
|
||||
versionName "3.4"
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
|
|
@ -334,6 +328,4 @@ gradle.projectsEvaluated {
|
|||
}
|
||||
}
|
||||
|
||||
check { findbugs { skip true } }
|
||||
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ import org.solovyev.android.checkout.Checkout
|
|||
import org.solovyev.android.checkout.PurchaseVerifier
|
||||
import javax.inject.Inject
|
||||
|
||||
//contains all HabiticaApplicationLogic except dagger componentInitialisation
|
||||
// contains all HabiticaApplicationLogic except dagger componentInitialisation
|
||||
abstract class HabiticaBaseApplication : Application() {
|
||||
@Inject
|
||||
internal lateinit var lazyApiHelper: ApiClient
|
||||
|
|
@ -90,12 +90,11 @@ abstract class HabiticaBaseApplication : Application() {
|
|||
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", ""))
|
||||
.setOnce("androidStore", BuildConfig.STORE)
|
||||
.set("launch_screen", sharedPrefs.getString("launch_screen", ""))
|
||||
Amplitude.getInstance().identify(identify)
|
||||
} catch (ignored: Resources.NotFoundException) {
|
||||
}
|
||||
|
||||
}
|
||||
var builder = ImageLoader.Builder(this)
|
||||
.transition(CrossfadeTransition())
|
||||
|
|
@ -121,9 +120,9 @@ abstract class HabiticaBaseApplication : Application() {
|
|||
protected open fun setupRealm() {
|
||||
Realm.init(this)
|
||||
val builder = RealmConfiguration.Builder()
|
||||
.schemaVersion(1)
|
||||
.deleteRealmIfMigrationNeeded()
|
||||
.allowWritesOnUiThread(true)
|
||||
.schemaVersion(1)
|
||||
.deleteRealmIfMigrationNeeded()
|
||||
.allowWritesOnUiThread(true)
|
||||
.compactOnLaunch { totalBytes, usedBytes ->
|
||||
|
||||
// Compact if the file is over 100MB in size and less than 50% 'used'
|
||||
|
|
@ -133,9 +132,8 @@ abstract class HabiticaBaseApplication : Application() {
|
|||
try {
|
||||
Realm.setDefaultConfiguration(builder.build())
|
||||
} catch (ignored: UnsatisfiedLinkError) {
|
||||
//Catch crash in tests
|
||||
// Catch crash in tests
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun checkIfNewVersion() {
|
||||
|
|
@ -168,13 +166,20 @@ abstract class HabiticaBaseApplication : Application() {
|
|||
|
||||
protected abstract fun initDagger(): AppComponent
|
||||
|
||||
override fun openOrCreateDatabase(name: String,
|
||||
mode: Int, factory: SQLiteDatabase.CursorFactory?): SQLiteDatabase {
|
||||
override fun openOrCreateDatabase(
|
||||
name: String,
|
||||
mode: Int,
|
||||
factory: SQLiteDatabase.CursorFactory?
|
||||
): SQLiteDatabase {
|
||||
return super.openOrCreateDatabase(getDatabasePath(name).absolutePath, mode, factory)
|
||||
}
|
||||
|
||||
override fun openOrCreateDatabase(name: String,
|
||||
mode: Int, factory: SQLiteDatabase.CursorFactory?, errorHandler: DatabaseErrorHandler?): SQLiteDatabase {
|
||||
override fun openOrCreateDatabase(
|
||||
name: String,
|
||||
mode: Int,
|
||||
factory: SQLiteDatabase.CursorFactory?,
|
||||
errorHandler: DatabaseErrorHandler?
|
||||
): SQLiteDatabase {
|
||||
return super.openOrCreateDatabase(getDatabasePath(name).absolutePath, mode, factory, errorHandler)
|
||||
}
|
||||
|
||||
|
|
@ -192,19 +197,22 @@ abstract class HabiticaBaseApplication : Application() {
|
|||
}
|
||||
|
||||
private fun createBillingAndCheckout() {
|
||||
billing = Billing(this, object : Billing.DefaultConfiguration() {
|
||||
override fun getPublicKey(): String {
|
||||
return "DONT-NEED-IT"
|
||||
}
|
||||
billing = Billing(
|
||||
this,
|
||||
object : Billing.DefaultConfiguration() {
|
||||
override fun getPublicKey(): String {
|
||||
return "DONT-NEED-IT"
|
||||
}
|
||||
|
||||
override fun getCache(): Cache {
|
||||
return Billing.newCache()
|
||||
}
|
||||
override fun getCache(): Cache {
|
||||
return Billing.newCache()
|
||||
}
|
||||
|
||||
override fun getPurchaseVerifier(): PurchaseVerifier {
|
||||
return HabiticaPurchaseVerifier(this@HabiticaBaseApplication, lazyApiHelper)
|
||||
override fun getPurchaseVerifier(): PurchaseVerifier {
|
||||
return HabiticaPurchaseVerifier(this@HabiticaBaseApplication, lazyApiHelper)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
billing?.let { checkout = Checkout.forApplication(it) }
|
||||
}
|
||||
|
|
@ -212,8 +220,8 @@ abstract class HabiticaBaseApplication : Application() {
|
|||
private fun setupRemoteConfig() {
|
||||
val remoteConfig = FirebaseRemoteConfig.getInstance()
|
||||
val configSettings = FirebaseRemoteConfigSettings.Builder()
|
||||
.setMinimumFetchIntervalInSeconds(if (BuildConfig.DEBUG) 0 else 3600)
|
||||
.build()
|
||||
.setMinimumFetchIntervalInSeconds(if (BuildConfig.DEBUG) 0 else 3600)
|
||||
.build()
|
||||
remoteConfig.setConfigSettingsAsync(configSettings)
|
||||
remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults)
|
||||
remoteConfig.fetchAndActivate()
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import org.solovyev.android.checkout.ResponseCodes
|
|||
import retrofit2.HttpException
|
||||
import java.util.*
|
||||
|
||||
|
||||
class HabiticaPurchaseVerifier(context: Context, apiClient: ApiClient) : BasePurchaseVerifier() {
|
||||
private val apiClient: ApiClient
|
||||
private val purchasedOrderList: MutableSet<String> = HashSet()
|
||||
|
|
@ -93,7 +92,7 @@ class HabiticaPurchaseVerifier(context: Context, apiClient: ApiClient) : BasePur
|
|||
}
|
||||
|
||||
private fun handleError(throwable: Throwable, purchase: Purchase, requestListener: RequestListener<List<Purchase>>, verifiedPurchases: MutableList<Purchase>) {
|
||||
(throwable as? HttpException)?.let {error ->
|
||||
(throwable as? HttpException)?.let { error ->
|
||||
if (error.code() == 401) {
|
||||
val res = apiClient.getErrorResponse(throwable)
|
||||
if (res.message != null && res.message == "RECEIPT_ALREADY_USED") {
|
||||
|
|
@ -159,4 +158,4 @@ class HabiticaPurchaseVerifier(context: Context, apiClient: ApiClient) : BasePur
|
|||
pendingGifts = loadPendingGifts()
|
||||
this.apiClient = apiClient
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,13 +30,11 @@ interface ApiService {
|
|||
@get:GET("user/")
|
||||
val user: Flowable<HabitResponse<User>>
|
||||
|
||||
|
||||
@GET("inbox/messages")
|
||||
fun getInboxMessages(@Query("conversation") uuid: String, @Query("page") page: Int): Flowable<HabitResponse<List<ChatMessage>>>
|
||||
@GET("inbox/conversations")
|
||||
fun getInboxConversations(): Flowable<HabitResponse<List<InboxConversation>>>
|
||||
|
||||
|
||||
@get:GET("tasks/user")
|
||||
val tasks: Flowable<HabitResponse<TaskList>>
|
||||
|
||||
|
|
@ -94,7 +92,6 @@ interface ApiService {
|
|||
@GET("tasks/user")
|
||||
fun getTasks(@Query("type") type: String, @Query("dueDate") dueDate: String): Flowable<HabitResponse<TaskList>>
|
||||
|
||||
|
||||
@POST("user/unlock")
|
||||
fun unlockPath(@Query("path") path: String): Flowable<HabitResponse<UnlockResponse>>
|
||||
|
||||
|
|
@ -124,7 +121,6 @@ interface ApiService {
|
|||
@DELETE("tasks/{id}")
|
||||
fun deleteTask(@Path("id") id: String): Flowable<HabitResponse<Void>>
|
||||
|
||||
|
||||
@POST("tags")
|
||||
fun createTag(@Body tag: Tag): Flowable<HabitResponse<Tag>>
|
||||
|
||||
|
|
@ -170,7 +166,6 @@ interface ApiService {
|
|||
@POST("user/mark-pms-read")
|
||||
fun markPrivateMessagesRead(): Flowable<Void>
|
||||
|
||||
|
||||
/* Group API */
|
||||
|
||||
@GET("groups")
|
||||
|
|
@ -264,7 +259,7 @@ interface ApiService {
|
|||
@POST("user/custom-day-start")
|
||||
fun changeCustomDayStart(@Body updateObject: Map<String, Any>): Flowable<HabitResponse<User>>
|
||||
|
||||
//Members URL
|
||||
// Members URL
|
||||
@GET("members/{mid}")
|
||||
fun getMember(@Path("mid") memberId: String): Flowable<HabitResponse<Member>>
|
||||
|
||||
|
|
@ -289,7 +284,7 @@ interface ApiService {
|
|||
@GET("shops/market-gear")
|
||||
fun retrieveMarketGear(): Flowable<HabitResponse<Shop>>
|
||||
|
||||
//Push notifications
|
||||
// Push notifications
|
||||
@POST("user/push-devices")
|
||||
fun addPushDevice(@Body pushDeviceData: Map<String, String>): Flowable<HabitResponse<List<Void>>>
|
||||
|
||||
|
|
@ -331,8 +326,7 @@ interface ApiService {
|
|||
@DELETE("challenges/{challengeId}")
|
||||
fun deleteChallenge(@Path("challengeId") challengeId: String): Flowable<HabitResponse<Void>>
|
||||
|
||||
|
||||
//DEBUG: These calls only work on a local development server
|
||||
// DEBUG: These calls only work on a local development server
|
||||
|
||||
@POST("debug/add-ten-gems")
|
||||
fun debugAddTenGems(): Flowable<HabitResponse<Void>>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import com.habitrpg.android.habitica.BuildConfig
|
|||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.helpers.KeyHelper
|
||||
|
||||
|
||||
/**
|
||||
* The configuration of the host<br></br>
|
||||
* Currently, the Port isn't used at all.
|
||||
|
|
@ -69,6 +68,4 @@ class HostConfig {
|
|||
fun hasAuthentication(): Boolean {
|
||||
return userID.isNotEmpty() && apiKey.isNotEmpty()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,4 +25,4 @@ class Server {
|
|||
override fun toString(): String {
|
||||
return addr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import io.reactivex.rxjava3.core.Flowable
|
|||
import io.reactivex.rxjava3.core.FlowableTransformer
|
||||
import retrofit2.HttpException
|
||||
|
||||
|
||||
interface ApiClient {
|
||||
|
||||
val hostConfig: HostConfig
|
||||
|
|
@ -32,7 +31,6 @@ interface ApiClient {
|
|||
|
||||
val user: Flowable<User>
|
||||
|
||||
|
||||
val tasks: Flowable<TaskList>
|
||||
|
||||
/* challenges api */
|
||||
|
|
@ -74,7 +72,6 @@ interface ApiClient {
|
|||
fun getTasks(type: String): Flowable<TaskList>
|
||||
fun getTasks(type: String, dueDate: String): Flowable<TaskList>
|
||||
|
||||
|
||||
fun unlockPath(path: String): Flowable<UnlockResponse>
|
||||
|
||||
fun getTask(id: String): Flowable<Task>
|
||||
|
|
@ -94,7 +91,6 @@ interface ApiClient {
|
|||
|
||||
fun deleteTask(id: String): Flowable<Void>
|
||||
|
||||
|
||||
fun createTag(tag: Tag): Flowable<Tag>
|
||||
|
||||
fun updateTag(id: String, tag: Tag): Flowable<Tag>
|
||||
|
|
@ -179,7 +175,7 @@ interface ApiClient {
|
|||
|
||||
fun changeCustomDayStart(updateObject: Map<String, Any>): Flowable<User>
|
||||
|
||||
//Members URL
|
||||
// Members URL
|
||||
fun getMember(memberId: String): Flowable<Member>
|
||||
fun getMemberWithUsername(username: String): Flowable<Member>
|
||||
|
||||
|
|
@ -189,7 +185,7 @@ interface ApiClient {
|
|||
|
||||
fun retrieveShopIventory(identifier: String): Flowable<Shop>
|
||||
|
||||
//Push notifications
|
||||
// Push notifications
|
||||
fun addPushDevice(pushDeviceData: Map<String, String>): Flowable<List<Void>>
|
||||
|
||||
fun deletePushDevice(regId: String): Flowable<List<Void>>
|
||||
|
|
@ -202,7 +198,6 @@ interface ApiClient {
|
|||
|
||||
fun leaveChallenge(challengeId: String, body: LeaveChallengeBody): Flowable<Void>
|
||||
|
||||
|
||||
fun createChallenge(challenge: Challenge): Flowable<Challenge>
|
||||
|
||||
fun createChallengeTasks(challengeId: String, tasks: List<Task>): Flowable<List<Task>>
|
||||
|
|
@ -210,7 +205,7 @@ interface ApiClient {
|
|||
fun updateChallenge(challenge: Challenge): Flowable<Challenge>
|
||||
fun deleteChallenge(challengeId: String): Flowable<Void>
|
||||
|
||||
//DEBUG: These calls only work on a local development server
|
||||
// DEBUG: These calls only work on a local development server
|
||||
|
||||
fun debugAddTenGems(): Flowable<Void>
|
||||
|
||||
|
|
|
|||
|
|
@ -26,13 +26,17 @@ interface ChallengeRepository : BaseRepository {
|
|||
* @param removedTaskList tasks that has be to be removed
|
||||
* @return Observable with the updated challenge
|
||||
*/
|
||||
fun updateChallenge(challenge: Challenge, fullTaskList: List<Task>,
|
||||
addedTaskList: List<Task>, updatedTaskList: List<Task>, removedTaskList: List<String>): Flowable<Challenge>
|
||||
fun updateChallenge(
|
||||
challenge: Challenge,
|
||||
fullTaskList: List<Task>,
|
||||
addedTaskList: List<Task>,
|
||||
updatedTaskList: List<Task>,
|
||||
removedTaskList: List<String>
|
||||
): Flowable<Challenge>
|
||||
|
||||
fun deleteChallenge(challengeId: String): Flowable<Void>
|
||||
fun getUserChallenges(userId: String? = null): Flowable<out List<Challenge>>
|
||||
|
||||
|
||||
fun leaveChallenge(challenge: Challenge, keepTasks: String): Flowable<Void>
|
||||
|
||||
fun joinChallenge(challenge: Challenge): Flowable<Challenge>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.habitrpg.android.habitica.data
|
|||
import android.content.Context
|
||||
import com.habitrpg.android.habitica.models.ContentResult
|
||||
import com.habitrpg.android.habitica.models.WorldState
|
||||
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
|
||||
interface ContentRepository {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.habitrpg.android.habitica.data
|
||||
|
||||
import com.habitrpg.android.habitica.models.inventory.Customization
|
||||
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
|
||||
interface CustomizationRepository : BaseRepository {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.habitrpg.android.habitica.data
|
||||
|
||||
import com.habitrpg.android.habitica.models.FAQArticle
|
||||
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
|
||||
interface FAQRepository : BaseRepository {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import com.habitrpg.android.habitica.models.shops.ShopItem
|
|||
import com.habitrpg.android.habitica.models.user.*
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
|
||||
|
||||
interface InventoryRepository : BaseRepository {
|
||||
|
||||
fun getArmoireRemainingCount(): Long
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.habitrpg.android.habitica.data
|
||||
|
||||
|
||||
import com.habitrpg.android.habitica.models.SetupCustomization
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ interface SocialRepository : BaseRepository {
|
|||
fun retrieveGroups(type: String): Flowable<List<Group>>
|
||||
fun getGroups(type: String): Flowable<out List<Group>>
|
||||
|
||||
|
||||
fun getInboxMessages(replyToUserID: String?): Flowable<out List<ChatMessage>>
|
||||
fun retrieveInboxMessages(uuid: String, page: Int): Flowable<List<ChatMessage>>
|
||||
fun retrieveInboxConversations(): Flowable<List<InboxConversation>>
|
||||
|
|
@ -49,7 +48,6 @@ interface SocialRepository : BaseRepository {
|
|||
fun postPrivateMessage(recipientId: String, messageObject: HashMap<String, String>): Flowable<List<ChatMessage>>
|
||||
fun postPrivateMessage(recipientId: String, message: String): Flowable<List<ChatMessage>>
|
||||
|
||||
|
||||
fun getGroupMembers(id: String): Flowable<out List<Member>>
|
||||
fun retrieveGroupMembers(id: String, includeAllPublicFields: Boolean): Flowable<List<Member>>
|
||||
|
||||
|
|
@ -62,7 +60,6 @@ interface SocialRepository : BaseRepository {
|
|||
|
||||
fun markPrivateMessagesRead(user: User?): Flowable<Void>
|
||||
|
||||
|
||||
fun transferGroupOwnership(groupID: String, userID: String): Flowable<Group>
|
||||
fun removeMemberFromGroup(groupID: String, userID: String): Flowable<List<Member>>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.habitrpg.android.habitica.data
|
||||
|
||||
import com.habitrpg.android.habitica.models.Tag
|
||||
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
|
||||
|
|
@ -14,7 +13,6 @@ interface TagRepository : BaseRepository {
|
|||
fun updateTag(tag: Tag): Flowable<Tag>
|
||||
fun deleteTag(id: String): Flowable<Void>
|
||||
|
||||
|
||||
fun createTags(tags: Collection<Tag>): Single<List<Tag>>
|
||||
fun updateTags(tags: Collection<Tag>): Single<List<Tag>>
|
||||
fun deleteTags(tagIds: Collection<String>): Single<List<Void>>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
package com.habitrpg.android.habitica.data
|
||||
|
||||
import com.habitrpg.android.habitica.models.BaseMainObject
|
||||
import com.habitrpg.android.habitica.models.BaseObject
|
||||
import com.habitrpg.android.habitica.models.responses.BulkTaskScoringData
|
||||
import com.habitrpg.android.habitica.models.responses.TaskScoringResult
|
||||
import com.habitrpg.android.habitica.models.tasks.RemindersItem
|
||||
import com.habitrpg.android.habitica.models.tasks.Task
|
||||
import com.habitrpg.android.habitica.models.tasks.TaskList
|
||||
import com.habitrpg.android.habitica.models.tasks.TasksOrder
|
||||
|
|
@ -36,7 +34,7 @@ interface TaskRepository : BaseRepository {
|
|||
|
||||
fun markTaskCompleted(taskId: String, isCompleted: Boolean)
|
||||
|
||||
fun <T: BaseMainObject> modify(obj: T, transaction: (T) -> Unit)
|
||||
fun <T : BaseMainObject> modify(obj: T, transaction: (T) -> Unit)
|
||||
|
||||
fun swapTaskPosition(firstPosition: Int, secondPosition: Int)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,5 +7,4 @@ interface TutorialRepository : BaseRepository {
|
|||
|
||||
fun getTutorialStep(key: String): Flowable<TutorialStep>
|
||||
fun getTutorialSteps(keys: List<String>): Flowable<out List<TutorialStep>>
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@ import com.habitrpg.android.habitica.models.user.Items
|
|||
import com.habitrpg.android.habitica.models.user.Stats
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import com.habitrpg.android.habitica.proxy.AnalyticsManager
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
import io.reactivex.rxjava3.core.FlowableTransformer
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.functions.Consumer
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import okhttp3.Cache
|
||||
|
|
@ -54,12 +54,10 @@ import java.util.*
|
|||
import java.util.concurrent.TimeUnit
|
||||
import javax.net.ssl.SSLException
|
||||
|
||||
|
||||
class ApiClientImpl//private OnHabitsAPIResult mResultListener;
|
||||
//private HostConfig mConfig;
|
||||
class ApiClientImpl // private OnHabitsAPIResult mResultListener;
|
||||
// private HostConfig mConfig;
|
||||
(private val gsonConverter: GsonConverterFactory, override val hostConfig: HostConfig, private val analyticsManager: AnalyticsManager, private val notificationsManager: NotificationsManager, private val context: Context) : Consumer<Throwable>, ApiClient {
|
||||
|
||||
|
||||
private lateinit var retrofitAdapter: Retrofit
|
||||
|
||||
// I think we don't need the ApiClientImpl anymore we could just use ApiService
|
||||
|
|
@ -67,17 +65,16 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
|
|||
|
||||
private val apiCallTransformer = FlowableTransformer<HabitResponse<Any>, Any> { observable ->
|
||||
observable
|
||||
.filter { it.data != null }
|
||||
.map { habitResponse ->
|
||||
habitResponse.notifications?.let {
|
||||
notificationsManager.setNotifications(it)
|
||||
|
||||
}
|
||||
habitResponse.data
|
||||
.filter { it.data != null }
|
||||
.map { habitResponse ->
|
||||
habitResponse.notifications?.let {
|
||||
notificationsManager.setNotifications(it)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnError(this)
|
||||
habitResponse.data
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnError(this)
|
||||
}
|
||||
private var languageCode: String? = null
|
||||
private var lastAPICallURL: String? = null
|
||||
|
|
@ -104,43 +101,43 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
|
|||
|
||||
val cacheSize: Long = 10 * 1024 * 1024 // 10 MB
|
||||
|
||||
val cache = Cache(getCacheDir(), cacheSize)
|
||||
val cache = getCacheDir()?.let { Cache(it, cacheSize) }
|
||||
|
||||
val client = OkHttpClient.Builder()
|
||||
.cache(cache)
|
||||
.addInterceptor(logging)
|
||||
.addNetworkInterceptor { chain ->
|
||||
val original = chain.request()
|
||||
var builder: Request.Builder = original.newBuilder()
|
||||
if (this.hostConfig.hasAuthentication()) {
|
||||
builder = builder
|
||||
.header("x-api-key", this.hostConfig.apiKey)
|
||||
.header("x-api-user", this.hostConfig.userID)
|
||||
}
|
||||
builder = builder.header("x-client", "habitica-android")
|
||||
.header("x-user-timezoneOffset", timezoneOffset.toString())
|
||||
if (userAgent != null) {
|
||||
builder = builder.header("user-agent", userAgent)
|
||||
}
|
||||
if (BuildConfig.STAGING_KEY.isNotEmpty()) {
|
||||
builder = builder.header("Authorization", "Basic " + BuildConfig.STAGING_KEY)
|
||||
}
|
||||
val request = builder.method(original.method, original.body)
|
||||
.build()
|
||||
lastAPICallURL = original.url.toString()
|
||||
chain.proceed(request)
|
||||
.cache(cache)
|
||||
.addInterceptor(logging)
|
||||
.addNetworkInterceptor { chain ->
|
||||
val original = chain.request()
|
||||
var builder: Request.Builder = original.newBuilder()
|
||||
if (this.hostConfig.hasAuthentication()) {
|
||||
builder = builder
|
||||
.header("x-api-key", this.hostConfig.apiKey)
|
||||
.header("x-api-user", this.hostConfig.userID)
|
||||
}
|
||||
.readTimeout(2400, TimeUnit.SECONDS)
|
||||
.build()
|
||||
builder = builder.header("x-client", "habitica-android")
|
||||
.header("x-user-timezoneOffset", timezoneOffset.toString())
|
||||
if (userAgent != null) {
|
||||
builder = builder.header("user-agent", userAgent)
|
||||
}
|
||||
if (BuildConfig.STAGING_KEY.isNotEmpty()) {
|
||||
builder = builder.header("Authorization", "Basic " + BuildConfig.STAGING_KEY)
|
||||
}
|
||||
val request = builder.method(original.method, original.body)
|
||||
.build()
|
||||
lastAPICallURL = original.url.toString()
|
||||
chain.proceed(request)
|
||||
}
|
||||
.readTimeout(2400, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
val server = Server(this.hostConfig.address)
|
||||
|
||||
retrofitAdapter = Retrofit.Builder()
|
||||
.client(client)
|
||||
.baseUrl(server.toString())
|
||||
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
|
||||
.addConverterFactory(gsonConverter)
|
||||
.build()
|
||||
.client(client)
|
||||
.baseUrl(server.toString())
|
||||
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
|
||||
.addConverterFactory(gsonConverter)
|
||||
.build()
|
||||
|
||||
this.apiService = retrofitAdapter.create(ApiService::class.java)
|
||||
}
|
||||
|
|
@ -199,7 +196,7 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
|
|||
val status = error.code()
|
||||
|
||||
if (status == 404 || error.response()?.raw()?.request?.url?.toString()?.endsWith("/user/push-devices") == true) {
|
||||
//workaround for an error that sometimes displays that the user already has this push device
|
||||
// workaround for an error that sometimes displays that the user already has this push device
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -224,14 +221,13 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
|
|||
override fun getErrorResponse(throwable: HttpException): ErrorResponse {
|
||||
val errorResponse = throwable.response()?.errorBody() ?: return ErrorResponse()
|
||||
val errorConverter = gsonConverter
|
||||
.responseBodyConverter(ErrorResponse::class.java, arrayOfNulls(0), retrofitAdapter)
|
||||
.responseBodyConverter(ErrorResponse::class.java, arrayOfNulls(0), retrofitAdapter)
|
||||
return try {
|
||||
errorConverter?.convert(errorResponse) as ErrorResponse
|
||||
} catch (e: IOException) {
|
||||
analyticsManager.logError("Json Error: " + lastAPICallURL + ", " + e.message)
|
||||
ErrorResponse()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun retrieveUser(withTasks: Boolean): Flowable<User> {
|
||||
|
|
@ -241,11 +237,13 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
|
|||
if (withTasks) {
|
||||
val tasksObservable = this.tasks
|
||||
|
||||
userObservable = Flowable.zip(userObservable, tasksObservable,
|
||||
{ habitRPGUser, tasks ->
|
||||
habitRPGUser.tasks = tasks
|
||||
habitRPGUser
|
||||
})
|
||||
userObservable = Flowable.zip(
|
||||
userObservable, tasksObservable,
|
||||
{ habitRPGUser, tasks ->
|
||||
habitRPGUser.tasks = tasks
|
||||
habitRPGUser
|
||||
}
|
||||
)
|
||||
}
|
||||
return userObservable
|
||||
}
|
||||
|
|
@ -375,11 +373,11 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
|
|||
|
||||
override fun feedPet(petKey: String, foodKey: String): Flowable<FeedResponse> {
|
||||
return apiService.feedPet(petKey, foodKey)
|
||||
.map {
|
||||
it.data?.message = it.message
|
||||
it
|
||||
}
|
||||
.compose(configureApiCallObserver())
|
||||
.map {
|
||||
it.data?.message = it.message
|
||||
it
|
||||
}
|
||||
.compose(configureApiCallObserver())
|
||||
}
|
||||
|
||||
override fun hatchPet(eggKey: String, hatchingPotionKey: String): Flowable<Items> {
|
||||
|
|
@ -393,12 +391,10 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
|
|||
return apiService.getTasks(type).compose(configureApiCallObserver())
|
||||
}
|
||||
|
||||
|
||||
override fun getTasks(type: String, dueDate: String): Flowable<TaskList> {
|
||||
return apiService.getTasks(type, dueDate).compose(configureApiCallObserver())
|
||||
}
|
||||
|
||||
|
||||
override fun unlockPath(path: String): Flowable<UnlockResponse> {
|
||||
return apiService.unlockPath(path).compose(configureApiCallObserver())
|
||||
}
|
||||
|
|
@ -480,11 +476,11 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
|
|||
}
|
||||
|
||||
override fun markPrivateMessagesRead(): Flowable<Void> {
|
||||
//This is necessary, because the API call returns weird data.
|
||||
// This is necessary, because the API call returns weird data.
|
||||
return apiService.markPrivateMessagesRead()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnError(this)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnError(this)
|
||||
}
|
||||
|
||||
override fun listGroups(type: String): Flowable<List<Group>> {
|
||||
|
|
@ -654,7 +650,6 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
|
|||
return apiService.leaveChallenge(challengeId, body).compose(configureApiCallObserver())
|
||||
}
|
||||
|
||||
|
||||
override fun createChallenge(challenge: Challenge): Flowable<Challenge> {
|
||||
return apiService.createChallenge(challenge).compose(configureApiCallObserver())
|
||||
}
|
||||
|
|
@ -702,7 +697,6 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
|
|||
return apiService.runCron().compose(configureApiCallObserver())
|
||||
}
|
||||
|
||||
|
||||
override fun reroll(): Flowable<User> {
|
||||
return apiService.reroll().compose(configureApiCallObserver())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,14 +11,14 @@ abstract class BaseRepositoryImpl<T : BaseLocalRepository>(protected val localRe
|
|||
this.localRepository.close()
|
||||
}
|
||||
|
||||
override fun <T: BaseObject> getUnmanagedCopy(list: List<T>): List<T> {
|
||||
override fun <T : BaseObject> getUnmanagedCopy(list: List<T>): List<T> {
|
||||
return localRepository.getUnmanagedCopy(list)
|
||||
}
|
||||
|
||||
override val isClosed: Boolean
|
||||
get() = localRepository.isClosed
|
||||
|
||||
override fun <T: BaseObject> getUnmanagedCopy(obj: T): T {
|
||||
override fun <T : BaseObject> getUnmanagedCopy(obj: T): T {
|
||||
return localRepository.getUnmanagedCopy(obj)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import com.habitrpg.android.habitica.models.tasks.TaskList
|
|||
import com.habitrpg.android.habitica.models.tasks.TasksOrder
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
|
||||
|
||||
class ChallengeRepositoryImpl(localRepository: ChallengeLocalRepository, apiClient: ApiClient, userID: String) : BaseRepositoryImpl<ChallengeLocalRepository>(localRepository, apiClient, userID), ChallengeRepository {
|
||||
|
||||
override fun isChallengeMember(challengeID: String): Flowable<Boolean> {
|
||||
|
|
@ -85,16 +84,21 @@ class ChallengeRepositoryImpl(localRepository: ChallengeLocalRepository, apiClie
|
|||
}
|
||||
}
|
||||
|
||||
override fun updateChallenge(challenge: Challenge, fullTaskList: List<Task>,
|
||||
addedTaskList: List<Task>, updatedTaskList: List<Task>, removedTaskList: List<String>): Flowable<Challenge> {
|
||||
override fun updateChallenge(
|
||||
challenge: Challenge,
|
||||
fullTaskList: List<Task>,
|
||||
addedTaskList: List<Task>,
|
||||
updatedTaskList: List<Task>,
|
||||
removedTaskList: List<String>
|
||||
): Flowable<Challenge> {
|
||||
|
||||
var flowable: Flowable<*> = Flowable.just("")
|
||||
|
||||
updatedTaskList
|
||||
.map { localRepository.getUnmanagedCopy(it) }
|
||||
.forEach { task ->
|
||||
flowable = flowable.flatMap { apiClient.updateTask(task.id ?: "", task) }
|
||||
}
|
||||
.map { localRepository.getUnmanagedCopy(it) }
|
||||
.forEach { task ->
|
||||
flowable = flowable.flatMap { apiClient.updateTask(task.id ?: "", task) }
|
||||
}
|
||||
|
||||
removedTaskList.forEach { task ->
|
||||
flowable = flowable.flatMap { apiClient.deleteTask(task) }
|
||||
|
|
@ -106,7 +110,7 @@ class ChallengeRepositoryImpl(localRepository: ChallengeLocalRepository, apiClie
|
|||
challenge.tasksOrder = getTaskOrders(fullTaskList)
|
||||
|
||||
return flowable.flatMap { apiClient.updateChallenge(challenge) }
|
||||
.doOnNext { localRepository.save(challenge) }
|
||||
.doOnNext { localRepository.save(challenge) }
|
||||
}
|
||||
|
||||
override fun deleteChallenge(challengeId: String): Flowable<Void> {
|
||||
|
|
@ -123,16 +127,16 @@ class ChallengeRepositoryImpl(localRepository: ChallengeLocalRepository, apiClie
|
|||
|
||||
override fun retrieveChallenges(page: Int, memberOnly: Boolean): Flowable<List<Challenge>> {
|
||||
return apiClient.getUserChallenges(page, memberOnly)
|
||||
.doOnNext { localRepository.saveChallenges(it, page == 0, memberOnly, userID) }
|
||||
.doOnNext { localRepository.saveChallenges(it, page == 0, memberOnly, userID) }
|
||||
}
|
||||
|
||||
override fun leaveChallenge(challenge: Challenge, keepTasks: String): Flowable<Void> {
|
||||
return apiClient.leaveChallenge(challenge.id ?: "", LeaveChallengeBody(keepTasks))
|
||||
.doOnNext { localRepository.setParticipating(userID, challenge.id ?: "", false) }
|
||||
.doOnNext { localRepository.setParticipating(userID, challenge.id ?: "", false) }
|
||||
}
|
||||
|
||||
override fun joinChallenge(challenge: Challenge): Flowable<Challenge> {
|
||||
return apiClient.joinChallenge(challenge.id ?: "")
|
||||
.doOnNext { localRepository.setParticipating(userID, challenge.id ?: "", true) }
|
||||
.doOnNext { localRepository.setParticipating(userID, challenge.id ?: "", true) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.habitrpg.android.habitica.data.implementation
|
||||
|
||||
import android.content.Context
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.habitrpg.android.habitica.data.ApiClient
|
||||
import com.habitrpg.android.habitica.data.ContentRepository
|
||||
import com.habitrpg.android.habitica.data.local.ContentLocalRepository
|
||||
|
|
@ -19,7 +18,7 @@ abstract class ContentRepositoryImpl<T : ContentLocalRepository>(localRepository
|
|||
private var lastWorldStateSync = 0L
|
||||
|
||||
override fun retrieveContent(context: Context?): Flowable<ContentResult> {
|
||||
return retrieveContent(context,false)
|
||||
return retrieveContent(context, false)
|
||||
}
|
||||
|
||||
override fun retrieveContent(context: Context?, forced: Boolean): Flowable<ContentResult> {
|
||||
|
|
@ -27,7 +26,7 @@ abstract class ContentRepositoryImpl<T : ContentLocalRepository>(localRepository
|
|||
return if (forced || now - this.lastContentSync > 300000) {
|
||||
lastContentSync = now
|
||||
apiClient.content.doOnNext {
|
||||
context?.let {context ->
|
||||
context?.let { context ->
|
||||
it.special = RealmList()
|
||||
it.special.add(SpecialItem.makeMysteryItem(context))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import com.habitrpg.android.habitica.data.ApiClient
|
|||
import com.habitrpg.android.habitica.data.CustomizationRepository
|
||||
import com.habitrpg.android.habitica.data.local.CustomizationLocalRepository
|
||||
import com.habitrpg.android.habitica.models.inventory.Customization
|
||||
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
|
||||
class CustomizationRepositoryImpl(localRepository: CustomizationLocalRepository, apiClient: ApiClient, userID: String) : BaseRepositoryImpl<CustomizationLocalRepository>(localRepository, apiClient, userID), CustomizationRepository {
|
||||
|
|
|
|||
|
|
@ -4,10 +4,8 @@ import com.habitrpg.android.habitica.data.ApiClient
|
|||
import com.habitrpg.android.habitica.data.FAQRepository
|
||||
import com.habitrpg.android.habitica.data.local.FAQLocalRepository
|
||||
import com.habitrpg.android.habitica.models.FAQArticle
|
||||
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
|
||||
|
||||
class FAQRepositoryImpl(localRepository: FAQLocalRepository, apiClient: ApiClient, userID: String) : BaseRepositoryImpl<FAQLocalRepository>(localRepository, apiClient, userID), FAQRepository {
|
||||
override fun getArticle(position: Int): Flowable<FAQArticle> {
|
||||
return localRepository.getArticle(position)
|
||||
|
|
|
|||
|
|
@ -71,14 +71,14 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
|
|||
|
||||
override fun openMysteryItem(user: User?): Flowable<Equipment> {
|
||||
return apiClient.openMysteryItem()
|
||||
.flatMap { localRepository.getEquipment(it.key ?: "").firstElement().toFlowable() }
|
||||
.doOnNext { itemData ->
|
||||
val liveEquipment = localRepository.getLiveObject(itemData)
|
||||
localRepository.executeTransaction {
|
||||
liveEquipment?.owned = true
|
||||
}
|
||||
localRepository.decrementMysteryItemCount(user)
|
||||
}
|
||||
.flatMap { localRepository.getEquipment(it.key ?: "").firstElement().toFlowable() }
|
||||
.doOnNext { itemData ->
|
||||
val liveEquipment = localRepository.getLiveObject(itemData)
|
||||
localRepository.executeTransaction {
|
||||
liveEquipment?.owned = true
|
||||
}
|
||||
localRepository.decrementMysteryItemCount(user)
|
||||
}
|
||||
}
|
||||
|
||||
override fun saveEquipment(equipment: Equipment) {
|
||||
|
|
@ -119,12 +119,12 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
|
|||
|
||||
override fun sellItem(type: String, key: String): Flowable<User> {
|
||||
return localRepository.getOwnedItem(userID, type, key, true)
|
||||
.flatMap { item -> sellItem(item) }
|
||||
.flatMap { item -> sellItem(item) }
|
||||
}
|
||||
|
||||
override fun sellItem(item: OwnedItem): Flowable<User> {
|
||||
return localRepository.getItem(item.itemType ?: "", item.key ?: "")
|
||||
.flatMap { newItem -> sellItem(newItem, item) }
|
||||
.flatMap { newItem -> sellItem(newItem, item) }
|
||||
}
|
||||
|
||||
override fun getLatestMysteryItem(): Flowable<Equipment> {
|
||||
|
|
@ -141,9 +141,9 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
|
|||
liveItem?.numberOwned = (liveItem?.numberOwned ?: 0) - 1
|
||||
}
|
||||
return apiClient.sellItem(item.type, item.key)
|
||||
.map { user ->
|
||||
localRepository.soldItem(userID, user)
|
||||
}
|
||||
.map { user ->
|
||||
localRepository.soldItem(userID, user)
|
||||
}
|
||||
}
|
||||
|
||||
override fun equipGear(user: User?, equipment: String, asCostume: Boolean): Flowable<Items> {
|
||||
|
|
@ -176,29 +176,29 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
|
|||
}
|
||||
}
|
||||
return apiClient.equipItem(type, key)
|
||||
.doOnNext { items ->
|
||||
if (user == null) {
|
||||
return@doOnNext
|
||||
}
|
||||
localRepository.modify(user) { liveUser ->
|
||||
val newEquipped = items.gear?.equipped
|
||||
val oldEquipped = liveUser.items?.gear?.equipped
|
||||
val newCostume = items.gear?.costume
|
||||
val oldCostume = liveUser.items?.gear?.costume
|
||||
newEquipped?.let { equipped -> oldEquipped?.updateWith(equipped) }
|
||||
newCostume?.let { costume -> oldCostume?.updateWith(costume) }
|
||||
liveUser.items?.currentMount = items.currentMount
|
||||
liveUser.items?.currentPet = items.currentPet
|
||||
liveUser.balance = liveUser.balance
|
||||
}
|
||||
.doOnNext { items ->
|
||||
if (user == null) {
|
||||
return@doOnNext
|
||||
}
|
||||
localRepository.modify(user) { liveUser ->
|
||||
val newEquipped = items.gear?.equipped
|
||||
val oldEquipped = liveUser.items?.gear?.equipped
|
||||
val newCostume = items.gear?.costume
|
||||
val oldCostume = liveUser.items?.gear?.costume
|
||||
newEquipped?.let { equipped -> oldEquipped?.updateWith(equipped) }
|
||||
newCostume?.let { costume -> oldCostume?.updateWith(costume) }
|
||||
liveUser.items?.currentMount = items.currentMount
|
||||
liveUser.items?.currentPet = items.currentPet
|
||||
liveUser.balance = liveUser.balance
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun feedPet(pet: Pet, food: Food): Flowable<FeedResponse> {
|
||||
return apiClient.feedPet(pet.key ?: "", food.key)
|
||||
.doOnNext { feedResponse ->
|
||||
localRepository.feedPet(food.key, pet.key ?: "", feedResponse.value ?: 0, userID)
|
||||
}
|
||||
.doOnNext { feedResponse ->
|
||||
localRepository.feedPet(food.key, pet.key ?: "", feedResponse.value ?: 0, userID)
|
||||
}
|
||||
}
|
||||
|
||||
override fun hatchPet(egg: Egg, hatchingPotion: HatchingPotion, successFunction: () -> Unit): Flowable<Items> {
|
||||
|
|
@ -207,48 +207,48 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
|
|||
successFunction()
|
||||
}
|
||||
return apiClient.hatchPet(egg.key, hatchingPotion.key)
|
||||
.doOnNext {
|
||||
localRepository.save(it, userID)
|
||||
if (!appConfigManager.enableLocalChanges()) {
|
||||
successFunction()
|
||||
}
|
||||
.doOnNext {
|
||||
localRepository.save(it, userID)
|
||||
if (!appConfigManager.enableLocalChanges()) {
|
||||
successFunction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun inviteToQuest(quest: QuestContent): Flowable<Quest> {
|
||||
return apiClient.inviteToQuest("party", quest.key)
|
||||
.doOnNext { localRepository.changeOwnedCount("quests", quest.key, userID, -1) }
|
||||
.doOnNext { localRepository.changeOwnedCount("quests", quest.key, userID, -1) }
|
||||
}
|
||||
|
||||
override fun buyItem(user: User?, id: String, value: Double, purchaseQuantity: Int): Flowable<BuyResponse> {
|
||||
return apiClient.buyItem(id, purchaseQuantity)
|
||||
.doOnNext { buyResponse ->
|
||||
if (user == null) {
|
||||
return@doOnNext
|
||||
}
|
||||
val copiedUser = localRepository.getUnmanagedCopy(user)
|
||||
if (buyResponse.items != null) {
|
||||
copiedUser.items = buyResponse.items
|
||||
}
|
||||
if (buyResponse.hp != null) {
|
||||
copiedUser.stats?.hp = buyResponse.hp
|
||||
}
|
||||
if (buyResponse.exp != null) {
|
||||
copiedUser.stats?.exp = buyResponse.exp
|
||||
}
|
||||
if (buyResponse.mp != null) {
|
||||
copiedUser.stats?.mp = buyResponse.mp
|
||||
}
|
||||
if (buyResponse.gp != null) {
|
||||
copiedUser.stats?.gp = buyResponse.gp
|
||||
} else {
|
||||
copiedUser.stats?.gp = copiedUser.stats?.gp ?: 0 - (value * purchaseQuantity)
|
||||
}
|
||||
if (buyResponse.lvl != null) {
|
||||
copiedUser.stats?.lvl = buyResponse.lvl
|
||||
}
|
||||
localRepository.save(copiedUser)
|
||||
.doOnNext { buyResponse ->
|
||||
if (user == null) {
|
||||
return@doOnNext
|
||||
}
|
||||
val copiedUser = localRepository.getUnmanagedCopy(user)
|
||||
if (buyResponse.items != null) {
|
||||
copiedUser.items = buyResponse.items
|
||||
}
|
||||
if (buyResponse.hp != null) {
|
||||
copiedUser.stats?.hp = buyResponse.hp
|
||||
}
|
||||
if (buyResponse.exp != null) {
|
||||
copiedUser.stats?.exp = buyResponse.exp
|
||||
}
|
||||
if (buyResponse.mp != null) {
|
||||
copiedUser.stats?.mp = buyResponse.mp
|
||||
}
|
||||
if (buyResponse.gp != null) {
|
||||
copiedUser.stats?.gp = buyResponse.gp
|
||||
} else {
|
||||
copiedUser.stats?.gp = copiedUser.stats?.gp ?: 0 - (value * purchaseQuantity)
|
||||
}
|
||||
if (buyResponse.lvl != null) {
|
||||
copiedUser.stats?.lvl = buyResponse.lvl
|
||||
}
|
||||
localRepository.save(copiedUser)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAvailableLimitedItems(): Flowable<List<Item>> {
|
||||
|
|
@ -287,6 +287,6 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
|
|||
return if (!item.isValid) {
|
||||
Flowable.empty()
|
||||
} else apiClient.togglePinnedItem(item.pinType ?: "", item.path ?: "")
|
||||
.flatMap { retrieveInAppRewards() }
|
||||
.flatMap { retrieveInAppRewards() }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,20 +36,20 @@ constructor(private val context: Context) : SetupCustomizationRepository {
|
|||
override fun getCustomizations(type: String, subtype: String?, user: User): List<SetupCustomization> {
|
||||
return when (type) {
|
||||
SetupCustomizationRepository.CATEGORY_BODY -> {
|
||||
when (subtype) {
|
||||
SetupCustomizationRepository.SUBCATEGORY_SIZE -> sizes
|
||||
SetupCustomizationRepository.SUBCATEGORY_SHIRT -> getShirts(user.preferences?.size ?: "slim")
|
||||
else -> emptyList()
|
||||
}
|
||||
when (subtype) {
|
||||
SetupCustomizationRepository.SUBCATEGORY_SIZE -> sizes
|
||||
SetupCustomizationRepository.SUBCATEGORY_SHIRT -> getShirts(user.preferences?.size ?: "slim")
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
SetupCustomizationRepository.CATEGORY_SKIN -> skins
|
||||
SetupCustomizationRepository.CATEGORY_HAIR -> {
|
||||
when (subtype) {
|
||||
SetupCustomizationRepository.SUBCATEGORY_BANGS -> getBangs(user.preferences?.hair?.color ?: "")
|
||||
SetupCustomizationRepository.SUBCATEGORY_PONYTAIL -> getHairBases(user.preferences?.hair?.color ?: "")
|
||||
SetupCustomizationRepository.SUBCATEGORY_COLOR -> hairColors
|
||||
else -> emptyList()
|
||||
}
|
||||
when (subtype) {
|
||||
SetupCustomizationRepository.SUBCATEGORY_BANGS -> getBangs(user.preferences?.hair?.color ?: "")
|
||||
SetupCustomizationRepository.SUBCATEGORY_PONYTAIL -> getHairBases(user.preferences?.hair?.color ?: "")
|
||||
SetupCustomizationRepository.SUBCATEGORY_COLOR -> hairColors
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
SetupCustomizationRepository.CATEGORY_EXTRAS -> {
|
||||
when (subtype) {
|
||||
|
|
@ -86,6 +86,5 @@ constructor(private val context: Context) : SetupCustomizationRepository {
|
|||
e.printStackTrace()
|
||||
-1
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,21 +19,21 @@ import kotlin.collections.HashMap
|
|||
class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: ApiClient, userID: String) : BaseRepositoryImpl<SocialLocalRepository>(localRepository, apiClient, userID), SocialRepository {
|
||||
override fun transferGroupOwnership(groupID: String, userID: String): Flowable<Group> {
|
||||
return localRepository.getGroup(groupID)
|
||||
.map {
|
||||
val group = localRepository.getUnmanagedCopy(it)
|
||||
group.leaderID = userID
|
||||
group
|
||||
}
|
||||
.flatMap {
|
||||
apiClient.updateGroup(it.id, it)
|
||||
}
|
||||
.map {
|
||||
val group = localRepository.getUnmanagedCopy(it)
|
||||
group.leaderID = userID
|
||||
group
|
||||
}
|
||||
.flatMap {
|
||||
apiClient.updateGroup(it.id, it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeMemberFromGroup(groupID: String, userID: String): Flowable<List<Member>> {
|
||||
return apiClient.removeMemberFromGroup(groupID, userID)
|
||||
.flatMap {
|
||||
retrieveGroupMembers(groupID, true)
|
||||
}
|
||||
.flatMap {
|
||||
retrieveGroupMembers(groupID, true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getChatmessage(messageID: String): Flowable<ChatMessage> {
|
||||
|
|
@ -54,13 +54,13 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap
|
|||
|
||||
override fun retrieveGroupChat(groupId: String): Single<List<ChatMessage>> {
|
||||
return apiClient.listGroupChat(groupId)
|
||||
.flatMap { Flowable.fromIterable(it) }
|
||||
.map { chatMessage ->
|
||||
chatMessage.groupId = groupId
|
||||
chatMessage
|
||||
}
|
||||
.toList()
|
||||
.doOnSuccess { localRepository.saveChatMessages(groupId, it) }
|
||||
.flatMap { Flowable.fromIterable(it) }
|
||||
.map { chatMessage ->
|
||||
chatMessage.groupId = groupId
|
||||
chatMessage
|
||||
}
|
||||
.toList()
|
||||
.doOnSuccess { localRepository.saveChatMessages(groupId, it) }
|
||||
}
|
||||
|
||||
override fun getGroupChat(groupId: String): Flowable<out List<ChatMessage>> {
|
||||
|
|
@ -94,7 +94,7 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap
|
|||
val liked = chatMessage.userLikesMessage(userID)
|
||||
localRepository.likeMessage(chatMessage, userID, !liked)
|
||||
return apiClient.likeMessage(chatMessage.groupId ?: "", chatMessage.id)
|
||||
.doOnError { localRepository.likeMessage(chatMessage, userID, liked) }
|
||||
.doOnError { localRepository.likeMessage(chatMessage, userID, liked) }
|
||||
}
|
||||
|
||||
override fun deleteMessage(chatMessage: ChatMessage): Flowable<Void> {
|
||||
|
|
@ -107,15 +107,15 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap
|
|||
|
||||
override fun postGroupChat(groupId: String, messageObject: HashMap<String, String>): Flowable<PostChatMessageResult> {
|
||||
return apiClient.postGroupChat(groupId, messageObject)
|
||||
.map { postChatMessageResult ->
|
||||
postChatMessageResult.message.groupId = groupId
|
||||
postChatMessageResult
|
||||
}
|
||||
.doOnNext { postChatMessageResult ->
|
||||
if (postChatMessageResult != null) {
|
||||
localRepository.save(postChatMessageResult.message)
|
||||
}
|
||||
.map { postChatMessageResult ->
|
||||
postChatMessageResult.message.groupId = groupId
|
||||
postChatMessageResult
|
||||
}
|
||||
.doOnNext { postChatMessageResult ->
|
||||
if (postChatMessageResult != null) {
|
||||
localRepository.save(postChatMessageResult.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun postGroupChat(groupId: String, message: String): Flowable<PostChatMessageResult> {
|
||||
|
|
@ -125,11 +125,13 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap
|
|||
}
|
||||
|
||||
override fun retrieveGroup(id: String): Flowable<Group> {
|
||||
return Flowable.zip(apiClient.getGroup(id).doOnNext { localRepository.saveGroup(it) }, retrieveGroupChat(id)
|
||||
return Flowable.zip(
|
||||
apiClient.getGroup(id).doOnNext { localRepository.saveGroup(it) },
|
||||
retrieveGroupChat(id)
|
||||
.toFlowable(),
|
||||
{ group, _ ->
|
||||
group
|
||||
}
|
||||
{ group, _ ->
|
||||
group
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -145,8 +147,8 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap
|
|||
return Flowable.empty()
|
||||
}
|
||||
return apiClient.leaveGroup(id, if (keepChallenges) "remain-in-challenges" else "leave-challenges")
|
||||
.doOnNext { localRepository.updateMembership(userID, id, false) }
|
||||
.flatMapMaybe { localRepository.getGroup(id).firstElement() }
|
||||
.doOnNext { localRepository.updateMembership(userID, id, false) }
|
||||
.flatMapMaybe { localRepository.getGroup(id).firstElement() }
|
||||
}
|
||||
|
||||
override fun joinGroup(id: String?): Flowable<Group> {
|
||||
|
|
@ -154,10 +156,10 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap
|
|||
return Flowable.empty()
|
||||
}
|
||||
return apiClient.joinGroup(id)
|
||||
.doOnNext { group ->
|
||||
localRepository.updateMembership(userID, id, true)
|
||||
localRepository.save(group)
|
||||
}
|
||||
.doOnNext { group ->
|
||||
localRepository.updateMembership(userID, id, true)
|
||||
localRepository.save(group)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createGroup(name: String?, description: String?, leader: String?, type: String?, privacy: String?, leaderCreateChallenge: Boolean?): Flowable<Group> {
|
||||
|
|
@ -187,15 +189,15 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap
|
|||
|
||||
override fun retrieveGroups(type: String): Flowable<List<Group>> {
|
||||
return apiClient.listGroups(type)
|
||||
.doOnNext { groups ->
|
||||
if ("guilds" == type) {
|
||||
val memberships = groups.map {
|
||||
GroupMembership(userID, it.id)
|
||||
}
|
||||
localRepository.saveGroupMemberships(userID, memberships)
|
||||
.doOnNext { groups ->
|
||||
if ("guilds" == type) {
|
||||
val memberships = groups.map {
|
||||
GroupMembership(userID, it.id)
|
||||
}
|
||||
localRepository.save(groups)
|
||||
localRepository.saveGroupMemberships(userID, memberships)
|
||||
}
|
||||
localRepository.save(groups)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getGroups(type: String): Flowable<out List<Group>> = localRepository.getGroups(type)
|
||||
|
|
@ -236,7 +238,7 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap
|
|||
|
||||
override fun retrieveGroupMembers(id: String, includeAllPublicFields: Boolean): Flowable<List<Member>> {
|
||||
return apiClient.getGroupMembers(id, includeAllPublicFields)
|
||||
.doOnNext { members -> localRepository.saveGroupMembers(id, members) }
|
||||
.doOnNext { members -> localRepository.saveGroupMembers(id, members) }
|
||||
}
|
||||
|
||||
override fun inviteToGroup(id: String, inviteData: Map<String, Any>): Flowable<Void> = apiClient.inviteToGroup(id, inviteData)
|
||||
|
|
@ -247,7 +249,7 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap
|
|||
} else {
|
||||
try {
|
||||
apiClient.getMember(UUID.fromString(userId).toString())
|
||||
} catch(_: IllegalArgumentException) {
|
||||
} catch (_: IllegalArgumentException) {
|
||||
apiClient.getMemberWithUsername(userId)
|
||||
}
|
||||
}
|
||||
|
|
@ -263,31 +265,31 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap
|
|||
|
||||
override fun markPrivateMessagesRead(user: User?): Flowable<Void> {
|
||||
return apiClient.markPrivateMessagesRead()
|
||||
.doOnNext {
|
||||
if (user?.isManaged == true) {
|
||||
localRepository.modify(user) { it.inbox?.newMessages = 0 }
|
||||
}
|
||||
.doOnNext {
|
||||
if (user?.isManaged == true) {
|
||||
localRepository.modify(user) { it.inbox?.newMessages = 0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getUserGroups(type: String?): Flowable<out List<Group>> = localRepository.getUserGroups(userID, type)
|
||||
|
||||
override fun acceptQuest(user: User?, partyId: String): Flowable<Void> {
|
||||
return apiClient.acceptQuest(partyId)
|
||||
.doOnNext {
|
||||
user?.let {
|
||||
localRepository.updateRSVPNeeded(it, false)
|
||||
}
|
||||
.doOnNext {
|
||||
user?.let {
|
||||
localRepository.updateRSVPNeeded(it, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun rejectQuest(user: User?, partyId: String): Flowable<Void> {
|
||||
return apiClient.rejectQuest(partyId)
|
||||
.doOnNext { _ ->
|
||||
user?.let {
|
||||
localRepository.updateRSVPNeeded(it, false)
|
||||
}
|
||||
.doOnNext { _ ->
|
||||
user?.let {
|
||||
localRepository.updateRSVPNeeded(it, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun leaveQuest(partyId: String): Flowable<Void> {
|
||||
|
|
@ -296,24 +298,24 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap
|
|||
|
||||
override fun cancelQuest(partyId: String): Flowable<Void> {
|
||||
return apiClient.cancelQuest(partyId)
|
||||
.doOnNext { localRepository.removeQuest(partyId) }
|
||||
.doOnNext { localRepository.removeQuest(partyId) }
|
||||
}
|
||||
|
||||
override fun abortQuest(partyId: String): Flowable<Quest> {
|
||||
return apiClient.abortQuest(partyId)
|
||||
.doOnNext { localRepository.removeQuest(partyId) }
|
||||
.doOnNext { localRepository.removeQuest(partyId) }
|
||||
}
|
||||
|
||||
override fun rejectGroupInvite(groupId: String): Flowable<Void> {
|
||||
return apiClient.rejectGroupInvite(groupId)
|
||||
.doOnNext {
|
||||
localRepository.rejectGroupInvitation(userID, groupId)
|
||||
}
|
||||
.doOnNext {
|
||||
localRepository.rejectGroupInvitation(userID, groupId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun forceStartQuest(party: Group): Flowable<Quest> {
|
||||
return apiClient.forceStartQuest(party.id, localRepository.getUnmanagedCopy(party))
|
||||
.doOnNext { localRepository.setQuestActivity(party, true) }
|
||||
.doOnNext { localRepository.setQuestActivity(party, true) }
|
||||
}
|
||||
|
||||
override fun getMemberAchievements(userId: String?): Flowable<List<Achievement>> {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import com.habitrpg.android.habitica.models.Tag
|
|||
import io.reactivex.rxjava3.core.Flowable
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
|
||||
|
||||
class TagRepositoryImpl(localRepository: TagLocalRepository, apiClient: ApiClient, userID: String) : BaseRepositoryImpl<TagLocalRepository>(localRepository, apiClient, userID), TagRepository {
|
||||
|
||||
override fun getTags(): Flowable<out List<Tag>> {
|
||||
|
|
@ -20,43 +19,43 @@ class TagRepositoryImpl(localRepository: TagLocalRepository, apiClient: ApiClien
|
|||
|
||||
override fun createTag(tag: Tag): Flowable<Tag> {
|
||||
return apiClient.createTag(tag)
|
||||
.doOnNext {
|
||||
it.userId = userID
|
||||
localRepository.save(it)
|
||||
}
|
||||
.doOnNext {
|
||||
it.userId = userID
|
||||
localRepository.save(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateTag(tag: Tag): Flowable<Tag> {
|
||||
return apiClient.updateTag(tag.id, tag)
|
||||
.doOnNext {
|
||||
it.userId = userID
|
||||
localRepository.save(it)
|
||||
}
|
||||
.doOnNext {
|
||||
it.userId = userID
|
||||
localRepository.save(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun deleteTag(id: String): Flowable<Void> {
|
||||
return apiClient.deleteTag(id)
|
||||
.doOnNext {
|
||||
localRepository.deleteTag(id)
|
||||
}
|
||||
.doOnNext {
|
||||
localRepository.deleteTag(id)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createTags(tags: Collection<Tag>): Single<List<Tag>> {
|
||||
return Flowable.defer { Flowable.fromIterable(tags) }
|
||||
.filter { tag -> tag.name.isNotEmpty() }
|
||||
.flatMap { this.createTag(it) }
|
||||
.toList()
|
||||
.filter { tag -> tag.name.isNotEmpty() }
|
||||
.flatMap { this.createTag(it) }
|
||||
.toList()
|
||||
}
|
||||
|
||||
override fun updateTags(tags: Collection<Tag>): Single<List<Tag>> {
|
||||
return Flowable.defer { Flowable.fromIterable(tags) }
|
||||
.flatMap { this.updateTag(it) }
|
||||
.toList()
|
||||
.flatMap { this.updateTag(it) }
|
||||
.toList()
|
||||
}
|
||||
|
||||
override fun deleteTags(tagIds: Collection<String>): Single<List<Void>> {
|
||||
return Flowable.defer { Flowable.fromIterable(tagIds) }
|
||||
.flatMap { this.deleteTag(it) }
|
||||
.toList()
|
||||
.flatMap { this.deleteTag(it) }
|
||||
.toList()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,12 +22,11 @@ import io.reactivex.rxjava3.core.Single
|
|||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
||||
class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiClient, userID: String, val appConfigManager: AppConfigManager, val analyticsManager: AnalyticsManager) : BaseRepositoryImpl<TaskLocalRepository>(localRepository, apiClient, userID), TaskRepository {
|
||||
private var lastTaskAction: Long = 0
|
||||
|
||||
override fun getTasks(taskType: String, userID: String?): Flowable<out List<Task>> =
|
||||
this.localRepository.getTasks(taskType, userID ?: this.userID)
|
||||
this.localRepository.getTasks(taskType, userID ?: this.userID)
|
||||
|
||||
override fun saveTasks(userId: String, order: TasksOrder, tasks: TaskList) {
|
||||
localRepository.saveTasks(userId, order, tasks)
|
||||
|
|
@ -35,27 +34,27 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
|
|||
|
||||
override fun retrieveTasks(userId: String, tasksOrder: TasksOrder): Flowable<TaskList> {
|
||||
return this.apiClient.tasks
|
||||
.doOnNext { res -> this.localRepository.saveTasks(userId, tasksOrder, res) }
|
||||
.doOnNext { res -> this.localRepository.saveTasks(userId, tasksOrder, res) }
|
||||
}
|
||||
|
||||
override fun retrieveCompletedTodos(userId: String?): Flowable<TaskList> {
|
||||
return this.apiClient.getTasks("completedTodos")
|
||||
.doOnNext { taskList ->
|
||||
val tasks = taskList.tasks
|
||||
this.localRepository.saveCompletedTodos(userId ?: this.userID, tasks.values)
|
||||
}
|
||||
.doOnNext { taskList ->
|
||||
val tasks = taskList.tasks
|
||||
this.localRepository.saveCompletedTodos(userId ?: this.userID, tasks.values)
|
||||
}
|
||||
}
|
||||
|
||||
override fun retrieveTasks(userId: String, tasksOrder: TasksOrder, dueDate: Date): Flowable<TaskList> {
|
||||
val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZZ", Locale.US)
|
||||
return this.apiClient.getTasks("dailys", formatter.format(dueDate))
|
||||
.doOnNext { res -> this.localRepository.saveTasks(userId, tasksOrder, res) }
|
||||
.doOnNext { res -> this.localRepository.saveTasks(userId, tasksOrder, res) }
|
||||
}
|
||||
|
||||
@Suppress("ReturnCount")
|
||||
override fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable<TaskScoringResult?> {
|
||||
val localData = if (user != null && appConfigManager.enableLocalTaskScoring()) {
|
||||
ScoreTaskLocallyInteractor.score(user, task, if (up) TaskDirection.UP else TaskDirection.DOWN)
|
||||
ScoreTaskLocallyInteractor.score(user, task, if (up) TaskDirection.UP else TaskDirection.DOWN)
|
||||
} else null
|
||||
if (user != null && localData != null) {
|
||||
val stats = user.stats
|
||||
|
|
@ -82,44 +81,47 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
|
|||
|
||||
lastTaskAction = now
|
||||
return this.apiClient.postTaskDirection(id, (if (up) TaskDirection.UP else TaskDirection.DOWN).text)
|
||||
.flatMapMaybe {
|
||||
// There are cases where the user object is not set correctly. So the app refetches it as a fallback
|
||||
if (user == null) {
|
||||
localRepository.getUser(userID).firstElement()
|
||||
} else {
|
||||
Maybe.just(user)
|
||||
}.map { user -> Pair(it, user) }
|
||||
}
|
||||
.map { (res, user): Pair<TaskDirectionData, User> ->
|
||||
// save local task changes
|
||||
.flatMapMaybe {
|
||||
// There are cases where the user object is not set correctly. So the app refetches it as a fallback
|
||||
if (user == null) {
|
||||
localRepository.getUser(userID).firstElement()
|
||||
} else {
|
||||
Maybe.just(user)
|
||||
}.map { user -> Pair(it, user) }
|
||||
}
|
||||
.map { (res, user): Pair<TaskDirectionData, User> ->
|
||||
// save local task changes
|
||||
|
||||
analyticsManager.logEvent("task_scored", bundleOf(
|
||||
Pair("type", task.type),
|
||||
Pair("scored_up", up),
|
||||
Pair("value", task.value)
|
||||
))
|
||||
val result = TaskScoringResult()
|
||||
if (res.lvl == 0) {
|
||||
// Team tasks that require approval have weird data that we should just ignore.
|
||||
return@map result
|
||||
}
|
||||
val stats = user.stats
|
||||
|
||||
result.healthDelta = res.hp - (stats?.hp ?: 0.0)
|
||||
result.experienceDelta = res.exp - (stats?.exp ?: 0.0)
|
||||
result.manaDelta = res.mp - (stats?.mp ?: 0.0)
|
||||
result.goldDelta = res.gp - (stats?.gp ?: 0.0)
|
||||
result.hasLeveledUp = res.lvl > stats?.lvl ?: 0
|
||||
result.level = res.lvl
|
||||
result.questDamage = res._tmp?.quest?.progressDelta
|
||||
result.questItemsFound = res._tmp?.quest?.collection
|
||||
result.drop = res._tmp?.drop
|
||||
if (localData == null) {
|
||||
notifyFunc?.invoke(result)
|
||||
}
|
||||
handleTaskResponse(user, res, task, up, localData?.delta ?: 0f)
|
||||
result
|
||||
analyticsManager.logEvent(
|
||||
"task_scored",
|
||||
bundleOf(
|
||||
Pair("type", task.type),
|
||||
Pair("scored_up", up),
|
||||
Pair("value", task.value)
|
||||
)
|
||||
)
|
||||
val result = TaskScoringResult()
|
||||
if (res.lvl == 0) {
|
||||
// Team tasks that require approval have weird data that we should just ignore.
|
||||
return@map result
|
||||
}
|
||||
val stats = user.stats
|
||||
|
||||
result.healthDelta = res.hp - (stats?.hp ?: 0.0)
|
||||
result.experienceDelta = res.exp - (stats?.exp ?: 0.0)
|
||||
result.manaDelta = res.mp - (stats?.mp ?: 0.0)
|
||||
result.goldDelta = res.gp - (stats?.gp ?: 0.0)
|
||||
result.hasLeveledUp = res.lvl > stats?.lvl ?: 0
|
||||
result.level = res.lvl
|
||||
result.questDamage = res._tmp?.quest?.progressDelta
|
||||
result.questItemsFound = res._tmp?.quest?.collection
|
||||
result.drop = res._tmp?.drop
|
||||
if (localData == null) {
|
||||
notifyFunc?.invoke(result)
|
||||
}
|
||||
handleTaskResponse(user, res, task, up, localData?.delta ?: 0f)
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
override fun bulkScoreTasks(data: List<Map<String, String>>): Flowable<BulkTaskScoringData> {
|
||||
|
|
@ -146,7 +148,7 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
|
|||
}
|
||||
}
|
||||
res._tmp?.drop?.key?.let { key ->
|
||||
val type = when(res._tmp?.drop?.type?.lowercase(Locale.US)) {
|
||||
val type = when (res._tmp?.drop?.type?.lowercase(Locale.US)) {
|
||||
"hatchingpotion" -> "hatchingPotions"
|
||||
"egg" -> "eggs"
|
||||
else -> res._tmp?.drop?.type?.lowercase(Locale.US)
|
||||
|
|
@ -173,25 +175,27 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
|
|||
bgUser.stats?.mp = res.mp
|
||||
bgUser.stats?.gp = res.gp
|
||||
bgUser.stats?.lvl = res.lvl
|
||||
bgUser.party?.quest?.progress?.up = (bgUser.party?.quest?.progress?.up
|
||||
?: 0F) + (res._tmp?.quest?.progressDelta?.toFloat() ?: 0F)
|
||||
bgUser.party?.quest?.progress?.up = (
|
||||
bgUser.party?.quest?.progress?.up
|
||||
?: 0F
|
||||
) + (res._tmp?.quest?.progressDelta?.toFloat() ?: 0F)
|
||||
}
|
||||
}
|
||||
|
||||
override fun taskChecked(user: User?, taskId: String, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Maybe<TaskScoringResult?> {
|
||||
return localRepository.getTask(taskId).firstElement()
|
||||
.flatMap { task -> taskChecked(user, task, up, force, notifyFunc).singleElement() }
|
||||
.flatMap { task -> taskChecked(user, task, up, force, notifyFunc).singleElement() }
|
||||
}
|
||||
|
||||
override fun scoreChecklistItem(taskId: String, itemId: String): Flowable<Task> {
|
||||
return apiClient.scoreChecklistItem(taskId, itemId)
|
||||
.flatMapMaybe { localRepository.getTask(taskId).firstElement() }
|
||||
.doOnNext { task ->
|
||||
val updatedItem: ChecklistItem? = task.checklist?.lastOrNull { itemId == it.id }
|
||||
if (updatedItem != null) {
|
||||
localRepository.modify(updatedItem) { liveItem -> liveItem.completed = !liveItem.completed }
|
||||
}
|
||||
.flatMapMaybe { localRepository.getTask(taskId).firstElement() }
|
||||
.doOnNext { task ->
|
||||
val updatedItem: ChecklistItem? = task.checklist?.lastOrNull { itemId == it.id }
|
||||
if (updatedItem != null) {
|
||||
localRepository.modify(updatedItem) { liveItem -> liveItem.completed = !liveItem.completed }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTask(taskId: String): Flowable<Task> = localRepository.getTask(taskId)
|
||||
|
|
@ -200,7 +204,7 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
|
|||
|
||||
override fun createTask(task: Task, force: Boolean): Flowable<Task> {
|
||||
val now = Date().time
|
||||
if (lastTaskAction > now - 500 && !force) {
|
||||
if (lastTaskAction > now - 500 && !force) {
|
||||
return Flowable.empty()
|
||||
}
|
||||
lastTaskAction = now
|
||||
|
|
@ -215,25 +219,25 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
|
|||
localRepository.saveSyncronous(task)
|
||||
|
||||
return apiClient.createTask(task)
|
||||
.map { task1 ->
|
||||
task1.dateCreated = Date()
|
||||
task1
|
||||
}
|
||||
.doOnNext {
|
||||
it.tags = task.tags
|
||||
localRepository.save(it)
|
||||
}
|
||||
.doOnError {
|
||||
task.hasErrored = true
|
||||
task.isSaving = false
|
||||
localRepository.saveSyncronous(task)
|
||||
}
|
||||
.map { task1 ->
|
||||
task1.dateCreated = Date()
|
||||
task1
|
||||
}
|
||||
.doOnNext {
|
||||
it.tags = task.tags
|
||||
localRepository.save(it)
|
||||
}
|
||||
.doOnError {
|
||||
task.hasErrored = true
|
||||
task.isSaving = false
|
||||
localRepository.saveSyncronous(task)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("ReturnCount")
|
||||
override fun updateTask(task: Task, force: Boolean): Maybe<Task> {
|
||||
val now = Date().time
|
||||
if ((lastTaskAction > now - 500 && !force)|| !task.isValid ) {
|
||||
if ((lastTaskAction > now - 500 && !force) || !task.isValid) {
|
||||
return Maybe.just(task)
|
||||
}
|
||||
lastTaskAction = now
|
||||
|
|
@ -243,25 +247,25 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
|
|||
unmanagedTask.hasErrored = false
|
||||
localRepository.saveSyncronous(unmanagedTask)
|
||||
return apiClient.updateTask(id, unmanagedTask).singleElement()
|
||||
.map { task1 ->
|
||||
task1.position = task.position
|
||||
task1.id = task.id
|
||||
task1
|
||||
}
|
||||
.doOnSuccess {
|
||||
it.tags = task.tags
|
||||
localRepository.save(it)
|
||||
}
|
||||
.doOnError {
|
||||
unmanagedTask.hasErrored = true
|
||||
unmanagedTask.isSaving = false
|
||||
localRepository.saveSyncronous(unmanagedTask)
|
||||
}
|
||||
.map { task1 ->
|
||||
task1.position = task.position
|
||||
task1.id = task.id
|
||||
task1
|
||||
}
|
||||
.doOnSuccess {
|
||||
it.tags = task.tags
|
||||
localRepository.save(it)
|
||||
}
|
||||
.doOnError {
|
||||
unmanagedTask.hasErrored = true
|
||||
unmanagedTask.isSaving = false
|
||||
localRepository.saveSyncronous(unmanagedTask)
|
||||
}
|
||||
}
|
||||
|
||||
override fun deleteTask(taskId: String): Flowable<Void> {
|
||||
return apiClient.deleteTask(taskId)
|
||||
.doOnNext { localRepository.deleteTask(taskId) }
|
||||
.doOnNext { localRepository.deleteTask(taskId) }
|
||||
}
|
||||
|
||||
override fun saveTask(task: Task) {
|
||||
|
|
@ -274,7 +278,7 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
|
|||
localRepository.markTaskCompleted(taskId, isCompleted)
|
||||
}
|
||||
|
||||
override fun <T: BaseMainObject> modify(obj: T, transaction: (T) -> Unit) {
|
||||
override fun <T : BaseMainObject> modify(obj: T, transaction: (T) -> Unit) {
|
||||
localRepository.modify(obj, transaction)
|
||||
}
|
||||
|
||||
|
|
@ -284,11 +288,11 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
|
|||
|
||||
override fun updateTaskPosition(taskType: String, taskID: String, newPosition: Int): Maybe<List<String>> {
|
||||
return apiClient.postTaskNewPosition(taskID, newPosition).firstElement()
|
||||
.doOnSuccess { localRepository.updateTaskPositions(it) }
|
||||
.doOnSuccess { localRepository.updateTaskPositions(it) }
|
||||
}
|
||||
|
||||
override fun getUnmanagedTask(taskid: String): Flowable<Task> =
|
||||
getTask(taskid).map { localRepository.getUnmanagedCopy(it) }
|
||||
getTask(taskid).map { localRepository.getUnmanagedCopy(it) }
|
||||
|
||||
override fun updateTaskInBackground(task: Task) {
|
||||
updateTask(task).subscribe({ }, RxErrorHandler.handleEmptyError())
|
||||
|
|
@ -299,10 +303,10 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
|
|||
}
|
||||
|
||||
override fun getTaskCopies(userId: String): Flowable<List<Task>> =
|
||||
localRepository.getTasks(userId).map { localRepository.getUnmanagedCopy(it) }
|
||||
localRepository.getTasks(userId).map { localRepository.getUnmanagedCopy(it) }
|
||||
|
||||
override fun getTaskCopies(tasks: List<Task>): Flowable<List<Task>> =
|
||||
Flowable.just(localRepository.getUnmanagedCopy(tasks))
|
||||
Flowable.just(localRepository.getUnmanagedCopy(tasks))
|
||||
|
||||
override fun retrieveDailiesFromDate(date: Date): Flowable<TaskList> {
|
||||
val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZZ", Locale.US)
|
||||
|
|
@ -311,15 +315,15 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
|
|||
|
||||
override fun syncErroredTasks(): Single<List<Task>> {
|
||||
return localRepository.getErroredTasks(userID).firstElement()
|
||||
.flatMapPublisher { Flowable.fromIterable(it) }
|
||||
.map { localRepository.getUnmanagedCopy(it) }
|
||||
.flatMap {
|
||||
return@flatMap if (it.isCreating) {
|
||||
createTask(it, true)
|
||||
} else {
|
||||
updateTask(it, true).toFlowable()
|
||||
}
|
||||
}.toList()
|
||||
.flatMapPublisher { Flowable.fromIterable(it) }
|
||||
.map { localRepository.getUnmanagedCopy(it) }
|
||||
.flatMap {
|
||||
return@flatMap if (it.isCreating) {
|
||||
createTask(it, true)
|
||||
} else {
|
||||
updateTask(it, true).toFlowable()
|
||||
}
|
||||
}.toList()
|
||||
}
|
||||
|
||||
override fun unlinkAllTasks(challengeID: String?, keepOption: String): Flowable<Void> {
|
||||
|
|
|
|||
|
|
@ -6,12 +6,11 @@ import com.habitrpg.android.habitica.data.local.TutorialLocalRepository
|
|||
import com.habitrpg.android.habitica.models.TutorialStep
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
|
||||
|
||||
class TutorialRepositoryImpl(localRepository: TutorialLocalRepository, apiClient: ApiClient, userID: String) : BaseRepositoryImpl<TutorialLocalRepository>(localRepository, apiClient, userID), TutorialRepository {
|
||||
|
||||
override fun getTutorialStep(key: String): Flowable<TutorialStep> =
|
||||
localRepository.getTutorialStep(key)
|
||||
localRepository.getTutorialStep(key)
|
||||
|
||||
override fun getTutorialSteps(keys: List<String>): Flowable<out List<TutorialStep>> =
|
||||
localRepository.getTutorialSteps(keys)
|
||||
localRepository.getTutorialSteps(keys)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,13 +34,14 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
|
||||
override fun getUser(): Flowable<User> = getUser(userID)
|
||||
|
||||
|
||||
override fun getUser(userID: String): Flowable<User> = localRepository.getUser(userID)
|
||||
|
||||
private fun updateUser(userID: String, updateData: Map<String, Any>): Flowable<User> {
|
||||
return Flowable.zip(apiClient.updateUser(updateData),
|
||||
localRepository.getUser(userID).firstElement().toFlowable(),
|
||||
{ newUser, user -> mergeUser(user, newUser) })
|
||||
return Flowable.zip(
|
||||
apiClient.updateUser(updateData),
|
||||
localRepository.getUser(userID).firstElement().toFlowable(),
|
||||
{ newUser, user -> mergeUser(user, newUser) }
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateUser(userID: String, key: String, value: Any): Flowable<User> {
|
||||
|
|
@ -58,7 +59,7 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
}
|
||||
|
||||
override fun retrieveUser(withTasks: Boolean): Flowable<User> =
|
||||
retrieveUser(withTasks, false)
|
||||
retrieveUser(withTasks, false)
|
||||
|
||||
@Suppress("ReturnCount")
|
||||
override fun retrieveUser(withTasks: Boolean, forced: Boolean, overrideExisting: Boolean): Flowable<User> {
|
||||
|
|
@ -66,48 +67,48 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
if (forced || this.lastSync == null || Date().time - (this.lastSync?.time ?: 0) > 180000) {
|
||||
lastSync = Date()
|
||||
return apiClient.retrieveUser(withTasks)
|
||||
.doOnNext { localRepository.saveUser(it, overrideExisting) }
|
||||
.doOnNext { user ->
|
||||
if (withTasks) {
|
||||
val id = user.id
|
||||
val tasksOrder = user.tasksOrder
|
||||
val tasks = user.tasks
|
||||
if (id != null && tasksOrder != null && tasks != null) {
|
||||
taskRepository.saveTasks(id, tasksOrder, tasks)
|
||||
}
|
||||
.doOnNext { localRepository.saveUser(it, overrideExisting) }
|
||||
.doOnNext { user ->
|
||||
if (withTasks) {
|
||||
val id = user.id
|
||||
val tasksOrder = user.tasksOrder
|
||||
val tasks = user.tasks
|
||||
if (id != null && tasksOrder != null && tasks != null) {
|
||||
taskRepository.saveTasks(id, tasksOrder, tasks)
|
||||
}
|
||||
}
|
||||
.flatMap { user ->
|
||||
val calendar = GregorianCalendar()
|
||||
val timeZone = calendar.timeZone
|
||||
val offset = -TimeUnit.MINUTES.convert(timeZone.getOffset(calendar.timeInMillis).toLong(), TimeUnit.MILLISECONDS)
|
||||
if (offset.toInt() != user.preferences?.timezoneOffset ?: 0) {
|
||||
return@flatMap updateUser(user.id ?: "", "preferences.timezoneOffset", offset.toString())
|
||||
} else {
|
||||
return@flatMap Flowable.just(user)
|
||||
}
|
||||
}
|
||||
.flatMap { user ->
|
||||
val calendar = GregorianCalendar()
|
||||
val timeZone = calendar.timeZone
|
||||
val offset = -TimeUnit.MINUTES.convert(timeZone.getOffset(calendar.timeInMillis).toLong(), TimeUnit.MILLISECONDS)
|
||||
if (offset.toInt() != user.preferences?.timezoneOffset ?: 0) {
|
||||
return@flatMap updateUser(user.id ?: "", "preferences.timezoneOffset", offset.toString())
|
||||
} else {
|
||||
return@flatMap Flowable.just(user)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return getUser().take(1)
|
||||
}
|
||||
}
|
||||
|
||||
override fun revive(user: User): Flowable<User> =
|
||||
apiClient.revive().map { newUser -> mergeUser(user, newUser) }
|
||||
.flatMap { retrieveUser(false, true) }
|
||||
apiClient.revive().map { newUser -> mergeUser(user, newUser) }
|
||||
.flatMap { retrieveUser(false, true) }
|
||||
|
||||
override fun resetTutorial() {
|
||||
localRepository.getTutorialSteps()
|
||||
.firstElement()
|
||||
.map<Map<String, Any>> { tutorialSteps ->
|
||||
val updateData = HashMap<String, Any>()
|
||||
for (step in tutorialSteps) {
|
||||
updateData["flags.tutorial." + step.tutorialGroup + "." + step.identifier] = false
|
||||
}
|
||||
updateData
|
||||
.firstElement()
|
||||
.map<Map<String, Any>> { tutorialSteps ->
|
||||
val updateData = HashMap<String, Any>()
|
||||
for (step in tutorialSteps) {
|
||||
updateData["flags.tutorial." + step.tutorialGroup + "." + step.identifier] = false
|
||||
}
|
||||
.flatMap { updateData -> updateUser(updateData).firstElement() }
|
||||
.subscribe({ }, RxErrorHandler.handleEmptyError())
|
||||
updateData
|
||||
}
|
||||
.flatMap { updateData -> updateUser(updateData).firstElement() }
|
||||
.subscribe({ }, RxErrorHandler.handleEmptyError())
|
||||
}
|
||||
|
||||
override fun sleep(user: User): Flowable<User> {
|
||||
|
|
@ -116,10 +117,10 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
}
|
||||
|
||||
override fun getSkills(user: User): Flowable<out List<Skill>> =
|
||||
localRepository.getSkills(user)
|
||||
localRepository.getSkills(user)
|
||||
|
||||
override fun getSpecialItems(user: User): Flowable<out List<Skill>> =
|
||||
localRepository.getSpecialItems(user)
|
||||
localRepository.getSpecialItems(user)
|
||||
|
||||
override fun useSkill(key: String, target: String?, taskId: String): Flowable<SkillResponse> {
|
||||
return zipWithLiveUser(apiClient.useSkill(key, target ?: "", taskId)) { response, user ->
|
||||
|
|
@ -174,16 +175,20 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
return Flowable.just(null)
|
||||
}
|
||||
path = path.substring(1)
|
||||
return Flowable.zip(apiClient.unlockPath(path), localRepository.getUser(userID).firstElement().toFlowable()
|
||||
return Flowable.zip(
|
||||
apiClient.unlockPath(path),
|
||||
localRepository.getUser(userID).firstElement().toFlowable()
|
||||
.map { localRepository.getUnmanagedCopy(it) }
|
||||
.skipNull(), { unlockResponse, copiedUser ->
|
||||
copiedUser.preferences = unlockResponse.preferences
|
||||
copiedUser.purchased = unlockResponse.purchased
|
||||
copiedUser.items = unlockResponse.items
|
||||
copiedUser.balance = copiedUser.balance - set.price / 4.0
|
||||
localRepository.saveUser(copiedUser, false)
|
||||
unlockResponse
|
||||
})
|
||||
.skipNull(),
|
||||
{ unlockResponse, copiedUser ->
|
||||
copiedUser.preferences = unlockResponse.preferences
|
||||
copiedUser.purchased = unlockResponse.purchased
|
||||
copiedUser.items = unlockResponse.items
|
||||
copiedUser.balance = copiedUser.balance - set.price / 4.0
|
||||
localRepository.saveUser(copiedUser, false)
|
||||
unlockResponse
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun runCron() {
|
||||
|
|
@ -197,14 +202,14 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
|
||||
override fun reroll(): Flowable<User> {
|
||||
return apiClient.reroll()
|
||||
.flatMap { retrieveUser(true, true, true) }
|
||||
.flatMap { retrieveUser(true, true, true) }
|
||||
}
|
||||
|
||||
override fun readNotifications(notificationIds: Map<String, List<String>>): Flowable<List<Any>> =
|
||||
apiClient.readNotifications(notificationIds)
|
||||
apiClient.readNotifications(notificationIds)
|
||||
|
||||
override fun seeNotifications(notificationIds: Map<String, List<String>>): Flowable<List<Any>> =
|
||||
apiClient.seeNotifications(notificationIds)
|
||||
apiClient.seeNotifications(notificationIds)
|
||||
|
||||
override fun changeCustomDayStart(dayStartTime: Int): Flowable<User> {
|
||||
val updateObject = HashMap<String, Any>()
|
||||
|
|
@ -214,7 +219,7 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
|
||||
override fun updateLanguage(languageCode: String): Flowable<User> {
|
||||
return updateUser("preferences.language", languageCode)
|
||||
.doOnNext { apiClient.setLanguageCode(languageCode) }
|
||||
.doOnNext { apiClient.setLanguageCode(languageCode) }
|
||||
}
|
||||
|
||||
override fun resetAccount(): Flowable<User> {
|
||||
|
|
@ -222,46 +227,51 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
}
|
||||
|
||||
override fun deleteAccount(password: String): Flowable<Void> =
|
||||
apiClient.deleteAccount(password)
|
||||
apiClient.deleteAccount(password)
|
||||
|
||||
override fun sendPasswordResetEmail(email: String): Flowable<Void> =
|
||||
apiClient.sendPasswordResetEmail(email)
|
||||
apiClient.sendPasswordResetEmail(email)
|
||||
|
||||
override fun updateLoginName(newLoginName: String, password: String?): Maybe<User> {
|
||||
return (if (password != null && password.isNotEmpty()) {
|
||||
apiClient.updateLoginName(newLoginName.trim(), password.trim())
|
||||
} else {
|
||||
apiClient.updateUsername(newLoginName.trim())
|
||||
}).flatMapMaybe { localRepository.getUser(userID).firstElement() }
|
||||
.doOnNext { user ->
|
||||
localRepository.modify(user) { liveUser ->
|
||||
liveUser.authentication?.localAuthentication?.username = newLoginName
|
||||
liveUser.flags?.verifiedUsername = true
|
||||
}
|
||||
return (
|
||||
if (password != null && password.isNotEmpty()) {
|
||||
apiClient.updateLoginName(newLoginName.trim(), password.trim())
|
||||
} else {
|
||||
apiClient.updateUsername(newLoginName.trim())
|
||||
}
|
||||
).flatMapMaybe { localRepository.getUser(userID).firstElement() }
|
||||
.doOnNext { user ->
|
||||
localRepository.modify(user) { liveUser ->
|
||||
liveUser.authentication?.localAuthentication?.username = newLoginName
|
||||
liveUser.flags?.verifiedUsername = true
|
||||
}
|
||||
.firstElement()
|
||||
}
|
||||
.firstElement()
|
||||
}
|
||||
|
||||
override fun verifyUsername(username: String): Flowable<VerifyUsernameResponse> = apiClient.verifyUsername(username.trim())
|
||||
|
||||
override fun updateEmail(newEmail: String, password: String): Flowable<Void> =
|
||||
apiClient.updateEmail(newEmail.trim(), password)
|
||||
apiClient.updateEmail(newEmail.trim(), password)
|
||||
|
||||
override fun updatePassword(oldPassword: String, newPassword: String, newPasswordConfirmation: String): Flowable<Void> =
|
||||
apiClient.updatePassword(oldPassword.trim(), newPassword.trim(), newPasswordConfirmation.trim())
|
||||
apiClient.updatePassword(oldPassword.trim(), newPassword.trim(), newPasswordConfirmation.trim())
|
||||
|
||||
override fun allocatePoint(stat: String): Flowable<Stats> {
|
||||
getLiveUser().firstElement().subscribe( { liveUser ->
|
||||
localRepository.executeTransaction {
|
||||
when (stat) {
|
||||
Stats.STRENGTH -> liveUser.stats?.strength = liveUser.stats?.strength?.inc()
|
||||
Stats.INTELLIGENCE -> liveUser.stats?.intelligence = liveUser.stats?.intelligence?.inc()
|
||||
Stats.CONSTITUTION -> liveUser.stats?.constitution= liveUser.stats?.constitution?.inc()
|
||||
Stats.PERCEPTION -> liveUser.stats?.per = liveUser.stats?.per?.inc()
|
||||
getLiveUser().firstElement().subscribe(
|
||||
{ liveUser ->
|
||||
localRepository.executeTransaction {
|
||||
when (stat) {
|
||||
Stats.STRENGTH -> liveUser.stats?.strength = liveUser.stats?.strength?.inc()
|
||||
Stats.INTELLIGENCE -> liveUser.stats?.intelligence = liveUser.stats?.intelligence?.inc()
|
||||
Stats.CONSTITUTION -> liveUser.stats?.constitution = liveUser.stats?.constitution?.inc()
|
||||
Stats.PERCEPTION -> liveUser.stats?.per = liveUser.stats?.per?.inc()
|
||||
}
|
||||
liveUser.stats?.points = liveUser.stats?.points?.dec()
|
||||
}
|
||||
liveUser.stats?.points = liveUser.stats?.points?.dec()
|
||||
}
|
||||
}, RxErrorHandler.handleEmptyError())
|
||||
},
|
||||
RxErrorHandler.handleEmptyError()
|
||||
)
|
||||
return zipWithLiveUser(apiClient.allocatePoint(stat)) { stats, user ->
|
||||
localRepository.modify(user) { liveUser ->
|
||||
liveUser.stats?.strength = stats.strength
|
||||
|
|
@ -276,28 +286,28 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
}
|
||||
|
||||
override fun bulkAllocatePoints(strength: Int, intelligence: Int, constitution: Int, perception: Int): Flowable<Stats> =
|
||||
zipWithLiveUser(apiClient.bulkAllocatePoints(strength, intelligence, constitution, perception)) { stats, user ->
|
||||
localRepository.modify(user) { liveUser ->
|
||||
liveUser.stats?.strength = stats.strength
|
||||
liveUser.stats?.constitution = stats.constitution
|
||||
liveUser.stats?.per = stats.per
|
||||
liveUser.stats?.intelligence = stats.intelligence
|
||||
liveUser.stats?.points = stats.points
|
||||
liveUser.stats?.mp = stats.mp
|
||||
}
|
||||
stats
|
||||
zipWithLiveUser(apiClient.bulkAllocatePoints(strength, intelligence, constitution, perception)) { stats, user ->
|
||||
localRepository.modify(user) { liveUser ->
|
||||
liveUser.stats?.strength = stats.strength
|
||||
liveUser.stats?.constitution = stats.constitution
|
||||
liveUser.stats?.per = stats.per
|
||||
liveUser.stats?.intelligence = stats.intelligence
|
||||
liveUser.stats?.points = stats.points
|
||||
liveUser.stats?.mp = stats.mp
|
||||
}
|
||||
stats
|
||||
}
|
||||
|
||||
override fun runCron(tasks: MutableList<Task>) {
|
||||
var observable: Maybe<Any> = localRepository.getUser(userID).firstElement()
|
||||
.filter { it.needsCron }
|
||||
.map { user ->
|
||||
localRepository.modify(user) { liveUser ->
|
||||
liveUser.needsCron = false
|
||||
liveUser.lastCron = Date()
|
||||
}
|
||||
user
|
||||
.filter { it.needsCron }
|
||||
.map { user ->
|
||||
localRepository.modify(user) { liveUser ->
|
||||
liveUser.needsCron = false
|
||||
liveUser.lastCron = Date()
|
||||
}
|
||||
user
|
||||
}
|
||||
if (tasks.isNotEmpty()) {
|
||||
val scoringList = mutableListOf<Map<String, String>>()
|
||||
for (task in tasks) {
|
||||
|
|
@ -309,32 +319,35 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
observable = observable.flatMap { taskRepository.bulkScoreTasks(scoringList).firstElement() }
|
||||
}
|
||||
observable.flatMap { apiClient.runCron().firstElement() }
|
||||
.flatMap { this.retrieveUser(withTasks = true, forced = true).firstElement() }
|
||||
.subscribe({ }, RxErrorHandler.handleEmptyError())
|
||||
.flatMap { this.retrieveUser(withTasks = true, forced = true).firstElement() }
|
||||
.subscribe({ }, RxErrorHandler.handleEmptyError())
|
||||
}
|
||||
|
||||
override fun useCustomization(type: String, category: String?, identifier: String): Flowable<User> {
|
||||
if (appConfigManager.enableLocalChanges()) {
|
||||
localRepository.getUser(userID).firstElement().subscribe( { liveUser ->
|
||||
localRepository.modify(liveUser) { liveUser ->
|
||||
when (type) {
|
||||
"skin" -> liveUser.preferences?.skin = identifier
|
||||
"shirt" -> liveUser.preferences?.shirt = identifier
|
||||
"hair" -> {
|
||||
when (category) {
|
||||
"color" -> liveUser.preferences?.hair?.color = identifier
|
||||
"flower" -> liveUser.preferences?.hair?.flower = identifier.toInt()
|
||||
"mustache" -> liveUser.preferences?.hair?.mustache = identifier.toInt()
|
||||
"beard" -> liveUser.preferences?.hair?.beard = identifier.toInt()
|
||||
"bangs" -> liveUser.preferences?.hair?.bangs = identifier.toInt()
|
||||
"base" -> liveUser.preferences?.hair?.base = identifier.toInt()
|
||||
localRepository.getUser(userID).firstElement().subscribe(
|
||||
{ liveUser ->
|
||||
localRepository.modify(liveUser) { liveUser ->
|
||||
when (type) {
|
||||
"skin" -> liveUser.preferences?.skin = identifier
|
||||
"shirt" -> liveUser.preferences?.shirt = identifier
|
||||
"hair" -> {
|
||||
when (category) {
|
||||
"color" -> liveUser.preferences?.hair?.color = identifier
|
||||
"flower" -> liveUser.preferences?.hair?.flower = identifier.toInt()
|
||||
"mustache" -> liveUser.preferences?.hair?.mustache = identifier.toInt()
|
||||
"beard" -> liveUser.preferences?.hair?.beard = identifier.toInt()
|
||||
"bangs" -> liveUser.preferences?.hair?.bangs = identifier.toInt()
|
||||
"base" -> liveUser.preferences?.hair?.base = identifier.toInt()
|
||||
}
|
||||
}
|
||||
"background" -> liveUser.preferences?.background = identifier
|
||||
"chair" -> liveUser.preferences?.chair = identifier
|
||||
}
|
||||
"background" -> liveUser.preferences?.background = identifier
|
||||
"chair" -> liveUser.preferences?.chair = identifier
|
||||
}
|
||||
}
|
||||
}, RxErrorHandler.handleEmptyError())
|
||||
},
|
||||
RxErrorHandler.handleEmptyError()
|
||||
)
|
||||
}
|
||||
var updatePath = "preferences.$type"
|
||||
if (category != null) {
|
||||
|
|
@ -369,20 +382,22 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
}
|
||||
|
||||
override fun retrieveTeamPlan(teamID: String): Flowable<Group> {
|
||||
return Flowable.zip(apiClient.getGroup(teamID), apiClient.getTeamPlanTasks(teamID),
|
||||
{ team, tasks ->
|
||||
team.tasks = tasks
|
||||
team
|
||||
})
|
||||
.doOnNext { localRepository.save(it) }
|
||||
.doOnNext { team ->
|
||||
val id = team.id
|
||||
val tasksOrder = team.tasksOrder
|
||||
val tasks = team.tasks
|
||||
if (id.isNotBlank() && tasksOrder != null && tasks != null) {
|
||||
taskRepository.saveTasks(id, tasksOrder, tasks)
|
||||
}
|
||||
return Flowable.zip(
|
||||
apiClient.getGroup(teamID), apiClient.getTeamPlanTasks(teamID),
|
||||
{ team, tasks ->
|
||||
team.tasks = tasks
|
||||
team
|
||||
}
|
||||
)
|
||||
.doOnNext { localRepository.save(it) }
|
||||
.doOnNext { team ->
|
||||
val id = team.id
|
||||
val tasksOrder = team.tasksOrder
|
||||
val tasks = team.tasks
|
||||
if (id.isNotBlank() && tasksOrder != null && tasks != null) {
|
||||
taskRepository.saveTasks(id, tasksOrder, tasks)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTeamPlan(teamID: String): Flowable<Group> {
|
||||
|
|
@ -391,8 +406,8 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
|
|||
|
||||
private fun getLiveUser(): Flowable<User> {
|
||||
return localRepository.getUser(userID)
|
||||
.map { localRepository.getLiveObject(it) }
|
||||
.skipNull()
|
||||
.map { localRepository.getLiveObject(it) }
|
||||
.skipNull()
|
||||
}
|
||||
|
||||
private fun <T> zipWithLiveUser(flowable: Flowable<T>, mergeFunc: BiFunction<T, User, T>): Flowable<T> {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ package com.habitrpg.android.habitica.data.local
|
|||
|
||||
import com.habitrpg.android.habitica.models.BaseMainObject
|
||||
import com.habitrpg.android.habitica.models.BaseObject
|
||||
import com.habitrpg.android.habitica.models.user.OwnedObject
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmModel
|
||||
|
||||
interface BaseLocalRepository {
|
||||
|
||||
|
|
@ -17,14 +15,14 @@ interface BaseLocalRepository {
|
|||
fun executeTransaction(transaction: Realm.Transaction)
|
||||
fun executeTransactionAsync(transaction: (Realm) -> Unit)
|
||||
fun executeTransactionAsync(transaction: Realm.Transaction)
|
||||
fun <T: BaseMainObject> modify(obj: T, transaction: (T) -> Unit)
|
||||
fun <T: BaseMainObject> modifyWithRealm(obj: T, transaction: (Realm, T) -> Unit)
|
||||
fun <T: BaseObject> getLiveObject(obj: T): T?
|
||||
fun <T : BaseMainObject> modify(obj: T, transaction: (T) -> Unit)
|
||||
fun <T : BaseMainObject> modifyWithRealm(obj: T, transaction: (Realm, T) -> Unit)
|
||||
fun <T : BaseObject> getLiveObject(obj: T): T?
|
||||
|
||||
fun <T: BaseObject> getUnmanagedCopy(managedObject: T): T
|
||||
fun <T: BaseObject> getUnmanagedCopy(list: List<T>): List<T>
|
||||
fun <T : BaseObject> getUnmanagedCopy(managedObject: T): T
|
||||
fun <T : BaseObject> getUnmanagedCopy(list: List<T>): List<T>
|
||||
|
||||
fun <T: BaseObject> save(objects: List<T>)
|
||||
fun <T: BaseObject> save(`object`: T)
|
||||
fun <T: BaseObject> saveSyncronous(`object`: T)
|
||||
fun <T : BaseObject> save(objects: List<T>)
|
||||
fun <T : BaseObject> save(`object`: T)
|
||||
fun <T : BaseObject> saveSyncronous(`object`: T)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
package com.habitrpg.android.habitica.data.local
|
||||
|
||||
|
||||
import com.habitrpg.android.habitica.models.social.Challenge
|
||||
import com.habitrpg.android.habitica.models.social.ChallengeMembership
|
||||
import com.habitrpg.android.habitica.models.tasks.Task
|
||||
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
|
||||
interface ChallengeLocalRepository : BaseLocalRepository {
|
||||
|
|
@ -21,5 +19,4 @@ interface ChallengeLocalRepository : BaseLocalRepository {
|
|||
fun getChallengeMembership(userId: String, id: String): Flowable<ChallengeMembership>
|
||||
fun getChallengeMemberships(userId: String): Flowable<out List<ChallengeMembership>>
|
||||
fun isChallengeMember(userID: String, challengeID: String): Flowable<Boolean>
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.habitrpg.android.habitica.data.local
|
||||
|
||||
import com.habitrpg.android.habitica.models.inventory.Customization
|
||||
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
|
||||
interface CustomizationLocalRepository : ContentLocalRepository {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.habitrpg.android.habitica.data.local
|
||||
|
||||
import com.habitrpg.android.habitica.models.FAQArticle
|
||||
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
|
||||
interface FAQLocalRepository : ContentLocalRepository {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.habitrpg.android.habitica.data.local
|
||||
|
||||
import com.habitrpg.android.habitica.models.Tag
|
||||
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
|
||||
interface TagLocalRepository : BaseLocalRepository {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.habitrpg.android.habitica.data.local
|
||||
|
||||
import com.habitrpg.android.habitica.models.tasks.RemindersItem
|
||||
import com.habitrpg.android.habitica.models.tasks.Task
|
||||
import com.habitrpg.android.habitica.models.tasks.TaskList
|
||||
import com.habitrpg.android.habitica.models.tasks.TasksOrder
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
package com.habitrpg.android.habitica.data.local.implementation
|
||||
|
||||
import android.renderscript.BaseObj
|
||||
import com.habitrpg.android.habitica.data.local.BaseLocalRepository
|
||||
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
|
||||
|
||||
|
|
@ -72,15 +70,15 @@ abstract class RealmBaseLocalRepository internal constructor(override var realm:
|
|||
realm.executeTransaction { realm1 -> realm1.insertOrUpdate(`object`) }
|
||||
}
|
||||
|
||||
override fun <T: BaseMainObject> modify(obj: T, transaction: (T) -> Unit) {
|
||||
override fun <T : BaseMainObject> modify(obj: T, transaction: (T) -> Unit) {
|
||||
if (isClosed) { return }
|
||||
val liveObject = getLiveObject(obj) ?: return
|
||||
val liveObject = getLiveObject(obj) ?: return
|
||||
realm.executeTransaction {
|
||||
transaction(liveObject)
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T: BaseMainObject> modifyWithRealm(obj: T, transaction: (Realm, T) -> Unit) {
|
||||
override fun <T : BaseMainObject> modifyWithRealm(obj: T, transaction: (Realm, T) -> Unit) {
|
||||
if (isClosed) { return }
|
||||
val liveObject = getLiveObject(obj) ?: return
|
||||
realm.executeTransaction {
|
||||
|
|
@ -88,19 +86,20 @@ abstract class RealmBaseLocalRepository internal constructor(override var realm:
|
|||
}
|
||||
}
|
||||
|
||||
override fun <T: BaseObject> getLiveObject(obj: T): T? {
|
||||
override fun <T : BaseObject> getLiveObject(obj: T): T? {
|
||||
if (isClosed) return null
|
||||
if (!(obj is RealmObject) || !obj.isManaged) return obj
|
||||
val baseObject = obj as? BaseMainObject ?: return null
|
||||
return realm.where(baseObject.realmClass).equalTo(baseObject.primaryIdentifierName, baseObject.primaryIdentifier).findFirst() as? T
|
||||
}
|
||||
|
||||
|
||||
fun queryUser(userID: String): Flowable<User> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(User::class.java)
|
||||
.equalTo("id", userID)
|
||||
.findAll()
|
||||
.asFlowable())
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(User::class.java)
|
||||
.equalTo("id", userID)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
)
|
||||
.filter { it.isLoaded && it.isValid && !it.isEmpty() }
|
||||
.map { it.first() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,73 +13,87 @@ import java.util.*
|
|||
|
||||
class RealmChallengeLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm), ChallengeLocalRepository {
|
||||
|
||||
override fun isChallengeMember(userID: String, challengeID: String): Flowable<Boolean> = RxJavaBridge.toV3Flowable(realm.where(ChallengeMembership::class.java)
|
||||
override fun isChallengeMember(userID: String, challengeID: String): Flowable<Boolean> = RxJavaBridge.toV3Flowable(
|
||||
realm.where(ChallengeMembership::class.java)
|
||||
.equalTo("userID", userID)
|
||||
.equalTo("challengeID", challengeID)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }).map { it.count() > 0 }
|
||||
.filter { it.isLoaded }
|
||||
).map { it.count() > 0 }
|
||||
|
||||
override fun getChallengeMembership(userId: String, id: String): Flowable<ChallengeMembership> = RxJavaBridge.toV3Flowable(realm.where(ChallengeMembership::class.java)
|
||||
override fun getChallengeMembership(userId: String, id: String): Flowable<ChallengeMembership> = RxJavaBridge.toV3Flowable(
|
||||
realm.where(ChallengeMembership::class.java)
|
||||
.equalTo("userID", userId)
|
||||
.equalTo("challengeID", id)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }).map { it.first() }
|
||||
.filter { it.isLoaded }
|
||||
).map { it.first() }
|
||||
|
||||
override fun getChallengeMemberships(userId: String): Flowable<out List<ChallengeMembership>> = RxJavaBridge.toV3Flowable(realm.where(ChallengeMembership::class.java)
|
||||
override fun getChallengeMemberships(userId: String): Flowable<out List<ChallengeMembership>> = RxJavaBridge.toV3Flowable(
|
||||
realm.where(ChallengeMembership::class.java)
|
||||
.equalTo("userID", userId)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
|
||||
override fun getChallenge(id: String): Flowable<Challenge> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Challenge::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Challenge::class.java)
|
||||
.equalTo("id", id)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { realmObject -> realmObject.isLoaded && realmObject.isNotEmpty() }
|
||||
.map { it.first() })
|
||||
.map { it.first() }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getTasks(challengeID: String): Flowable<out List<Task>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Task::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Task::class.java)
|
||||
.equalTo("userId", challengeID)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { realmObject -> realmObject.isLoaded })
|
||||
.filter { realmObject -> realmObject.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override val challenges: Flowable<out List<Challenge>>
|
||||
get() = RxJavaBridge.toV3Flowable(realm.where(Challenge::class.java)
|
||||
get() = RxJavaBridge.toV3Flowable(
|
||||
realm.where(Challenge::class.java)
|
||||
.isNotNull("name")
|
||||
.sort("official", Sort.DESCENDING, "createdAt", Sort.DESCENDING)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
|
||||
override fun getUserChallenges(userId: String): Flowable<out List<Challenge>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(ChallengeMembership::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(ChallengeMembership::class.java)
|
||||
.equalTo("userID", userId)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.flatMap { it ->
|
||||
val ids = it.map {
|
||||
return@map it.challengeID
|
||||
}.toTypedArray()
|
||||
realm.where(Challenge::class.java)
|
||||
.isNotNull("name")
|
||||
.beginGroup()
|
||||
.`in`("id", ids)
|
||||
.or()
|
||||
.equalTo("leaderId", userId)
|
||||
.endGroup()
|
||||
.sort("official", Sort.DESCENDING, "createdAt", Sort.DESCENDING)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }
|
||||
}
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
.flatMap { it ->
|
||||
val ids = it.map {
|
||||
return@map it.challengeID
|
||||
}.toTypedArray()
|
||||
realm.where(Challenge::class.java)
|
||||
.isNotNull("name")
|
||||
.beginGroup()
|
||||
.`in`("id", ids)
|
||||
.or()
|
||||
.equalTo("leaderId", userId)
|
||||
.endGroup()
|
||||
.sort("official", Sort.DESCENDING, "createdAt", Sort.DESCENDING)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }
|
||||
}
|
||||
}
|
||||
|
||||
override fun setParticipating(userID: String, challengeID: String, isParticipating: Boolean) {
|
||||
|
|
@ -100,9 +114,10 @@ class RealmChallengeLocalRepository(realm: Realm) : RealmBaseLocalRepository(rea
|
|||
val memberships = realm.where(ChallengeMembership::class.java).findAll()
|
||||
val challengesToDelete = ArrayList<Challenge>()
|
||||
for (localTask in localChallenges) {
|
||||
if (!challenges.contains(localTask)
|
||||
&& memberships.find { it.challengeID == localTask.id } == null
|
||||
&& localTask.leaderId != userID) {
|
||||
if (!challenges.contains(localTask) &&
|
||||
memberships.find { it.challengeID == localTask.id } == null &&
|
||||
localTask.leaderId != userID
|
||||
) {
|
||||
challengesToDelete.add(localTask)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,8 @@ import com.habitrpg.android.habitica.models.inventory.Quest
|
|||
import com.habitrpg.android.habitica.models.social.Group
|
||||
import hu.akarnokd.rxjava3.bridge.RxJavaBridge
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
|
||||
import io.realm.Realm
|
||||
|
||||
|
||||
open class RealmContentLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm), ContentLocalRepository {
|
||||
|
||||
override fun saveContent(contentResult: ContentResult) {
|
||||
|
|
@ -37,18 +35,22 @@ open class RealmContentLocalRepository(realm: Realm) : RealmBaseLocalRepository(
|
|||
}
|
||||
|
||||
override fun getWorldState(): Flowable<WorldState> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(WorldState::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(WorldState::class.java)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded && it.size > 0 }
|
||||
.map { it.first() })
|
||||
.skipNull()
|
||||
.map { it.first() }
|
||||
)
|
||||
.skipNull()
|
||||
}
|
||||
|
||||
override fun saveWorldState(worldState: WorldState) {
|
||||
val tavern = getUnmanagedCopy(realm.where(Group::class.java)
|
||||
val tavern = getUnmanagedCopy(
|
||||
realm.where(Group::class.java)
|
||||
.equalTo("id", Group.TAVERN_ID)
|
||||
.findFirst() ?: Group())
|
||||
.findFirst() ?: Group()
|
||||
)
|
||||
if (!tavern.isManaged) {
|
||||
tavern.id = Group.TAVERN_ID
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,33 +7,34 @@ import io.reactivex.rxjava3.core.Flowable
|
|||
import io.realm.Realm
|
||||
import java.util.*
|
||||
|
||||
|
||||
class RealmCustomizationLocalRepository(realm: Realm) : RealmContentLocalRepository(realm), CustomizationLocalRepository {
|
||||
|
||||
override fun getCustomizations(type: String, category: String?, onlyAvailable: Boolean): Flowable<out List<Customization>> {
|
||||
var query = realm.where(Customization::class.java)
|
||||
.equalTo("type", type)
|
||||
.equalTo("category", category)
|
||||
.equalTo("type", type)
|
||||
.equalTo("category", category)
|
||||
if (onlyAvailable) {
|
||||
val today = Date()
|
||||
query = query
|
||||
.beginGroup()
|
||||
.beginGroup()
|
||||
.lessThanOrEqualTo("availableFrom", today)
|
||||
.greaterThanOrEqualTo("availableUntil", today)
|
||||
.endGroup()
|
||||
.or()
|
||||
.beginGroup()
|
||||
.isNull("availableFrom")
|
||||
.isNull("availableUntil")
|
||||
.endGroup()
|
||||
.endGroup()
|
||||
.beginGroup()
|
||||
.beginGroup()
|
||||
.lessThanOrEqualTo("availableFrom", today)
|
||||
.greaterThanOrEqualTo("availableUntil", today)
|
||||
.endGroup()
|
||||
.or()
|
||||
.beginGroup()
|
||||
.isNull("availableFrom")
|
||||
.isNull("availableUntil")
|
||||
.endGroup()
|
||||
.endGroup()
|
||||
}
|
||||
return RxJavaBridge.toV3Flowable(query
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
query
|
||||
.sort("customizationSetName")
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }
|
||||
.map { it })
|
||||
.map { it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,17 +8,21 @@ import io.realm.Realm
|
|||
|
||||
class RealmFAQLocalRepository(realm: Realm) : RealmContentLocalRepository(realm), FAQLocalRepository {
|
||||
override fun getArticle(position: Int): Flowable<FAQArticle> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(FAQArticle::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(FAQArticle::class.java)
|
||||
.equalTo("position", position)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter{ it.isLoaded && it.count() > 0 }
|
||||
.map { it.first() })
|
||||
.filter { it.isLoaded && it.count() > 0 }
|
||||
.map { it.first() }
|
||||
)
|
||||
}
|
||||
|
||||
override val articles: Flowable<out List<FAQArticle>>
|
||||
get() = RxJavaBridge.toV3Flowable(realm.where(FAQArticle::class.java)
|
||||
get() = RxJavaBridge.toV3Flowable(
|
||||
realm.where(FAQArticle::class.java)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter{ it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,12 @@ package com.habitrpg.android.habitica.data.local.implementation
|
|||
|
||||
import com.habitrpg.android.habitica.data.local.InventoryLocalRepository
|
||||
import com.habitrpg.android.habitica.helpers.RxErrorHandler
|
||||
import com.habitrpg.android.habitica.models.BaseMainObject
|
||||
import com.habitrpg.android.habitica.models.inventory.*
|
||||
import com.habitrpg.android.habitica.models.shops.ShopItem
|
||||
import com.habitrpg.android.habitica.models.user.*
|
||||
import hu.akarnokd.rxjava3.bridge.RxJavaBridge
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.Sort
|
||||
import io.realm.kotlin.isManaged
|
||||
|
|
@ -17,67 +15,78 @@ import java.text.SimpleDateFormat
|
|||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
|
||||
class RealmInventoryLocalRepository(realm: Realm) : RealmContentLocalRepository(realm), InventoryLocalRepository {
|
||||
override fun getQuestContent(keys: List<String>): Flowable<out List<QuestContent>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(QuestContent::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(QuestContent::class.java)
|
||||
.`in`("key", keys.toTypedArray())
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getQuestContent(key: String): Flowable<QuestContent> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(QuestContent::class.java).equalTo("key", key)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(QuestContent::class.java).equalTo("key", key)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { content -> content.isLoaded && content.isValid && !content.isEmpty() }
|
||||
.map { content -> content.first() })
|
||||
.map { content -> content.first() }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getEquipment(searchedKeys: List<String>): Flowable<out List<Equipment>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Equipment::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Equipment::class.java)
|
||||
.`in`("key", searchedKeys.toTypedArray())
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getArmoireRemainingCount(): Long {
|
||||
return realm.where(Equipment::class.java)
|
||||
.equalTo("klass", "armoire")
|
||||
.beginGroup()
|
||||
.equalTo("owned", false)
|
||||
.or()
|
||||
.isNull("owned")
|
||||
.endGroup()
|
||||
.count()
|
||||
.equalTo("klass", "armoire")
|
||||
.beginGroup()
|
||||
.equalTo("owned", false)
|
||||
.or()
|
||||
.isNull("owned")
|
||||
.endGroup()
|
||||
.count()
|
||||
}
|
||||
|
||||
override fun getOwnedEquipment(type: String): Flowable<out List<Equipment>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Equipment::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Equipment::class.java)
|
||||
.equalTo("type", type)
|
||||
.equalTo("owned", true)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getOwnedEquipment(): Flowable<out List<Equipment>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Equipment::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Equipment::class.java)
|
||||
.equalTo("owned", true)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getEquipmentType(type: String, set: String): Flowable<out List<Equipment>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Equipment::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Equipment::class.java)
|
||||
.equalTo("type", type)
|
||||
.equalTo("gearSet", set)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getOwnedItems(itemType: String, userID: String, includeZero: Boolean): Flowable<out List<OwnedItem>> {
|
||||
|
|
@ -99,13 +108,17 @@ class RealmInventoryLocalRepository(realm: Realm) : RealmContentLocalRepository(
|
|||
}
|
||||
|
||||
override fun getItems(itemClass: Class<out Item>, keys: Array<String>): Flowable<out List<Item>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(itemClass).`in`("key", keys).findAll().asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(itemClass).`in`("key", keys).findAll().asFlowable()
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getItems(itemClass: Class<out Item>): Flowable<out List<Item>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(itemClass).findAll().asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(itemClass).findAll().asFlowable()
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getOwnedItems(userID: String, includeZero: Boolean): Flowable<Map<String, OwnedItem>> {
|
||||
|
|
@ -124,25 +137,29 @@ class RealmInventoryLocalRepository(realm: Realm) : RealmContentLocalRepository(
|
|||
}
|
||||
|
||||
override fun getEquipment(key: String): Flowable<Equipment> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Equipment::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Equipment::class.java)
|
||||
.equalTo("key", key)
|
||||
.findFirstAsync()
|
||||
.asFlowable<RealmObject>()
|
||||
.filter { realmObject -> realmObject.isLoaded }
|
||||
.cast(Equipment::class.java))
|
||||
.cast(Equipment::class.java)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getMounts(): Flowable<out List<Mount>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Mount::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Mount::class.java)
|
||||
.sort("type", Sort.ASCENDING, "animal", Sort.ASCENDING)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getMounts(type: String?, group: String?, color: String?): Flowable<out List<Mount>> {
|
||||
var query = realm.where(Mount::class.java)
|
||||
.sort("type", Sort.ASCENDING, if (color == null) "color" else "animal", Sort.ASCENDING)
|
||||
.sort("type", Sort.ASCENDING, if (color == null) "color" else "animal", Sort.ASCENDING)
|
||||
if (type != null) {
|
||||
query = query.equalTo("animal", type)
|
||||
}
|
||||
|
|
@ -152,30 +169,35 @@ class RealmInventoryLocalRepository(realm: Realm) : RealmContentLocalRepository(
|
|||
if (color != null) {
|
||||
query = query.equalTo("color", color)
|
||||
}
|
||||
return RxJavaBridge.toV3Flowable(query.findAll()
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
query.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getOwnedMounts(userID: String): Flowable<out List<OwnedMount>> {
|
||||
return queryUser(userID)
|
||||
.map { it.items?.mounts?.filter {
|
||||
it.owned == true
|
||||
} ?: emptyList() }
|
||||
.map {
|
||||
it.items?.mounts?.filter {
|
||||
it.owned == true
|
||||
} ?: emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun getPets(): Flowable<out List<Pet>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Pet::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Pet::class.java)
|
||||
.sort("type", Sort.ASCENDING, "animal", Sort.ASCENDING)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getPets(type: String?, group: String?, color: String?): Flowable<out List<Pet>> {
|
||||
var query = realm.where(Pet::class.java)
|
||||
.sort("type", Sort.ASCENDING, if (color == null) "color" else "animal", Sort.ASCENDING)
|
||||
.sort("type", Sort.ASCENDING, if (color == null) "color" else "animal", Sort.ASCENDING)
|
||||
if (type != null) {
|
||||
query = query.equalTo("animal", type)
|
||||
}
|
||||
|
|
@ -185,28 +207,33 @@ class RealmInventoryLocalRepository(realm: Realm) : RealmContentLocalRepository(
|
|||
if (color != null) {
|
||||
query = query.equalTo("color", color)
|
||||
}
|
||||
return RxJavaBridge.toV3Flowable(query.findAll()
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
query.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getOwnedPets(userID: String): Flowable<out List<OwnedPet>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(User::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(User::class.java)
|
||||
.equalTo("id", userID)
|
||||
.findAll()
|
||||
.asFlowable())
|
||||
.asFlowable()
|
||||
)
|
||||
.filter { it.isLoaded && it.isValid && !it.isEmpty() }
|
||||
.map { it.first()?.items?.pets?.filter {
|
||||
it.trained > 0
|
||||
} ?: emptyList() }
|
||||
.map {
|
||||
it.first()?.items?.pets?.filter {
|
||||
it.trained > 0
|
||||
} ?: emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateOwnedEquipment(user: User) {
|
||||
|
||||
}
|
||||
|
||||
override fun changeOwnedCount(type: String, key: String, userID: String, amountToAdd: Int) {
|
||||
getOwnedItem(userID, type, key, true).firstElement().subscribe({ changeOwnedCount(it, amountToAdd)}, RxErrorHandler.handleEmptyError())
|
||||
getOwnedItem(userID, type, key, true).firstElement().subscribe({ changeOwnedCount(it, amountToAdd) }, RxErrorHandler.handleEmptyError())
|
||||
}
|
||||
|
||||
override fun changeOwnedCount(item: OwnedItem, amountToAdd: Int?) {
|
||||
|
|
@ -218,13 +245,15 @@ class RealmInventoryLocalRepository(realm: Realm) : RealmContentLocalRepository(
|
|||
|
||||
override fun getOwnedItem(userID: String, type: String, key: String, includeZero: Boolean): Flowable<OwnedItem> {
|
||||
return queryUser(userID).map {
|
||||
var items = (when (type) {
|
||||
"eggs" -> it.items?.eggs
|
||||
"hatchingPotions" -> it.items?.hatchingPotions
|
||||
"food" -> it.items?.food
|
||||
"quests" -> it.items?.quests
|
||||
else -> emptyList()
|
||||
} ?: emptyList())
|
||||
var items = (
|
||||
when (type) {
|
||||
"eggs" -> it.items?.eggs
|
||||
"hatchingPotions" -> it.items?.hatchingPotions
|
||||
"food" -> it.items?.food
|
||||
"quests" -> it.items?.quests
|
||||
else -> emptyList()
|
||||
} ?: emptyList()
|
||||
)
|
||||
items = items.filter { it.key == key }
|
||||
if (includeZero) {
|
||||
items
|
||||
|
|
@ -245,9 +274,11 @@ class RealmInventoryLocalRepository(realm: Realm) : RealmContentLocalRepository(
|
|||
"special" -> SpecialItem::class.java
|
||||
else -> Egg::class.java
|
||||
}
|
||||
return RxJavaBridge.toV3Flowable(realm.where(itemClass).equalTo("key", key).findFirstAsync().asFlowable<RealmObject>()
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(itemClass).equalTo("key", key).findFirstAsync().asFlowable<RealmObject>()
|
||||
.filter { realmObject -> realmObject.isLoaded }
|
||||
.cast(Item::class.java))
|
||||
.cast(Item::class.java)
|
||||
)
|
||||
}
|
||||
|
||||
override fun decrementMysteryItemCount(user: User?) {
|
||||
|
|
@ -268,10 +299,12 @@ class RealmInventoryLocalRepository(realm: Realm) : RealmContentLocalRepository(
|
|||
}
|
||||
|
||||
override fun getInAppRewards(): Flowable<out List<ShopItem>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(ShopItem::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(ShopItem::class.java)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun saveInAppRewards(onlineItems: List<ShopItem>) {
|
||||
|
|
@ -344,24 +377,26 @@ class RealmInventoryLocalRepository(realm: Realm) : RealmContentLocalRepository(
|
|||
}
|
||||
|
||||
override fun getLatestMysteryItem(): Flowable<Equipment> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Equipment::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Equipment::class.java)
|
||||
.contains("key", "mystery_2")
|
||||
.sort("mystery", Sort.DESCENDING)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded && it.size > 0}
|
||||
.filter { it.isLoaded && it.size > 0 }
|
||||
.map {
|
||||
val format = SimpleDateFormat("yyyyMM", Locale.US)
|
||||
it.first {
|
||||
it.key?.contains(format.format(Date())) == true
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun soldItem(userID: String, updatedUser: User): User {
|
||||
val user = realm.where(User::class.java)
|
||||
.equalTo("id", userID)
|
||||
.findFirst() ?: return updatedUser
|
||||
.equalTo("id", userID)
|
||||
.findFirst() ?: return updatedUser
|
||||
executeTransaction {
|
||||
val items = updatedUser.items
|
||||
if (items != null) {
|
||||
|
|
@ -377,30 +412,30 @@ class RealmInventoryLocalRepository(realm: Realm) : RealmContentLocalRepository(
|
|||
|
||||
override fun getAvailableLimitedItems(): Flowable<List<Item>> {
|
||||
return Flowable.combineLatest(
|
||||
realm.where(Egg::class.java)
|
||||
.lessThan("event.start", Date())
|
||||
.greaterThan("event.end", Date())
|
||||
.findAll().asFlowable(),
|
||||
realm.where(Food::class.java)
|
||||
.lessThan("event.start", Date())
|
||||
.greaterThan("event.end", Date())
|
||||
.findAll().asFlowable(),
|
||||
realm.where(HatchingPotion::class.java)
|
||||
.lessThan("event.start", Date())
|
||||
.greaterThan("event.end", Date())
|
||||
.findAll().asFlowable(),
|
||||
realm.where(QuestContent::class.java)
|
||||
.lessThan("event.start", Date())
|
||||
.greaterThan("event.end", Date())
|
||||
.findAll().asFlowable(),
|
||||
{ eggs, food, potions, quests ->
|
||||
val items = mutableListOf<Item>()
|
||||
items.addAll(eggs)
|
||||
items.addAll(food)
|
||||
items.addAll(potions)
|
||||
items.addAll(quests)
|
||||
items
|
||||
}
|
||||
realm.where(Egg::class.java)
|
||||
.lessThan("event.start", Date())
|
||||
.greaterThan("event.end", Date())
|
||||
.findAll().asFlowable(),
|
||||
realm.where(Food::class.java)
|
||||
.lessThan("event.start", Date())
|
||||
.greaterThan("event.end", Date())
|
||||
.findAll().asFlowable(),
|
||||
realm.where(HatchingPotion::class.java)
|
||||
.lessThan("event.start", Date())
|
||||
.greaterThan("event.end", Date())
|
||||
.findAll().asFlowable(),
|
||||
realm.where(QuestContent::class.java)
|
||||
.lessThan("event.start", Date())
|
||||
.greaterThan("event.end", Date())
|
||||
.findAll().asFlowable(),
|
||||
{ eggs, food, potions, quests ->
|
||||
val items = mutableListOf<Item>()
|
||||
items.addAll(eggs)
|
||||
items.addAll(food)
|
||||
items.addAll(potions)
|
||||
items.addAll(quests)
|
||||
items
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import com.habitrpg.android.habitica.data.local.SocialLocalRepository
|
|||
import com.habitrpg.android.habitica.models.inventory.Quest
|
||||
import com.habitrpg.android.habitica.models.members.Member
|
||||
import com.habitrpg.android.habitica.models.social.*
|
||||
import com.habitrpg.android.habitica.models.user.ContributorInfo
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import hu.akarnokd.rxjava3.bridge.RxJavaBridge
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
|
|
@ -12,28 +11,33 @@ import io.realm.Realm
|
|||
import io.realm.Sort
|
||||
import java.util.*
|
||||
|
||||
|
||||
class RealmSocialLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm), SocialLocalRepository {
|
||||
override fun getChatMessage(messageID: String): Flowable<ChatMessage> = RxJavaBridge.toV3Flowable(realm.where(ChatMessage::class.java)
|
||||
override fun getChatMessage(messageID: String): Flowable<ChatMessage> = RxJavaBridge.toV3Flowable(
|
||||
realm.where(ChatMessage::class.java)
|
||||
.equalTo("id", messageID)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded && it.isNotEmpty() }
|
||||
.map { it.first() })
|
||||
.map { it.first() }
|
||||
)
|
||||
|
||||
override fun getGroupMembership(userId: String, id: String): Flowable<GroupMembership> = RxJavaBridge.toV3Flowable(realm.where(GroupMembership::class.java)
|
||||
override fun getGroupMembership(userId: String, id: String): Flowable<GroupMembership> = RxJavaBridge.toV3Flowable(
|
||||
realm.where(GroupMembership::class.java)
|
||||
.equalTo("userID", userId)
|
||||
.equalTo("groupID", id)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded && it.isNotEmpty() }
|
||||
.map { it.first() })
|
||||
.map { it.first() }
|
||||
)
|
||||
|
||||
override fun getGroupMemberships(userId: String): Flowable<out List<GroupMembership>> = RxJavaBridge.toV3Flowable(realm.where(GroupMembership::class.java)
|
||||
override fun getGroupMemberships(userId: String): Flowable<out List<GroupMembership>> = RxJavaBridge.toV3Flowable(
|
||||
realm.where(GroupMembership::class.java)
|
||||
.equalTo("userID", userId)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
|
||||
override fun updateMembership(userId: String, id: String, isMember: Boolean) {
|
||||
if (isMember) {
|
||||
|
|
@ -108,60 +112,73 @@ class RealmSocialLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm)
|
|||
}
|
||||
}
|
||||
|
||||
override fun getPublicGuilds(): Flowable<out List<Group>> = RxJavaBridge.toV3Flowable(realm.where(Group::class.java)
|
||||
override fun getPublicGuilds(): Flowable<out List<Group>> = RxJavaBridge.toV3Flowable(
|
||||
realm.where(Group::class.java)
|
||||
.equalTo("type", "guild")
|
||||
.equalTo("privacy", "public")
|
||||
.notEqualTo("id", Group.TAVERN_ID)
|
||||
.sort("memberCount", Sort.DESCENDING)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
|
||||
override fun getUserGroups(userID: String, type: String?): Flowable<out List<Group>> = RxJavaBridge.toV3Flowable(realm.where(GroupMembership::class.java)
|
||||
override fun getUserGroups(userID: String, type: String?): Flowable<out List<Group>> = RxJavaBridge.toV3Flowable(
|
||||
realm.where(GroupMembership::class.java)
|
||||
.equalTo("userID", userID)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.flatMap {memberships ->
|
||||
RxJavaBridge.toV3Flowable(realm.where(Group::class.java)
|
||||
.equalTo("type", type ?: "guild")
|
||||
.notEqualTo("id", Group.TAVERN_ID)
|
||||
.`in`("id", memberships.map {
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
.flatMap { memberships ->
|
||||
RxJavaBridge.toV3Flowable(
|
||||
realm.where(Group::class.java)
|
||||
.equalTo("type", type ?: "guild")
|
||||
.notEqualTo("id", Group.TAVERN_ID)
|
||||
.`in`(
|
||||
"id",
|
||||
memberships.map {
|
||||
return@map it.groupID
|
||||
}.toTypedArray())
|
||||
.sort("memberCount", Sort.DESCENDING)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
}
|
||||
|
||||
|
||||
}.toTypedArray()
|
||||
)
|
||||
.sort("memberCount", Sort.DESCENDING)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getGroups(type: String): Flowable<out List<Group>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Group::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Group::class.java)
|
||||
.equalTo("type", type)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getGroup(id: String): Flowable<Group> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Group::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Group::class.java)
|
||||
.equalTo("id", id)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { group -> group.isLoaded && group.isValid && !group.isEmpty() }
|
||||
.map { groups -> groups.first() })
|
||||
.map { groups -> groups.first() }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getGroupChat(groupId: String): Flowable<out List<ChatMessage>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(ChatMessage::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(ChatMessage::class.java)
|
||||
.equalTo("groupId", groupId)
|
||||
.sort("timestamp", Sort.DESCENDING)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
}
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun deleteMessage(id: String) {
|
||||
val chatMessage = realm.where(ChatMessage::class.java).equalTo("id", id).findFirst()
|
||||
|
|
@ -169,12 +186,14 @@ class RealmSocialLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm)
|
|||
}
|
||||
|
||||
override fun getGroupMembers(partyId: String): Flowable<out List<Member>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Member::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Member::class.java)
|
||||
.equalTo("party.id", partyId)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
}
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun updateRSVPNeeded(user: User?, newValue: Boolean) {
|
||||
executeTransaction { user?.party?.quest?.RSVPNeeded = newValue }
|
||||
|
|
@ -192,9 +211,11 @@ class RealmSocialLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm)
|
|||
}
|
||||
} else {
|
||||
liveMessage?.likes?.filter { userId == it.id }?.forEach { like ->
|
||||
executeTransaction(Realm.Transaction {
|
||||
like.deleteFromRealm()
|
||||
})
|
||||
executeTransaction(
|
||||
Realm.Transaction {
|
||||
like.deleteFromRealm()
|
||||
}
|
||||
)
|
||||
}
|
||||
executeTransaction {
|
||||
liveMessage?.likeCount = liveMessage?.likes?.size ?: 0
|
||||
|
|
@ -266,22 +287,26 @@ class RealmSocialLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm)
|
|||
}
|
||||
|
||||
override fun getInboxMessages(userId: String, replyToUserID: String?): Flowable<out List<ChatMessage>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(ChatMessage::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(ChatMessage::class.java)
|
||||
.equalTo("isInboxMessage", true)
|
||||
.equalTo("uuid", replyToUserID)
|
||||
.equalTo("userID", userId)
|
||||
.sort("timestamp", Sort.DESCENDING)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
}
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getInboxConversation(userId: String): Flowable<out List<InboxConversation>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(InboxConversation::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(InboxConversation::class.java)
|
||||
.equalTo("userID", userId)
|
||||
.sort("timestamp", Sort.DESCENDING)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
}
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import hu.akarnokd.rxjava3.bridge.RxJavaBridge
|
|||
import io.reactivex.rxjava3.core.Flowable
|
||||
import io.realm.Realm
|
||||
|
||||
|
||||
class RealmTagLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm), TagLocalRepository {
|
||||
override fun deleteTag(tagID: String) {
|
||||
val tag = realm.where(Tag::class.java).equalTo("id", tagID).findFirst()
|
||||
|
|
|
|||
|
|
@ -16,25 +16,29 @@ class RealmTaskLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
|
|||
if (realm.isClosed) {
|
||||
return Flowable.empty()
|
||||
}
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Task::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Task::class.java)
|
||||
.equalTo("type", taskType)
|
||||
.equalTo("userId", userID)
|
||||
.sort("position", Sort.ASCENDING, "dateCreated", Sort.DESCENDING)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }).retry(1)
|
||||
.filter { it.isLoaded }
|
||||
).retry(1)
|
||||
}
|
||||
|
||||
override fun getTasks(userId: String): Flowable<out List<Task>> {
|
||||
if (realm.isClosed) {
|
||||
return Flowable.empty()
|
||||
}
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Task::class.java).equalTo("userId", userId)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Task::class.java).equalTo("userId", userId)
|
||||
.sort("position", Sort.ASCENDING, "dateCreated", Sort.DESCENDING)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
}
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun saveTasks(ownerID: String, tasksOrder: TasksOrder, tasks: TaskList) {
|
||||
val sortedTasks = ArrayList<Task>()
|
||||
|
|
@ -105,17 +109,17 @@ class RealmTaskLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
|
|||
private fun removeOldTasks(userID: String, onlineTaskList: List<Task>) {
|
||||
if (realm.isClosed) return
|
||||
val localTasks = realm.where(Task::class.java)
|
||||
.equalTo("userId", userID)
|
||||
.beginGroup()
|
||||
.beginGroup()
|
||||
.equalTo("type", Task.TYPE_TODO)
|
||||
.equalTo("completed", false)
|
||||
.endGroup()
|
||||
.or()
|
||||
.notEqualTo("type", Task.TYPE_TODO)
|
||||
.endGroup()
|
||||
.findAll()
|
||||
.createSnapshot()
|
||||
.equalTo("userId", userID)
|
||||
.beginGroup()
|
||||
.beginGroup()
|
||||
.equalTo("type", Task.TYPE_TODO)
|
||||
.equalTo("completed", false)
|
||||
.endGroup()
|
||||
.or()
|
||||
.notEqualTo("type", Task.TYPE_TODO)
|
||||
.endGroup()
|
||||
.findAll()
|
||||
.createSnapshot()
|
||||
val tasksToDelete = localTasks.filterNot { onlineTaskList.contains(it) }
|
||||
executeTransaction {
|
||||
for (localTask in tasksToDelete) {
|
||||
|
|
@ -126,11 +130,11 @@ class RealmTaskLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
|
|||
|
||||
private fun removeCompletedTodos(userID: String, onlineTaskList: MutableCollection<Task>) {
|
||||
val localTasks = realm.where(Task::class.java)
|
||||
.equalTo("userId", userID)
|
||||
.equalTo("type", Task.TYPE_TODO)
|
||||
.equalTo("completed", true)
|
||||
.findAll()
|
||||
.createSnapshot()
|
||||
.equalTo("userId", userID)
|
||||
.equalTo("type", Task.TYPE_TODO)
|
||||
.equalTo("completed", true)
|
||||
.findAll()
|
||||
.createSnapshot()
|
||||
val tasksToDelete = localTasks.filterNot { onlineTaskList.contains(it) }
|
||||
executeTransaction {
|
||||
for (localTask in tasksToDelete) {
|
||||
|
|
@ -152,20 +156,22 @@ class RealmTaskLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
|
|||
if (realm.isClosed) {
|
||||
return Flowable.empty()
|
||||
}
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Task::class.java).equalTo("id", taskId).findFirstAsync().asFlowable<RealmObject>()
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Task::class.java).equalTo("id", taskId).findFirstAsync().asFlowable<RealmObject>()
|
||||
.filter { realmObject -> realmObject.isLoaded }
|
||||
.cast(Task::class.java))
|
||||
.cast(Task::class.java)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getTaskCopy(taskId: String): Flowable<Task> {
|
||||
return getTask(taskId)
|
||||
.map { task ->
|
||||
return@map if (task.isManaged && task.isValid) {
|
||||
realm.copyFromRealm(task)
|
||||
} else {
|
||||
task
|
||||
}
|
||||
.map { task ->
|
||||
return@map if (task.isManaged && task.isValid) {
|
||||
realm.copyFromRealm(task)
|
||||
} else {
|
||||
task
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun markTaskCompleted(taskId: String, isCompleted: Boolean) {
|
||||
|
|
@ -185,20 +191,22 @@ class RealmTaskLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
|
|||
}
|
||||
|
||||
override fun getTaskAtPosition(taskType: String, position: Int): Flowable<Task> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Task::class.java).equalTo("type", taskType).equalTo("position", position).findFirstAsync().asFlowable<RealmObject>()
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Task::class.java).equalTo("type", taskType).equalTo("position", position).findFirstAsync().asFlowable<RealmObject>()
|
||||
.filter { realmObject -> realmObject.isLoaded }
|
||||
.cast(Task::class.java))
|
||||
.cast(Task::class.java)
|
||||
)
|
||||
}
|
||||
|
||||
override fun updateIsdue(daily: TaskList): Maybe<TaskList> {
|
||||
return Flowable.just(realm.where(Task::class.java).equalTo("type", "daily").findAll())
|
||||
.firstElement()
|
||||
.map { tasks ->
|
||||
realm.beginTransaction()
|
||||
tasks.filter { daily.tasks.containsKey(it.id) }.forEach { it.isDue = daily.tasks[it.id]?.isDue }
|
||||
realm.commitTransaction()
|
||||
daily
|
||||
}
|
||||
.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 updateTaskPositions(taskOrder: List<String>) {
|
||||
|
|
@ -211,31 +219,37 @@ class RealmTaskLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
|
|||
}
|
||||
|
||||
override fun getErroredTasks(userID: String): Flowable<out List<Task>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Task::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Task::class.java)
|
||||
.equalTo("userId", userID)
|
||||
.equalTo("hasErrored", true)
|
||||
.sort("position")
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }).retry(1)
|
||||
.filter { it.isLoaded }
|
||||
).retry(1)
|
||||
}
|
||||
|
||||
override fun getUser(userID: String): Flowable<User> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(User::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(User::class.java)
|
||||
.equalTo("id", userID)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { realmObject -> realmObject.isLoaded && realmObject.isValid && !realmObject.isEmpty() }
|
||||
.map { users -> users.first() })
|
||||
.map { users -> users.first() }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getTasksForChallenge(challengeID: String?, userID: String?): Flowable<out List<Task>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Task::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Task::class.java)
|
||||
.equalTo("challengeID", challengeID)
|
||||
.equalTo("userId", userID)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.retry(1)
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
.retry(1)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ import hu.akarnokd.rxjava3.bridge.RxJavaBridge
|
|||
import io.reactivex.rxjava3.core.Flowable
|
||||
import io.realm.Realm
|
||||
|
||||
|
||||
class RealmTutorialLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm), TutorialLocalRepository {
|
||||
|
||||
override fun getTutorialStep(key: String): Flowable<TutorialStep> {
|
||||
if (realm.isClosed) return Flowable.empty()
|
||||
return RxJavaBridge.toV3Flowable(realm.where(TutorialStep::class.java).equalTo("identifier", key)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(TutorialStep::class.java).equalTo("identifier", key)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { realmObject -> realmObject.isLoaded && realmObject.isValid && realmObject.isNotEmpty() }
|
||||
|
|
@ -26,15 +26,18 @@ class RealmTutorialLocalRepository(realm: Realm) : RealmBaseLocalRepository(real
|
|||
steps
|
||||
}
|
||||
}
|
||||
.map { steps -> steps.first() })
|
||||
.map { steps -> steps.first() }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getTutorialSteps(keys: List<String>): Flowable<out List<TutorialStep>> {
|
||||
if (realm.isClosed) return Flowable.empty()
|
||||
return RxJavaBridge.toV3Flowable(realm.where(TutorialStep::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(TutorialStep::class.java)
|
||||
.`in`("identifier", keys.toTypedArray())
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
}
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,8 @@ package com.habitrpg.android.habitica.data.local.implementation
|
|||
import com.habitrpg.android.habitica.data.local.UserLocalRepository
|
||||
import com.habitrpg.android.habitica.data.local.UserQuestStatus
|
||||
import com.habitrpg.android.habitica.models.*
|
||||
import com.habitrpg.android.habitica.models.social.ChallengeMembership
|
||||
import com.habitrpg.android.habitica.models.social.ChatMessage
|
||||
import com.habitrpg.android.habitica.models.social.Group
|
||||
import com.habitrpg.android.habitica.models.user.OwnedMount
|
||||
import com.habitrpg.android.habitica.models.user.OwnedPet
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import hu.akarnokd.rxjava3.bridge.RxJavaBridge
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
|
|
@ -16,59 +13,71 @@ import io.realm.Realm
|
|||
class RealmUserLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm), UserLocalRepository {
|
||||
override fun getUserQuestStatus(userID: String): Flowable<UserQuestStatus> {
|
||||
return getUser(userID)
|
||||
.map { it.party?.id ?: "" }
|
||||
.filter { it.isNotBlank() }
|
||||
.flatMap {
|
||||
RxJavaBridge.toV3Flowable(realm.where(Group::class.java)
|
||||
.equalTo("id", it)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { groups -> groups.size > 0 }
|
||||
.map { groups -> groups.first() })
|
||||
}
|
||||
.map { when {
|
||||
.map { it.party?.id ?: "" }
|
||||
.filter { it.isNotBlank() }
|
||||
.flatMap {
|
||||
RxJavaBridge.toV3Flowable(
|
||||
realm.where(Group::class.java)
|
||||
.equalTo("id", it)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { groups -> groups.size > 0 }
|
||||
.map { groups -> groups.first() }
|
||||
)
|
||||
}
|
||||
.map {
|
||||
when {
|
||||
it?.quest?.members?.find { questMember -> questMember.key == userID } === null -> UserQuestStatus.NO_QUEST
|
||||
it.quest?.progress?.collect?.isNotEmpty() ?: false -> UserQuestStatus.QUEST_COLLECT
|
||||
it.quest?.progress?.hp ?: 0.0 > 0.0 -> UserQuestStatus.QUEST_BOSS
|
||||
else -> UserQuestStatus.QUEST_UNKNOWN
|
||||
}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAchievements(): Flowable<out List<Achievement>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Achievement::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Achievement::class.java)
|
||||
.sort("index")
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getQuestAchievements(userID: String): Flowable<out List<QuestAchievement>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(User::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(User::class.java)
|
||||
.equalTo("id", userID)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }
|
||||
.map { it.first()?.questAchievements ?: emptyList() })
|
||||
}
|
||||
.map { it.first()?.questAchievements ?: emptyList() }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getTutorialSteps(): Flowable<List<TutorialStep>> = RxJavaBridge.toV3Flowable(realm.where(TutorialStep::class.java).findAll().asFlowable()
|
||||
.filter { it.isLoaded }.map { it })
|
||||
override fun getTutorialSteps(): Flowable<List<TutorialStep>> = RxJavaBridge.toV3Flowable(
|
||||
realm.where(TutorialStep::class.java).findAll().asFlowable()
|
||||
.filter { it.isLoaded }.map { it }
|
||||
)
|
||||
|
||||
override fun getUser(userID: String): Flowable<User> {
|
||||
if (realm.isClosed) return Flowable.empty()
|
||||
return RxJavaBridge.toV3Flowable(realm.where(User::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(User::class.java)
|
||||
.equalTo("id", userID)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { realmObject -> realmObject.isLoaded && realmObject.isValid && !realmObject.isEmpty() }
|
||||
.map { users -> users.first() })
|
||||
.map { users -> users.first() }
|
||||
)
|
||||
}
|
||||
|
||||
override fun saveUser(user: User, overrideExisting: Boolean) {
|
||||
if (realm.isClosed) return
|
||||
val oldUser = realm.where(User::class.java)
|
||||
.equalTo("id", user.id)
|
||||
.findFirst()
|
||||
.equalTo("id", user.id)
|
||||
.findFirst()
|
||||
if (oldUser != null && oldUser.isValid) {
|
||||
if (user.needsCron && !oldUser.needsCron) {
|
||||
if (user.lastCron?.before(oldUser.lastCron) == true) {
|
||||
|
|
@ -81,7 +90,6 @@ class RealmUserLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
|
|||
}
|
||||
}
|
||||
executeTransaction { realm1 -> realm1.insertOrUpdate(user) }
|
||||
|
||||
}
|
||||
|
||||
override fun saveMessages(messages: List<ChatMessage>) {
|
||||
|
|
@ -91,32 +99,38 @@ class RealmUserLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
|
|||
}
|
||||
|
||||
override fun getTeamPlans(userID: String): Flowable<out List<TeamPlan>> {
|
||||
return RxJavaBridge.toV3Flowable(realm.where(TeamPlan::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(TeamPlan::class.java)
|
||||
.equalTo("userID", userID)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getTeamPlan(teamID: String): Flowable<Group> {
|
||||
if (realm.isClosed) return Flowable.empty()
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Group::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Group::class.java)
|
||||
.equalTo("id", teamID)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { realmObject -> realmObject.isLoaded && realmObject.isValid && !realmObject.isEmpty() }
|
||||
.map { teams -> teams.first() })
|
||||
.map { teams -> teams.first() }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getSkills(user: User): Flowable<out List<Skill>> {
|
||||
val habitClass = if (user.preferences?.disableClasses == true) "none" else user.stats?.habitClass
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Skill::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Skill::class.java)
|
||||
.equalTo("habitClass", habitClass)
|
||||
.sort("lvl")
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
}
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getSpecialItems(user: User): Flowable<out List<Skill>> {
|
||||
val specialItems = user.items?.special
|
||||
|
|
@ -138,10 +152,12 @@ class RealmUserLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
|
|||
if (ownedItems.size == 0) {
|
||||
ownedItems.add("")
|
||||
}
|
||||
return RxJavaBridge.toV3Flowable(realm.where(Skill::class.java)
|
||||
return RxJavaBridge.toV3Flowable(
|
||||
realm.where(Skill::class.java)
|
||||
.`in`("key", ownedItems.toTypedArray())
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded })
|
||||
}
|
||||
.filter { it.isLoaded }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ package com.habitrpg.android.habitica.events
|
|||
/**
|
||||
* Created by Negue on 29.11.2015.
|
||||
*/
|
||||
class BoughtGemsEvent(var NewGemsToAdd: Int)
|
||||
class BoughtGemsEvent(var NewGemsToAdd: Int)
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@ package com.habitrpg.android.habitica.events
|
|||
|
||||
import com.habitrpg.android.habitica.models.shops.ShopItem
|
||||
|
||||
class GearPurchasedEvent(val item: ShopItem)
|
||||
class GearPurchasedEvent(val item: ShopItem)
|
||||
|
|
|
|||
|
|
@ -6,4 +6,4 @@ class ShareEvent {
|
|||
var identifier: String? = null
|
||||
var sharedMessage: String? = null
|
||||
var shareImage: Bitmap? = null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,4 +23,4 @@ class ShowSnackbarEvent {
|
|||
var rightIcon: Drawable? = null
|
||||
var rightTextColor = 0
|
||||
var rightText: String? = null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
package com.habitrpg.android.habitica.events
|
||||
|
||||
class UserSubscribedEvent
|
||||
class UserSubscribedEvent
|
||||
|
|
|
|||
|
|
@ -3,5 +3,4 @@ package com.habitrpg.android.habitica.events.commands
|
|||
import com.habitrpg.android.habitica.models.inventory.Food
|
||||
import com.habitrpg.android.habitica.models.inventory.Pet
|
||||
|
||||
class FeedCommand(val usingPet: Pet?, val usingFood: Food?) {
|
||||
}
|
||||
class FeedCommand(val usingPet: Pet?, val usingFood: Food?)
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ import com.habitrpg.android.habitica.R
|
|||
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
|
||||
|
||||
fun HabiticaAlertDialog.addOkButton(isPrimary: Boolean = true, listener: ((HabiticaAlertDialog, Int) -> Unit)? = null) {
|
||||
this.addButton(R.string.ok, isPrimary, false,true, listener)
|
||||
this.addButton(R.string.ok, isPrimary, false, true, listener)
|
||||
}
|
||||
|
||||
fun HabiticaAlertDialog.addCloseButton(isPrimary: Boolean = false, listener: ((DialogInterface, Int) -> Unit)? = null) {
|
||||
this.addButton(R.string.close, isPrimary, false,true, listener)
|
||||
this.addButton(R.string.close, isPrimary, false, true, listener)
|
||||
}
|
||||
|
||||
fun HabiticaAlertDialog.addCancelButton(isPrimary: Boolean = false, listener: ((DialogInterface, Int) -> Unit)? = null) {
|
||||
this.addButton(R.string.cancel, isPrimary, false,true, listener)
|
||||
}
|
||||
this.addButton(R.string.cancel, isPrimary, false, true, listener)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ fun Animal.getTranslatedType(c: Context?): String? {
|
|||
}
|
||||
|
||||
return when (type) {
|
||||
"drop" -> c.getString(R.string.standard)
|
||||
"quest" -> c.getString(R.string.quest)
|
||||
"wacky" -> c.getString(R.string.wacky)
|
||||
"drop" -> c.getString(R.string.standard)
|
||||
"quest" -> c.getString(R.string.quest)
|
||||
"wacky" -> c.getString(R.string.wacky)
|
||||
"special" -> c.getString(R.string.special)
|
||||
"premium" -> c.getString(R.string.magic_potion)
|
||||
else -> {
|
||||
type
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ import android.content.res.TypedArray
|
|||
import android.util.AttributeSet
|
||||
|
||||
fun AttributeSet.styledAttributes(context: Context?, style: IntArray): TypedArray? =
|
||||
context?.theme?.obtainStyledAttributes(this, style, 0, 0)
|
||||
context?.theme?.obtainStyledAttributes(this, style, 0, 0)
|
||||
|
|
|
|||
|
|
@ -9,5 +9,5 @@ import java.util.concurrent.TimeUnit
|
|||
|
||||
fun runDelayed(interval: Long, timeUnit: TimeUnit, function: () -> Unit) {
|
||||
Completable.complete().delay(interval, timeUnit)
|
||||
.subscribe(function)
|
||||
}
|
||||
.subscribe(function)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import android.graphics.Bitmap
|
|||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
|
||||
|
||||
fun Bitmap.asDrawable(resources: Resources): Drawable {
|
||||
return BitmapDrawable(resources, this)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import java.util.*
|
|||
val Context.layoutInflater: LayoutInflater
|
||||
get() = this.getSystemService(Service.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
|
||||
|
||||
fun Context.getThemeColor(colorRes: Int): Int {
|
||||
val value = TypedValue()
|
||||
theme.resolveAttribute(colorRes, value, true)
|
||||
|
|
@ -18,8 +17,10 @@ fun Context.getThemeColor(colorRes: Int): Int {
|
|||
}
|
||||
|
||||
fun Context.isUsingNightModeResources(): Boolean {
|
||||
return when (resources.configuration.uiMode and
|
||||
Configuration.UI_MODE_NIGHT_MASK) {
|
||||
return when (
|
||||
resources.configuration.uiMode and
|
||||
Configuration.UI_MODE_NIGHT_MASK
|
||||
) {
|
||||
Configuration.UI_MODE_NIGHT_YES -> true
|
||||
Configuration.UI_MODE_NIGHT_NO -> false
|
||||
Configuration.UI_MODE_NIGHT_UNDEFINED -> false
|
||||
|
|
@ -31,4 +32,4 @@ fun Context.forceLocale(locale: Locale): Context {
|
|||
val config = Configuration(resources.configuration)
|
||||
config.setLocale(locale)
|
||||
return createConfigurationContext(config)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,4 +114,4 @@ fun Long.getShortRemainingString(): String {
|
|||
str = "$str ${diffSeconds}s"
|
||||
}
|
||||
return str
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ import kotlin.math.roundToInt
|
|||
|
||||
fun Double.round(decimals: Int): Double {
|
||||
return (this * 10.0.pow(decimals.toDouble())).roundToInt() / 10.0.pow(decimals.toDouble())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,14 +6,12 @@ import android.graphics.drawable.Drawable
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.DrawableCompat
|
||||
|
||||
|
||||
public fun Drawable.setTintWith(context: Context, colorResource: Int, tintMode: PorterDuff.Mode = PorterDuff.Mode.MULTIPLY) {
|
||||
DrawableCompat.setTintMode(this, tintMode)
|
||||
DrawableCompat.setTint(this, ContextCompat.getColor(context, colorResource))
|
||||
|
||||
}
|
||||
|
||||
public fun Drawable.setTintWith(color: Int, tintMode: PorterDuff.Mode = PorterDuff.Mode.MULTIPLY) {
|
||||
DrawableCompat.setTint(this, color)
|
||||
DrawableCompat.setTintMode(this, tintMode)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,4 +12,4 @@ fun <T> Flowable<T>.subscribeWithErrorHandler(function: Consumer<T>): Disposable
|
|||
fun <T> Flowable<T?>.skipNull(): Flowable<T> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return skipWhile { it == null } as? Flowable<T> ?: Flowable.empty()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,5 +5,4 @@ import android.content.Context
|
|||
fun Int.dpToPx(context: Context?): Int {
|
||||
val displayMetrics = context?.resources?.displayMetrics
|
||||
return ((this * (displayMetrics?.density ?: 1.0f)) + 0.5).toInt()
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,9 @@ package com.habitrpg.android.habitica.extensions
|
|||
|
||||
import com.google.gson.JsonObject
|
||||
|
||||
|
||||
fun JsonObject?.getAsString(key: String): String {
|
||||
if (this?.get(key)?.isJsonPrimitive == true) {
|
||||
return this.get(key)?.asString ?: ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ package com.habitrpg.android.habitica.extensions
|
|||
data class Optional<T>(val value: T?) {
|
||||
val isEmpty = value == null
|
||||
}
|
||||
fun <T> T?.asOptional() = Optional(this)
|
||||
fun <T> T?.asOptional() = Optional(this)
|
||||
|
|
|
|||
|
|
@ -5,47 +5,46 @@ import io.reactivex.rxjava3.core.Maybe
|
|||
import io.reactivex.rxjava3.core.Observable
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
|
||||
|
||||
fun <S, T : Optional<S>> Flowable<T>.filterOptionalDoOnEmpty(function: () -> Unit): Flowable<S> {
|
||||
return this.doOnNext { if (it.isEmpty) function() }
|
||||
.filter { !it.isEmpty }
|
||||
.map { it.value }
|
||||
.filter { !it.isEmpty }
|
||||
.map { it.value }
|
||||
}
|
||||
|
||||
fun <S, T : Optional<S>> Flowable<T>.filterMapEmpty(): Flowable<S> {
|
||||
return this.filter { !it.isEmpty }
|
||||
.map { it.value }
|
||||
.map { it.value }
|
||||
}
|
||||
|
||||
fun <S, T : Optional<S>> Observable<T>.filterOptionalDoOnEmpty(function: () -> Unit): Observable<S> {
|
||||
return this.doOnNext { if (it.isEmpty) function() }
|
||||
.filter { !it.isEmpty }
|
||||
.map { it.value }
|
||||
.filter { !it.isEmpty }
|
||||
.map { it.value }
|
||||
}
|
||||
|
||||
fun <S, T : Optional<S>> Observable<T>.filterMapEmpty(): Observable<S> {
|
||||
return this.filter { !it.isEmpty }
|
||||
.map { it.value }
|
||||
.map { it.value }
|
||||
}
|
||||
|
||||
fun <S, T : Optional<S>> Single<T>.filterOptionalDoOnEmpty(function: () -> Unit): Maybe<S> {
|
||||
return this.doOnSuccess { if (it.isEmpty) function() }
|
||||
.filter { !it.isEmpty }
|
||||
.map { it.value }
|
||||
.filter { !it.isEmpty }
|
||||
.map { it.value }
|
||||
}
|
||||
|
||||
fun <S, T : Optional<S>> Single<T>.filterMapEmpty(): Maybe<S> {
|
||||
return this.filter { !it.isEmpty }
|
||||
.map { it.value }
|
||||
.map { it.value }
|
||||
}
|
||||
|
||||
fun <S, T : Optional<S>> Maybe<T>.filterOptionalDoOnEmpty(function: () -> Unit): Maybe<S> {
|
||||
return this.doOnSuccess { if (it.isEmpty) function() }
|
||||
.filter { !it.isEmpty }
|
||||
.map { it.value }
|
||||
.filter { !it.isEmpty }
|
||||
.map { it.value }
|
||||
}
|
||||
|
||||
fun <S, T : Optional<S>> Maybe<T>.filterMapEmpty(): Maybe<S> {
|
||||
return this.filter { !it.isEmpty }
|
||||
.map { it.value }
|
||||
}
|
||||
.map { it.value }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ import android.view.View
|
|||
import android.widget.TextView
|
||||
|
||||
fun TextView.handleUrlClicks(onClicked: ((String) -> Unit)? = null) {
|
||||
//create span builder and replaces current text with it
|
||||
// create span builder and replaces current text with it
|
||||
text = SpannableStringBuilder.valueOf(text).apply {
|
||||
//search for all URL spans and replace all spans with our own clickable spans
|
||||
// search for all URL spans and replace all spans with our own clickable spans
|
||||
getSpans(0, length, URLSpan::class.java).forEach {
|
||||
//add new clickable span at the same position
|
||||
// add new clickable span at the same position
|
||||
setSpan(
|
||||
object : ClickableSpan() {
|
||||
override fun onClick(widget: View) {
|
||||
|
|
@ -24,10 +24,10 @@ fun TextView.handleUrlClicks(onClicked: ((String) -> Unit)? = null) {
|
|||
getSpanEnd(it),
|
||||
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
//remove old URLSpan
|
||||
// remove old URLSpan
|
||||
removeSpan(it)
|
||||
}
|
||||
}
|
||||
//make sure movement method is set
|
||||
// make sure movement method is set
|
||||
movementMethod = LinkMovementMethod.getInstance()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,4 +31,4 @@ class AfterChangeTextWatcher(private var function: (Editable?) -> Unit) : TextWa
|
|||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { /* no-on */ }
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { /* no-on */ }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,10 @@ import android.content.Context
|
|||
import android.view.View
|
||||
import android.view.ViewTreeObserver
|
||||
|
||||
|
||||
fun View.setScaledPadding(context: Context?, left: Int, top: Int, right: Int, bottom: Int) {
|
||||
this.setPadding(left.dpToPx(context), top.dpToPx(context), right.dpToPx(context), bottom.dpToPx(context))
|
||||
}
|
||||
|
||||
|
||||
inline fun View.waitForLayout(crossinline f: View.() -> Unit) = with(viewTreeObserver) {
|
||||
addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
|
||||
override fun onGlobalLayout() {
|
||||
|
|
@ -19,7 +17,7 @@ inline fun View.waitForLayout(crossinline f: View.() -> Unit) = with(viewTreeObs
|
|||
})
|
||||
}
|
||||
|
||||
inline fun View.afterMeasured(crossinline f: View.() -> Unit) {
|
||||
inline fun View.afterMeasured(crossinline f: View.() -> Unit) {
|
||||
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
|
||||
override fun onGlobalLayout() {
|
||||
if (measuredWidth > 0 && measuredHeight > 0) {
|
||||
|
|
@ -28,4 +26,4 @@ inline fun View.afterMeasured(crossinline f: View.() -> Unit) {
|
|||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
|
||||
fun ViewGroup.inflate(layoutId: Int, attachToRoot: Boolean = false): View =
|
||||
context.layoutInflater.inflate(layoutId, this, attachToRoot)
|
||||
context.layoutInflater.inflate(layoutId, this, attachToRoot)
|
||||
|
|
|
|||
|
|
@ -41,4 +41,4 @@ object AmplitudeManager {
|
|||
additionalData["page"] = page
|
||||
sendEvent("navigated", EVENT_CATEGORY_NAVIGATION, EVENT_HITTYPE_PAGEVIEW, additionalData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,12 @@ class AppConfigManager(contentRepository: ContentRepository?) {
|
|||
private var worldState: WorldState? = null
|
||||
|
||||
init {
|
||||
contentRepository?.getWorldState()?.subscribe( {
|
||||
worldState = it
|
||||
}, RxErrorHandler.handleEmptyError())
|
||||
contentRepository?.getWorldState()?.subscribe(
|
||||
{
|
||||
worldState = it
|
||||
},
|
||||
RxErrorHandler.handleEmptyError()
|
||||
)
|
||||
}
|
||||
|
||||
private val remoteConfig = FirebaseRemoteConfig.getInstance()
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class AprilFoolsHandler {
|
|||
if (endDate != null) {
|
||||
this.eventEnd = endDate
|
||||
}
|
||||
when(name) {
|
||||
when (name) {
|
||||
"invert" -> invertFools()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,16 +171,25 @@ object DeviceName {
|
|||
if (codename != null && codename == "HWBND-H" || model != null && (model == "BND-L21" || model == "BND-L24" || model == "BND-L31")) {
|
||||
return "Honor 7X"
|
||||
}
|
||||
if (codename != null && codename == "HWBKL" || model != null && (model == "BKL-L04" || model ==
|
||||
"BKL-L09")) {
|
||||
if (codename != null && codename == "HWBKL" || model != null && (
|
||||
model == "BKL-L04" || model ==
|
||||
"BKL-L09"
|
||||
)
|
||||
) {
|
||||
return "Honor View 10"
|
||||
}
|
||||
if (codename != null && codename == "HWALP" || model != null && (model == "ALP-AL00" || model ==
|
||||
"ALP-L09" || model == "ALP-L29" || model == "ALP-TL00")) {
|
||||
if (codename != null && codename == "HWALP" || model != null && (
|
||||
model == "ALP-AL00" || model ==
|
||||
"ALP-L09" || model == "ALP-L29" || model == "ALP-TL00"
|
||||
)
|
||||
) {
|
||||
return "Mate 10"
|
||||
}
|
||||
if (codename != null && codename == "HWMHA" || model != null && (model == "MHA-AL00" || model ==
|
||||
"MHA-L09" || model == "MHA-L29" || model == "MHA-TL00")) {
|
||||
if (codename != null && codename == "HWMHA" || model != null && (
|
||||
model == "MHA-AL00" || model ==
|
||||
"MHA-L09" || model == "MHA-L29" || model == "MHA-TL00"
|
||||
)
|
||||
) {
|
||||
return "Mate 9"
|
||||
}
|
||||
if (codename != null && codename == "angler") {
|
||||
|
|
@ -188,11 +197,14 @@ object DeviceName {
|
|||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
// LGE
|
||||
if (codename != null && codename == "h1" || model != null && (model == "LG-F700K" || model ==
|
||||
"LG-F700L" || model == "LG-F700S" || model == "LG-H820" || model == "LG-H820PR" || model ==
|
||||
"LG-H830" || model == "LG-H831" || model == "LG-H850" || model == "LG-H858" || model ==
|
||||
"LG-H860" || model == "LG-H868" || model == "LGAS992" || model == "LGLS992" || model ==
|
||||
"LGUS992" || model == "RS988" || model == "VS987")) {
|
||||
if (codename != null && codename == "h1" || model != null && (
|
||||
model == "LG-F700K" || model ==
|
||||
"LG-F700L" || model == "LG-F700S" || model == "LG-H820" || model == "LG-H820PR" || model ==
|
||||
"LG-H830" || model == "LG-H831" || model == "LG-H850" || model == "LG-H858" || model ==
|
||||
"LG-H860" || model == "LG-H868" || model == "LGAS992" || model == "LGLS992" || model ==
|
||||
"LGUS992" || model == "RS988" || model == "VS987"
|
||||
)
|
||||
) {
|
||||
return "LG G5"
|
||||
}
|
||||
if (codename != null && codename == "lucye" || model != null && (model == "LG-AS993" || model == "LG-H870" || model == "LG-H870AR" || model == "LG-H870DS" || model == "LG-H870I" || model == "LG-H870S" || model == "LG-H871" || model == "LG-H871S" || model == "LG-H872" || model == "LG-H872PR" || model == "LG-H873" || model == "LG-LS993" || model == "LGM-G600K" || model == "LGM-G600L" || model == "LGM-G600S" || model == "LGUS997" || model == "VS988")) {
|
||||
|
|
@ -212,8 +224,11 @@ object DeviceName {
|
|||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
// Motorola
|
||||
if (codename != null && codename == "griffin" || model != null && (model == "XT1650" || model ==
|
||||
"XT1650-05")) {
|
||||
if (codename != null && codename == "griffin" || model != null && (
|
||||
model == "XT1650" || model ==
|
||||
"XT1650-05"
|
||||
)
|
||||
) {
|
||||
return "Moto Z"
|
||||
}
|
||||
if (codename != null && codename == "shamu") {
|
||||
|
|
@ -232,15 +247,21 @@ object DeviceName {
|
|||
if (codename != null && codename == "OnePlus6" || model != null && model == "ONEPLUS A6003") {
|
||||
return "OnePlus 6"
|
||||
}
|
||||
if (codename != null && (codename == "OnePlus6T" || codename == "OnePlus6TSingle") || (model != null
|
||||
&& model == "ONEPLUS A6013")) {
|
||||
if (codename != null && (codename == "OnePlus6T" || codename == "OnePlus6TSingle") || (
|
||||
model != null &&
|
||||
model == "ONEPLUS A6013"
|
||||
)
|
||||
) {
|
||||
return "OnePlus 6T"
|
||||
}
|
||||
if (codename != null && codename == "OnePlus7" || model != null && model == "GM1905") {
|
||||
return "OnePlus 7"
|
||||
}
|
||||
if (codename != null && (codename == "OnePlus7Pro" || codename == "OnePlus7ProTMO") || (model != null
|
||||
&& (model == "GM1915" || model == "GM1917"))) {
|
||||
if (codename != null && (codename == "OnePlus7Pro" || codename == "OnePlus7ProTMO") || (
|
||||
model != null &&
|
||||
(model == "GM1915" || model == "GM1917")
|
||||
)
|
||||
) {
|
||||
return "OnePlus 7 Pro"
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
@ -266,8 +287,11 @@ object DeviceName {
|
|||
if (codename != null && (codename == "SC-04L" || codename == "SCV42" || codename == "beyond2" || codename == "beyond2q") || model != null && (model == "SC-04L" || model == "SCV42" || model == "SM-G9750" || model == "SM-G9758" || model == "SM-G975F" || model == "SM-G975N" || model == "SM-G975U" || model == "SM-G975U1" || model == "SM-G975W")) {
|
||||
return "Galaxy S10+"
|
||||
}
|
||||
if (codename != null && (codename == "beyond0" || codename == "beyond0q") || (model != null
|
||||
&& (model == "SM-G9700" || model == "SM-G9708" || model == "SM-G970F" || model == "SM-G970N" || model == "SM-G970U" || model == "SM-G970U1" || model == "SM-G970W"))) {
|
||||
if (codename != null && (codename == "beyond0" || codename == "beyond0q") || (
|
||||
model != null &&
|
||||
(model == "SM-G9700" || model == "SM-G9708" || model == "SM-G970F" || model == "SM-G970N" || model == "SM-G970U" || model == "SM-G970U1" || model == "SM-G970W")
|
||||
)
|
||||
) {
|
||||
return "Galaxy S10e"
|
||||
}
|
||||
if (codename != null && (codename == "SC-04F" || codename == "SCL23" || codename == "k3g" || codename == "klte" || codename == "klteMetroPCS" || codename == "klteacg" || codename == "klteaio" || codename == "klteatt" || codename == "kltecan" || codename == "klteduoszn" || codename == "kltektt" || codename == "kltelgt" || codename == "kltelra" || codename == "klteskt" || codename == "kltespr" || codename == "kltetfnvzw" || codename == "kltetmo" || codename == "klteusc" || codename == "kltevzw" || codename == "kwifi" || codename == "lentisltektt" || codename == "lentisltelgt" || codename == "lentislteskt") || model != null && (model == "SAMSUNG-SM-G900A" || model == "SAMSUNG-SM-G900AZ" || model == "SC-04F" || model == "SCL23" || model == "SM-G9006W" || model == "SM-G9008W" || model == "SM-G9009W" || model == "SM-G900F" || model == "SM-G900FQ" || model == "SM-G900H" || model == "SM-G900I" || model == "SM-G900K" || model == "SM-G900L" || model == "SM-G900M" || model == "SM-G900MD" || model == "SM-G900P" || model == "SM-G900R4" || model == "SM-G900R6" || model == "SM-G900R7" || model == "SM-G900S" || model == "SM-G900T" || model == "SM-G900T1" || model == "SM-G900T3" || model == "SM-G900T4" || model == "SM-G900V" || model == "SM-G900W8" || model == "SM-G900X" || model == "SM-G906K" || model == "SM-G906L" || model == "SM-G906S" || model == "SM-S903VL")) {
|
||||
|
|
@ -285,13 +309,16 @@ object DeviceName {
|
|||
if (codename != null && (codename == "zenlte" || codename == "zenlteatt" || codename == "zenltebmc" || codename == "zenltechn" || codename == "zenltektt" || codename == "zenltekx" || codename == "zenltelgt" || codename == "zenlteskt" || codename == "zenltespr" || codename == "zenltetmo" || codename == "zenlteusc" || codename == "zenltevzw") || model != null && (model == "SAMSUNG-SM-G928A" || model == "SM-G9280" || model == "SM-G9287C" || model == "SM-G928C" || model == "SM-G928G" || model == "SM-G928I" || model == "SM-G928K" || model == "SM-G928L" || model == "SM-G928N0" || model == "SM-G928P" || model == "SM-G928R4" || model == "SM-G928S" || model == "SM-G928T" || model == "SM-G928V" || model == "SM-G928W8" || model == "SM-G928X")) {
|
||||
return "Galaxy S6 Edge+"
|
||||
}
|
||||
if (codename != null && (codename == "herolte" || codename == "heroltebmc" || codename ==
|
||||
"heroltektt" || codename == "heroltelgt" || codename == "herolteskt" || codename ==
|
||||
"heroqlteacg" || codename == "heroqlteaio" || codename == "heroqlteatt" || codename ==
|
||||
"heroqltecctvzw" || codename == "heroqltechn" || codename == "heroqltelra" || codename ==
|
||||
"heroqltemtr" || codename == "heroqltespr" || codename == "heroqltetfnvzw" || codename ==
|
||||
"heroqltetmo" || codename == "heroqlteue" || codename == "heroqlteusc" || codename ==
|
||||
"heroqltevzw") || model != null && (model == "SAMSUNG-SM-G930A" || model == "SAMSUNG-SM-G930AZ" || model == "SM-G9300" || model == "SM-G9308" || model == "SM-G930F" || model == "SM-G930K" || model == "SM-G930L" || model == "SM-G930P" || model == "SM-G930R4" || model == "SM-G930R6" || model == "SM-G930R7" || model == "SM-G930S" || model == "SM-G930T" || model == "SM-G930T1" || model == "SM-G930U" || model == "SM-G930V" || model == "SM-G930VC" || model == "SM-G930VL" || model == "SM-G930W8" || model == "SM-G930X")) {
|
||||
if (codename != null && (
|
||||
codename == "herolte" || codename == "heroltebmc" || codename ==
|
||||
"heroltektt" || codename == "heroltelgt" || codename == "herolteskt" || codename ==
|
||||
"heroqlteacg" || codename == "heroqlteaio" || codename == "heroqlteatt" || codename ==
|
||||
"heroqltecctvzw" || codename == "heroqltechn" || codename == "heroqltelra" || codename ==
|
||||
"heroqltemtr" || codename == "heroqltespr" || codename == "heroqltetfnvzw" || codename ==
|
||||
"heroqltetmo" || codename == "heroqlteue" || codename == "heroqlteusc" || codename ==
|
||||
"heroqltevzw"
|
||||
) || model != null && (model == "SAMSUNG-SM-G930A" || model == "SAMSUNG-SM-G930AZ" || model == "SM-G9300" || model == "SM-G9308" || model == "SM-G930F" || model == "SM-G930K" || model == "SM-G930L" || model == "SM-G930P" || model == "SM-G930R4" || model == "SM-G930R6" || model == "SM-G930R7" || model == "SM-G930S" || model == "SM-G930T" || model == "SM-G930T1" || model == "SM-G930U" || model == "SM-G930V" || model == "SM-G930VC" || model == "SM-G930VL" || model == "SM-G930W8" || model == "SM-G930X")
|
||||
) {
|
||||
return "Galaxy S7"
|
||||
}
|
||||
if (codename != null && (codename == "SC-02H" || codename == "SCV33" || codename == "hero2lte" || codename == "hero2ltebmc" || codename == "hero2ltektt" || codename == "hero2lteskt" || codename == "hero2qlteatt" || codename == "hero2qltecctvzw" || codename == "hero2qltespr" || codename == "hero2qltetmo" || codename == "hero2qlteusc" || codename == "hero2qltevzw") || model != null && (model == "SAMSUNG-SM-G935A" || model == "SC-02H" || model == "SCV33" || model == "SM-G935K" || model == "SM-G935P" || model == "SM-G935R4" || model == "SM-G935S" || model == "SM-G935T" || model == "SM-G935V" || model == "SM-G935VC" || model == "SM-G935W8" || model == "SM-G935X")) {
|
||||
|
|
@ -405,8 +432,9 @@ object DeviceName {
|
|||
while (i < len) {
|
||||
val json = jsonArray.getJSONObject(i)
|
||||
val info = DeviceInfo(json)
|
||||
if (codename.equals(info.codename, ignoreCase = true) && model == null
|
||||
|| codename.equals(info.codename, ignoreCase = true) && model.equals(info.model, ignoreCase = true)) {
|
||||
if (codename.equals(info.codename, ignoreCase = true) && model == null ||
|
||||
codename.equals(info.codename, ignoreCase = true) && model.equals(info.model, ignoreCase = true)
|
||||
) {
|
||||
// Save to SharedPreferences so we don't need to make another request.
|
||||
val editor = prefs.edit()
|
||||
editor.putString(key, json.toString())
|
||||
|
|
@ -570,4 +598,4 @@ object DeviceName {
|
|||
marketName
|
||||
} else model?.capitalize(Locale.getDefault())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.habitrpg.android.habitica.helpers
|
|||
|
||||
import android.view.HapticFeedbackConstants
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
|
||||
class HapticFeedbackManager {
|
||||
companion object {
|
||||
|
|
@ -14,4 +13,4 @@ class HapticFeedbackManager {
|
|||
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@ object HealthFormatter {
|
|||
|
||||
@JvmStatic
|
||||
fun format(input: Double) =
|
||||
if (input < 1 && input > 0) {
|
||||
ceil(input * 10) / 10
|
||||
} else {
|
||||
floor(input)
|
||||
}
|
||||
if (input < 1 && input > 0) {
|
||||
ceil(input * 10) / 10
|
||||
} else {
|
||||
floor(input)
|
||||
}
|
||||
|
||||
fun formatToString(input: Int, locale: Locale = getDefaultLocale()) = formatToString(input.toDouble(), locale)
|
||||
|
||||
|
|
@ -32,4 +32,4 @@ object HealthFormatter {
|
|||
} else {
|
||||
Locale.getDefault()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,11 +42,9 @@ constructor(ctx: Context, var sharedPreferences: SharedPreferences, var keyStore
|
|||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Throws(NoSuchProviderException::class, NoSuchAlgorithmException::class, InvalidAlgorithmParameterException::class, KeyStoreException::class, CertificateException::class, IOException::class)
|
||||
private fun generateEncryptKey(ctx: Context) {
|
||||
keyStore.load(null)
|
||||
|
|
@ -55,12 +53,15 @@ constructor(ctx: Context, var sharedPreferences: SharedPreferences, var keyStore
|
|||
if (!keyStore.containsAlias(KEY_ALIAS)) {
|
||||
val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, AndroidKeyStore)
|
||||
keyGenerator.init(
|
||||
KeyGenParameterSpec.Builder(KEY_ALIAS,
|
||||
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
|
||||
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
|
||||
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
|
||||
.setRandomizedEncryptionRequired(false)
|
||||
.build())
|
||||
KeyGenParameterSpec.Builder(
|
||||
KEY_ALIAS,
|
||||
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
|
||||
)
|
||||
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
|
||||
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
|
||||
.setRandomizedEncryptionRequired(false)
|
||||
.build()
|
||||
)
|
||||
keyGenerator.generateKey()
|
||||
}
|
||||
} else {
|
||||
|
|
@ -70,12 +71,12 @@ constructor(ctx: Context, var sharedPreferences: SharedPreferences, var keyStore
|
|||
val end = Calendar.getInstance()
|
||||
end.add(Calendar.YEAR, 30)
|
||||
val spec = KeyPairGeneratorSpec.Builder(ctx)
|
||||
.setAlias(KEY_ALIAS)
|
||||
.setSubject(X500Principal("CN=$KEY_ALIAS"))
|
||||
.setSerialNumber(BigInteger.TEN)
|
||||
.setStartDate(start.time)
|
||||
.setEndDate(end.time)
|
||||
.build()
|
||||
.setAlias(KEY_ALIAS)
|
||||
.setSubject(X500Principal("CN=$KEY_ALIAS"))
|
||||
.setSerialNumber(BigInteger.TEN)
|
||||
.setStartDate(start.time)
|
||||
.setEndDate(end.time)
|
||||
.build()
|
||||
val kpg = KeyPairGenerator.getInstance("RSA", AndroidKeyStore)
|
||||
kpg.initialize(spec)
|
||||
kpg.generateKeyPair()
|
||||
|
|
@ -104,7 +105,8 @@ constructor(ctx: Context, var sharedPreferences: SharedPreferences, var keyStore
|
|||
val output = Cipher.getInstance(RSA_MODE, "AndroidOpenSSL")
|
||||
output.init(Cipher.DECRYPT_MODE, privateKeyEntry?.privateKey)
|
||||
val cipherInputStream = CipherInputStream(
|
||||
ByteArrayInputStream(encrypted), output)
|
||||
ByteArrayInputStream(encrypted), output
|
||||
)
|
||||
return cipherInputStream.readBytes()
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +125,6 @@ constructor(ctx: Context, var sharedPreferences: SharedPreferences, var keyStore
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Throws(Exception::class)
|
||||
private fun getSecretKey(): Key {
|
||||
val enryptedKeyB64 = sharedPreferences.getString(ENCRYPTED_KEY, null)
|
||||
|
|
@ -152,13 +153,11 @@ constructor(ctx: Context, var sharedPreferences: SharedPreferences, var keyStore
|
|||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
val encodedBytes = c.doFinal(input.toByteArray(charset("UTF-8")))
|
||||
return Base64.encodeToString(encodedBytes, Base64.DEFAULT)
|
||||
}
|
||||
|
||||
|
||||
@Throws(NoSuchAlgorithmException::class, NoSuchPaddingException::class, NoSuchProviderException::class, BadPaddingException::class, IllegalBlockSizeException::class, UnsupportedEncodingException::class)
|
||||
fun decrypt(encrypted: String): String? {
|
||||
val c: Cipher
|
||||
|
|
@ -178,7 +177,6 @@ constructor(ctx: Context, var sharedPreferences: SharedPreferences, var keyStore
|
|||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return try {
|
||||
|
|
@ -237,9 +235,8 @@ constructor(ctx: Context, var sharedPreferences: SharedPreferences, var keyStore
|
|||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
return keyHelper
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import android.net.Uri
|
|||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavDeepLink
|
||||
import androidx.navigation.NavDeepLinkRequest
|
||||
import androidx.navigation.NavDirections
|
||||
import java.lang.ref.WeakReference
|
||||
|
|
@ -18,7 +17,7 @@ object MainNavigationController {
|
|||
private var controllerReference: WeakReference<NavController>? = null
|
||||
|
||||
private val navController: NavController?
|
||||
get() { return controllerReference?.get() }
|
||||
get() { return controllerReference?.get() }
|
||||
|
||||
fun setup(navController: NavController) {
|
||||
this.controllerReference = WeakReference(navController)
|
||||
|
|
@ -41,7 +40,7 @@ object MainNavigationController {
|
|||
if (abs((lastNavigation?.time ?: 0) - Date().time) > 500) {
|
||||
lastNavigation = Date()
|
||||
try {
|
||||
navController?.navigate(directions)
|
||||
navController?.navigate(directions)
|
||||
} catch (_: IllegalArgumentException) {}
|
||||
}
|
||||
}
|
||||
|
|
@ -66,4 +65,4 @@ object MainNavigationController {
|
|||
fun handle(deeplink: Intent) {
|
||||
navController?.handleDeepLink(deeplink)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import android.content.Intent
|
|||
import androidx.core.os.bundleOf
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -79,4 +78,4 @@ class NotificationOpenHandler {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import org.greenrobot.eventbus.EventBus
|
|||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class NotificationsManager (private val context: Context) {
|
||||
class NotificationsManager(private val context: Context) {
|
||||
private val seenNotifications: MutableMap<String, Boolean>
|
||||
private var apiClient: ApiClient? = null
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ class NotificationsManager (private val context: Context) {
|
|||
|
||||
fun getNotifications(): Flowable<List<Notification>> {
|
||||
return this.notifications.startWithArray(emptyList())
|
||||
.toFlowable(BackpressureStrategy.LATEST)
|
||||
.toFlowable(BackpressureStrategy.LATEST)
|
||||
}
|
||||
|
||||
fun getNotification(id: String): Notification? {
|
||||
|
|
@ -59,58 +59,60 @@ class NotificationsManager (private val context: Context) {
|
|||
}
|
||||
lastNotificationHandling = now
|
||||
notifications
|
||||
.filter { !this.seenNotifications.containsKey(it.id) }
|
||||
.map {
|
||||
val notificationDisplayed = when (it.type) {
|
||||
Notification.Type.LOGIN_INCENTIVE.type -> displayLoginIncentiveNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_PARTY_UP.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_PARTY_ON.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_BEAST_MASTER.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_MOUNT_MASTER.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_TRIAD_BINGO.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_GUILD_JOINED.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_CHALLENGE_JOINED.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_INVITED_FRIEND.type -> displayAchievementNotification(it)
|
||||
Notification.Type.WON_CHALLENGE.type -> displayWonChallengeNotificaiton(it)
|
||||
.filter { !this.seenNotifications.containsKey(it.id) }
|
||||
.map {
|
||||
val notificationDisplayed = when (it.type) {
|
||||
Notification.Type.LOGIN_INCENTIVE.type -> displayLoginIncentiveNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_PARTY_UP.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_PARTY_ON.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_BEAST_MASTER.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_MOUNT_MASTER.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_TRIAD_BINGO.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_GUILD_JOINED.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_CHALLENGE_JOINED.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_INVITED_FRIEND.type -> displayAchievementNotification(it)
|
||||
Notification.Type.WON_CHALLENGE.type -> displayWonChallengeNotificaiton(it)
|
||||
|
||||
Notification.Type.ACHIEVEMENT_ALL_YOUR_BASE.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_BACK_TO_BASICS.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_JUST_ADD_WATER.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_LOST_MASTERCLASSER.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_MIND_OVER_MATTER.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_DUST_DEVIL.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_ARID_AUTHORITY.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_MONSTER_MAGUS.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_UNDEAD_UNDERTAKER.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_PRIMED_FOR_PAINTING.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_PEARLY_PRO.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_TICKLED_PINK.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_ROSY_OUTLOOK.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_BUG_BONANZA.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_BARE_NECESSITIES.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_FRESHWATER_FRIENDS.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_GOOD_AS_GOLD.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_ALL_THAT_GLITTERS.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_GOOD_AS_GOLD.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_BONE_COLLECTOR.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_SKELETON_CREW.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_SEEING_RED.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_RED_LETTER_DAY.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_ALL_YOUR_BASE.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_BACK_TO_BASICS.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_JUST_ADD_WATER.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_LOST_MASTERCLASSER.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_MIND_OVER_MATTER.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_DUST_DEVIL.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_ARID_AUTHORITY.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_MONSTER_MAGUS.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_UNDEAD_UNDERTAKER.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_PRIMED_FOR_PAINTING.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_PEARLY_PRO.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_TICKLED_PINK.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_ROSY_OUTLOOK.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_BUG_BONANZA.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_BARE_NECESSITIES.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_FRESHWATER_FRIENDS.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_GOOD_AS_GOLD.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_ALL_THAT_GLITTERS.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_GOOD_AS_GOLD.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_BONE_COLLECTOR.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_SKELETON_CREW.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_SEEING_RED.type -> displayAchievementNotification(it)
|
||||
Notification.Type.ACHIEVEMENT_RED_LETTER_DAY.type -> displayAchievementNotification(it)
|
||||
|
||||
Notification.Type.ACHIEVEMENT_GENERIC.type -> displayAchievementNotification(it, notifications.find { notif ->
|
||||
Notification.Type.ACHIEVEMENT_GENERIC.type -> displayAchievementNotification(
|
||||
it,
|
||||
notifications.find { notif ->
|
||||
notif.type == Notification.Type.ACHIEVEMENT_ONBOARDING_COMPLETE.type
|
||||
} != null)
|
||||
Notification.Type.ACHIEVEMENT_ONBOARDING_COMPLETE.type -> displayAchievementNotification(it)
|
||||
Notification.Type.FIRST_DROP.type -> displayFirstDropNotification(it)
|
||||
else -> false
|
||||
}
|
||||
|
||||
if (notificationDisplayed == true) {
|
||||
this.seenNotifications[it.id] = true
|
||||
}
|
||||
|
||||
} != null
|
||||
)
|
||||
Notification.Type.ACHIEVEMENT_ONBOARDING_COMPLETE.type -> displayAchievementNotification(it)
|
||||
Notification.Type.FIRST_DROP.type -> displayFirstDropNotification(it)
|
||||
else -> false
|
||||
}
|
||||
|
||||
if (notificationDisplayed == true) {
|
||||
this.seenNotifications[it.id] = true
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -139,7 +141,7 @@ class NotificationsManager (private val context: Context) {
|
|||
EventBus.getDefault().post(event)
|
||||
if (apiClient != null) {
|
||||
apiClient?.readNotification(notification.id)
|
||||
?.subscribe({}, RxErrorHandler.handleEmptyError())
|
||||
?.subscribe({}, RxErrorHandler.handleEmptyError())
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
|
@ -154,10 +156,13 @@ class NotificationsManager (private val context: Context) {
|
|||
200
|
||||
}
|
||||
val sub = Completable.complete()
|
||||
.delay(delay, TimeUnit.MILLISECONDS)
|
||||
.subscribe({
|
||||
.delay(delay, TimeUnit.MILLISECONDS)
|
||||
.subscribe(
|
||||
{
|
||||
EventBus.getDefault().post(ShowAchievementDialog(achievement, notification.id, data?.message, data?.modalText, isLastOnboardingAchievement))
|
||||
}, RxErrorHandler.handleEmptyError())
|
||||
},
|
||||
RxErrorHandler.handleEmptyError()
|
||||
)
|
||||
logOnboardingEvents(achievement)
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package com.habitrpg.android.habitica.helpers
|
||||
|
||||
import android.content.Context
|
||||
|
||||
import com.habitrpg.android.habitica.R
|
||||
|
||||
import java.math.RoundingMode
|
||||
import java.text.DecimalFormat
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ class PurchaseHandler(activity: Activity, val analyticsManager: AnalyticsManager
|
|||
getSKU(ProductTypes.IN_APP, identifier, onSuccess)
|
||||
}
|
||||
|
||||
|
||||
private fun getSKUs(type: String, identifiers: List<String>, onSuccess: ((List<Sku>) -> Unit)) {
|
||||
getProduct(type, identifiers) {
|
||||
onSuccess(it.skus)
|
||||
|
|
@ -73,19 +72,25 @@ class PurchaseHandler(activity: Activity, val analyticsManager: AnalyticsManager
|
|||
}
|
||||
|
||||
private fun getProduct(type: String, identifiers: List<String>, onSuccess: ((Inventory.Product) -> Unit)) {
|
||||
loadInventory(type, identifiers, Inventory.Callback { products ->
|
||||
val purchases = products.get(type)
|
||||
if (!purchases.supported) return@Callback
|
||||
onSuccess(purchases)
|
||||
})
|
||||
loadInventory(
|
||||
type, identifiers,
|
||||
Inventory.Callback { products ->
|
||||
val purchases = products.get(type)
|
||||
if (!purchases.supported) return@Callback
|
||||
onSuccess(purchases)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun getSKU(type: String, identifier: String, onSuccess: ((Sku) -> Unit)) {
|
||||
loadInventory(type, listOf(identifier), Inventory.Callback { products ->
|
||||
val purchases = products.get(type)
|
||||
if (!purchases.supported) return@Callback
|
||||
purchases.skus.firstOrNull()?.let { onSuccess(it) }
|
||||
})
|
||||
loadInventory(
|
||||
type, listOf(identifier),
|
||||
Inventory.Callback { products ->
|
||||
val purchases = products.get(type)
|
||||
if (!purchases.supported) return@Callback
|
||||
purchases.skus.firstOrNull()?.let { onSuccess(it) }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun loadInventory(type: String, skus: List<String>, callback: Inventory.Callback) {
|
||||
|
|
@ -101,132 +106,166 @@ class PurchaseHandler(activity: Activity, val analyticsManager: AnalyticsManager
|
|||
|
||||
fun purchaseSubscription(sku: Sku, onSuccess: (() -> Unit)) {
|
||||
sku.id.code?.let { code ->
|
||||
billingRequests?.isPurchased(ProductTypes.SUBSCRIPTION, code, object : RequestListener<Boolean> {
|
||||
override fun onSuccess(aBoolean: Boolean) {
|
||||
if (!aBoolean) {
|
||||
// no current product exist
|
||||
checkout?.let {
|
||||
billingRequests?.purchase(ProductTypes.SUBSCRIPTION, code, null, it.createOneShotPurchaseFlow(object : RequestListener<Purchase> {
|
||||
override fun onSuccess(result: Purchase) {
|
||||
onSuccess()
|
||||
}
|
||||
billingRequests?.isPurchased(
|
||||
ProductTypes.SUBSCRIPTION, code,
|
||||
object : RequestListener<Boolean> {
|
||||
override fun onSuccess(aBoolean: Boolean) {
|
||||
if (!aBoolean) {
|
||||
// no current product exist
|
||||
checkout?.let {
|
||||
billingRequests?.purchase(
|
||||
ProductTypes.SUBSCRIPTION, code, null,
|
||||
it.createOneShotPurchaseFlow(object : RequestListener<Purchase> {
|
||||
override fun onSuccess(result: Purchase) {
|
||||
onSuccess()
|
||||
}
|
||||
|
||||
override fun onError(response: Int, e: java.lang.Exception) {}
|
||||
}))
|
||||
override fun onError(response: Int, e: java.lang.Exception) {}
|
||||
})
|
||||
)
|
||||
}
|
||||
} else {
|
||||
onSuccess()
|
||||
}
|
||||
} else {
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(i: Int, e: Exception) { analyticsManager.logException(e) }
|
||||
})
|
||||
override fun onError(i: Int, e: Exception) { analyticsManager.logException(e) }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun checkForSubscription(onSubscriptionFound: ((Purchase) -> Unit)) {
|
||||
billingRequests?.getPurchases(ProductTypes.SUBSCRIPTION, null, object : RequestListener<Purchases> {
|
||||
override fun onSuccess(result: Purchases) {
|
||||
var lastPurchase: Purchase? = null
|
||||
for (purchase in result.list) {
|
||||
if (lastPurchase != null && lastPurchase.time > purchase.time) {
|
||||
continue
|
||||
} else {
|
||||
lastPurchase = purchase
|
||||
billingRequests?.getPurchases(
|
||||
ProductTypes.SUBSCRIPTION, null,
|
||||
object : RequestListener<Purchases> {
|
||||
override fun onSuccess(result: Purchases) {
|
||||
var lastPurchase: Purchase? = null
|
||||
for (purchase in result.list) {
|
||||
if (lastPurchase != null && lastPurchase.time > purchase.time) {
|
||||
continue
|
||||
} else {
|
||||
lastPurchase = purchase
|
||||
}
|
||||
}
|
||||
if (lastPurchase != null) {
|
||||
onSubscriptionFound(lastPurchase)
|
||||
}
|
||||
}
|
||||
if (lastPurchase != null) {
|
||||
onSubscriptionFound(lastPurchase)
|
||||
|
||||
override fun onError(response: Int, e: java.lang.Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(response: Int, e: java.lang.Exception) {
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
private fun checkIfPendingPurchases() {
|
||||
billingRequests?.getAllPurchases(ProductTypes.IN_APP, object : RequestListener<Purchases> {
|
||||
override fun onSuccess(purchases: Purchases) {
|
||||
for (purchase in purchases.list) {
|
||||
if (PurchaseTypes.allGemTypes.contains(purchase.sku)) {
|
||||
billingRequests?.consume(purchase.token, object : RequestListener<Any> {
|
||||
override fun onSuccess(o: Any) {
|
||||
//EventBus.getDefault().post(new BoughtGemsEvent(GEMS_TO_ADD));
|
||||
}
|
||||
billingRequests?.getAllPurchases(
|
||||
ProductTypes.IN_APP,
|
||||
object : RequestListener<Purchases> {
|
||||
override fun onSuccess(purchases: Purchases) {
|
||||
for (purchase in purchases.list) {
|
||||
if (PurchaseTypes.allGemTypes.contains(purchase.sku)) {
|
||||
billingRequests?.consume(
|
||||
purchase.token,
|
||||
object : RequestListener<Any> {
|
||||
override fun onSuccess(o: Any) {
|
||||
// EventBus.getDefault().post(new BoughtGemsEvent(GEMS_TO_ADD));
|
||||
}
|
||||
|
||||
override fun onError(i: Int, e: Exception) {
|
||||
analyticsManager.logException(e)
|
||||
}
|
||||
})
|
||||
override fun onError(i: Int, e: Exception) {
|
||||
analyticsManager.logException(e)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(i: Int, e: Exception) {
|
||||
analyticsManager.logException(e)
|
||||
override fun onError(i: Int, e: Exception) {
|
||||
analyticsManager.logException(e)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
fun purchaseGems(identifier: String) {
|
||||
checkout?.let {
|
||||
it.destroyPurchaseFlow()
|
||||
billingRequests?.purchase(ProductTypes.IN_APP, identifier, null, it.createOneShotPurchaseFlow(
|
||||
PURCHASE_REQUEST_CODE, object : RequestListener<Purchase> {
|
||||
override fun onSuccess(result: Purchase) {
|
||||
billingRequests?.consume(result.token, object : RequestListener<Any> {
|
||||
override fun onSuccess(o: Any) { /* no-op */ }
|
||||
billingRequests?.purchase(
|
||||
ProductTypes.IN_APP, identifier, null,
|
||||
it.createOneShotPurchaseFlow(
|
||||
PURCHASE_REQUEST_CODE,
|
||||
object : RequestListener<Purchase> {
|
||||
override fun onSuccess(result: Purchase) {
|
||||
billingRequests?.consume(
|
||||
result.token,
|
||||
object : RequestListener<Any> {
|
||||
override fun onSuccess(o: Any) { /* no-op */ }
|
||||
|
||||
override fun onError(i: Int, e: Exception) {
|
||||
analyticsManager.logException(e)
|
||||
override fun onError(i: Int, e: Exception) {
|
||||
analyticsManager.logException(e)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onError(response: Int, e: java.lang.Exception) {
|
||||
analyticsManager.logException(e)
|
||||
if (response == ResponseCodes.ITEM_ALREADY_OWNED) {
|
||||
checkIfPendingPurchases()
|
||||
override fun onError(response: Int, e: java.lang.Exception) {
|
||||
analyticsManager.logException(e)
|
||||
if (response == ResponseCodes.ITEM_ALREADY_OWNED) {
|
||||
checkIfPendingPurchases()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun purchaseNoRenewSubscription(sku: Sku) {
|
||||
checkout?.let {
|
||||
billingRequests?.purchase(ProductTypes.IN_APP, sku.id.code, null, it.createOneShotPurchaseFlow(
|
||||
PURCHASE_REQUEST_CODE, object : RequestListener<Purchase> {
|
||||
override fun onSuccess(result: Purchase) {
|
||||
billingRequests?.consume(result.token, object : RequestListener<Any> {
|
||||
override fun onSuccess(o: Any) { /* no-op */ }
|
||||
billingRequests?.purchase(
|
||||
ProductTypes.IN_APP, sku.id.code, null,
|
||||
it.createOneShotPurchaseFlow(
|
||||
PURCHASE_REQUEST_CODE,
|
||||
object : RequestListener<Purchase> {
|
||||
override fun onSuccess(result: Purchase) {
|
||||
billingRequests?.consume(
|
||||
result.token,
|
||||
object : RequestListener<Any> {
|
||||
override fun onSuccess(o: Any) { /* no-op */ }
|
||||
|
||||
override fun onError(i: Int, e: Exception) {
|
||||
override fun onError(i: Int, e: Exception) {
|
||||
analyticsManager.logException(e)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun onError(response: Int, e: java.lang.Exception) {
|
||||
analyticsManager.logException(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onError(response: Int, e: java.lang.Exception) {
|
||||
analyticsManager.logException(e)
|
||||
}
|
||||
}))
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun consumePurchase(purchase: Purchase) {
|
||||
if (PurchaseTypes.allGemTypes.contains(purchase.sku) || PurchaseTypes.allSubscriptionNoRenewTypes.contains(purchase.sku)) {
|
||||
billingRequests?.consume(purchase.token, object : RequestListener<Any> {
|
||||
override fun onSuccess(result: Any) { /* no-op */ }
|
||||
billingRequests?.consume(
|
||||
purchase.token,
|
||||
object : RequestListener<Any> {
|
||||
override fun onSuccess(result: Any) { /* no-op */ }
|
||||
|
||||
override fun onError(response: Int, e: Exception) {
|
||||
analyticsManager.logException(e)
|
||||
override fun onError(response: Int, e: Exception) {
|
||||
analyticsManager.logException(e)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
|
||||
private var handlers = WeakHashMap<Activity, PurchaseHandler>()
|
||||
|
|
@ -237,4 +276,4 @@ class PurchaseHandler(activity: Activity, val analyticsManager: AnalyticsManager
|
|||
return handlers[activity]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class RxErrorHandler {
|
|||
}
|
||||
|
||||
fun handleEmptyError(): Consumer<Throwable> {
|
||||
//Can't be turned into a lambda, because it then doesn't work for some reason.
|
||||
// Can't be turned into a lambda, because it then doesn't work for some reason.
|
||||
return Consumer { reportError(it) }
|
||||
}
|
||||
|
||||
|
|
@ -32,13 +32,13 @@ class RxErrorHandler {
|
|||
Log.e("ObservableError", Log.getStackTraceString(throwable))
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!IOException::class.java.isAssignableFrom(throwable.javaClass)
|
||||
&& !HttpException::class.java.isAssignableFrom(throwable.javaClass)
|
||||
&& !retrofit2.HttpException::class.java.isAssignableFrom(throwable.javaClass)
|
||||
&& !EOFException::class.java.isAssignableFrom(throwable.javaClass)
|
||||
&& throwable !is ConnectionShutdownException) {
|
||||
if (!IOException::class.java.isAssignableFrom(throwable.javaClass) &&
|
||||
!HttpException::class.java.isAssignableFrom(throwable.javaClass) &&
|
||||
!retrofit2.HttpException::class.java.isAssignableFrom(throwable.javaClass) &&
|
||||
!EOFException::class.java.isAssignableFrom(throwable.javaClass) &&
|
||||
throwable !is ConnectionShutdownException
|
||||
) {
|
||||
instance?.analyticsManager?.logException(throwable)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import androidx.annotation.RequiresApi
|
|||
import com.habitrpg.android.habitica.BuildConfig
|
||||
|
||||
class SignInWebViewClient(
|
||||
private val attempt: SignInWithAppleService.AuthenticationAttempt,
|
||||
private val callback: (SignInWithAppleResult) -> Unit
|
||||
private val attempt: SignInWithAppleService.AuthenticationAttempt,
|
||||
private val callback: (SignInWithAppleResult) -> Unit
|
||||
) : WebViewClient() {
|
||||
|
||||
// for API levels < 24
|
||||
|
|
@ -61,7 +61,6 @@ class SignInWebViewClient(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sealed class SignInWithAppleResult {
|
||||
|
|
|
|||
|
|
@ -42,9 +42,9 @@ class SignInWebViewDialogFragment : DialogFragment() {
|
|||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
super.onCreateView(inflater, container, savedInstanceState)
|
||||
|
||||
|
|
@ -73,10 +73,10 @@ class SignInWebViewDialogFragment : DialogFragment() {
|
|||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putBundle(
|
||||
WEB_VIEW_KEY,
|
||||
Bundle().apply {
|
||||
webViewIfCreated?.saveState(this)
|
||||
}
|
||||
WEB_VIEW_KEY,
|
||||
Bundle().apply {
|
||||
webViewIfCreated?.saveState(this)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -102,4 +102,4 @@ class SignInWebViewDialogFragment : DialogFragment() {
|
|||
}
|
||||
callback(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,27 +8,27 @@ import com.willowtreeapps.signinwithapplebutton.SignInWithAppleConfiguration
|
|||
import java.util.*
|
||||
|
||||
class SignInWithAppleService(
|
||||
private val fragmentManager: FragmentManager,
|
||||
private val fragmentTag: String,
|
||||
private val configuration: SignInWithAppleConfiguration,
|
||||
private val callback: (SignInWithAppleResult) -> Unit
|
||||
private val fragmentManager: FragmentManager,
|
||||
private val fragmentTag: String,
|
||||
private val configuration: SignInWithAppleConfiguration,
|
||||
private val callback: (SignInWithAppleResult) -> Unit
|
||||
) {
|
||||
|
||||
init {
|
||||
val fragmentIfShown =
|
||||
fragmentManager.findFragmentByTag(fragmentTag) as? SignInWebViewDialogFragment
|
||||
fragmentManager.findFragmentByTag(fragmentTag) as? SignInWebViewDialogFragment
|
||||
fragmentIfShown?.configure(callback)
|
||||
}
|
||||
|
||||
data class AuthenticationAttempt(
|
||||
val authenticationUri: String,
|
||||
val redirectUri: String,
|
||||
val state: String
|
||||
val authenticationUri: String,
|
||||
val redirectUri: String,
|
||||
val state: String
|
||||
) : Parcelable {
|
||||
constructor(parcel: Parcel) : this(
|
||||
parcel.readString() ?: "invalid",
|
||||
parcel.readString() ?: "invalid",
|
||||
parcel.readString() ?: "invalid"
|
||||
parcel.readString() ?: "invalid",
|
||||
parcel.readString() ?: "invalid",
|
||||
parcel.readString() ?: "invalid"
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
|
|
@ -59,22 +59,22 @@ class SignInWithAppleService(
|
|||
https://developer.apple.com/documentation/signinwithapplejs/configuring_your_webpage_for_sign_in_with_apple
|
||||
*/
|
||||
fun create(
|
||||
configuration: SignInWithAppleConfiguration,
|
||||
state: String = UUID.randomUUID().toString()
|
||||
configuration: SignInWithAppleConfiguration,
|
||||
state: String = UUID.randomUUID().toString()
|
||||
): AuthenticationAttempt {
|
||||
val authenticationUri = Uri
|
||||
.parse("https://appleid.apple.com/auth/authorize")
|
||||
.buildUpon().apply {
|
||||
appendQueryParameter("response_type", "code")
|
||||
appendQueryParameter("v", "1.1.6")
|
||||
appendQueryParameter("client_id", configuration.clientId)
|
||||
appendQueryParameter("redirect_uri", configuration.redirectUri)
|
||||
appendQueryParameter("scope", configuration.scope)
|
||||
appendQueryParameter("state", state)
|
||||
appendQueryParameter("response_mode", "form_post")
|
||||
}
|
||||
.build()
|
||||
.toString()
|
||||
.parse("https://appleid.apple.com/auth/authorize")
|
||||
.buildUpon().apply {
|
||||
appendQueryParameter("response_type", "code")
|
||||
appendQueryParameter("v", "1.1.6")
|
||||
appendQueryParameter("client_id", configuration.clientId)
|
||||
appendQueryParameter("redirect_uri", configuration.redirectUri)
|
||||
appendQueryParameter("scope", configuration.scope)
|
||||
appendQueryParameter("state", state)
|
||||
appendQueryParameter("response_mode", "form_post")
|
||||
}
|
||||
.build()
|
||||
.toString()
|
||||
|
||||
return AuthenticationAttempt(authenticationUri, configuration.redirectUri, state)
|
||||
}
|
||||
|
|
@ -86,4 +86,4 @@ class SignInWithAppleService(
|
|||
fragment.configure(callback)
|
||||
fragment.show(fragmentManager, fragmentTag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@ package com.habitrpg.android.habitica.helpers
|
|||
import android.media.AudioAttributes
|
||||
import android.media.AudioManager
|
||||
import android.media.MediaPlayer
|
||||
import android.os.Build
|
||||
import java.io.File
|
||||
|
||||
|
||||
class SoundFile(val theme: String, private val fileName: String) : MediaPlayer.OnCompletionListener {
|
||||
var file: File? = null
|
||||
private var playerPrepared: Boolean = false
|
||||
|
|
@ -33,9 +31,9 @@ class SoundFile(val theme: String, private val fileName: String) : MediaPlayer.O
|
|||
try {
|
||||
m.setDataSource(file?.path)
|
||||
val attributes = AudioAttributes.Builder()
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||
.setLegacyStreamType(AudioManager.STREAM_NOTIFICATION)
|
||||
.build()
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||
.setLegacyStreamType(AudioManager.STREAM_NOTIFICATION)
|
||||
.build()
|
||||
m.setAudioAttributes(attributes)
|
||||
m.prepare()
|
||||
|
||||
|
|
@ -47,7 +45,6 @@ class SoundFile(val theme: String, private val fileName: String) : MediaPlayer.O
|
|||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onCompletion(mediaPlayer: MediaPlayer) {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ class SoundFileLoader(private val context: Context) {
|
|||
@SuppressLint("SetWorldReadable", "ReturnCount")
|
||||
fun download(files: List<SoundFile>): Single<List<SoundFile>> {
|
||||
return Observable.fromIterable(files)
|
||||
.flatMap({ audioFile ->
|
||||
.flatMap(
|
||||
{ audioFile ->
|
||||
val file = File(getFullAudioFilePath(audioFile))
|
||||
if (file.exists() && file.length() > 5000) {
|
||||
// Important, or else the MediaPlayer can't access this file
|
||||
|
|
@ -67,10 +68,12 @@ class SoundFileLoader(private val context: Context) {
|
|||
sub.onComplete()
|
||||
}
|
||||
fileObservable.subscribeOn(Schedulers.io())
|
||||
}, 5)
|
||||
.toList()
|
||||
},
|
||||
5
|
||||
)
|
||||
.toList()
|
||||
}
|
||||
|
||||
private fun getFullAudioFilePath(soundFile: SoundFile): String =
|
||||
externalCacheDir + File.separator + soundFile.filePath
|
||||
}
|
||||
externalCacheDir + File.separator + soundFile.filePath
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,11 +47,14 @@ 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()
|
||||
}, RxErrorHandler.handleEmptyError())
|
||||
soundFileLoader.download(soundFiles).observeOn(Schedulers.newThread()).subscribe(
|
||||
{
|
||||
val file = soundFiles[0]
|
||||
loadedSoundFiles[type] = file
|
||||
file.play()
|
||||
},
|
||||
RxErrorHandler.handleEmptyError()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -68,5 +71,4 @@ class SoundManager {
|
|||
const val SoundTodo = "Todo"
|
||||
const val SoundThemeOff = "off"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class TaskAlarmManager(private var context: Context, private var taskRepository:
|
|||
for (reminder in it) {
|
||||
var currentReminder = reminder
|
||||
if (task.type == Task.TYPE_DAILY) {
|
||||
//Ensure that we set to the next available time
|
||||
// Ensure that we set to the next available time
|
||||
currentReminder = this.setTimeForDailyReminder(currentReminder, task)
|
||||
}
|
||||
this.setAlarmForRemindersItem(task, currentReminder)
|
||||
|
|
@ -40,22 +40,22 @@ class TaskAlarmManager(private var context: Context, private var taskRepository:
|
|||
}
|
||||
}
|
||||
|
||||
//This function is used from the TaskReceiver since we do not have access to the task
|
||||
//We currently only use this function to schedule the next reminder for dailies
|
||||
//We may be able to use repeating alarms instead of this in the future
|
||||
// This function is used from the TaskReceiver since we do not have access to the task
|
||||
// We currently only use this function to schedule the next reminder for dailies
|
||||
// We may be able to use repeating alarms instead of this in the future
|
||||
fun addAlarmForTaskId(taskId: String) {
|
||||
taskRepository.getTaskCopy(taskId)
|
||||
.filter { task -> task.isValid && task.isManaged && Task.TYPE_DAILY == task.type }
|
||||
.firstElement()
|
||||
.subscribe({ this.setAlarmsForTask(it) }, RxErrorHandler.handleEmptyError())
|
||||
.filter { task -> task.isValid && task.isManaged && Task.TYPE_DAILY == task.type }
|
||||
.firstElement()
|
||||
.subscribe({ this.setAlarmsForTask(it) }, RxErrorHandler.handleEmptyError())
|
||||
}
|
||||
|
||||
fun scheduleAllSavedAlarms(preventDailyReminder: Boolean) {
|
||||
taskRepository.getTaskCopies(userId)
|
||||
.firstElement()
|
||||
.toFlowable()
|
||||
.flatMap { Flowable.fromIterable(it) }
|
||||
.subscribe({ this.setAlarmsForTask(it) }, RxErrorHandler.handleEmptyError())
|
||||
.firstElement()
|
||||
.toFlowable()
|
||||
.flatMap { Flowable.fromIterable(it) }
|
||||
.subscribe({ this.setAlarmsForTask(it) }, RxErrorHandler.handleEmptyError())
|
||||
|
||||
if (!preventDailyReminder) {
|
||||
scheduleDailyReminder(context)
|
||||
|
|
@ -92,7 +92,7 @@ class TaskAlarmManager(private var context: Context, private var taskRepository:
|
|||
intent.putExtra(TASK_ID_INTENT_KEY, reminderItemTask.id)
|
||||
|
||||
val intentId = remindersItem.id?.hashCode() ?: 0 and 0xfffffff
|
||||
//Cancel alarm if already exists
|
||||
// Cancel alarm if already exists
|
||||
val previousSender = PendingIntent.getBroadcast(context, intentId, intent, PendingIntent.FLAG_NO_CREATE)
|
||||
if (previousSender != null) {
|
||||
previousSender.cancel()
|
||||
|
|
|
|||
|
|
@ -97,11 +97,11 @@ class TaskFilterHelper {
|
|||
}
|
||||
if (searchQuery?.isNotEmpty() == true) {
|
||||
query = query
|
||||
.beginGroup()
|
||||
.contains("text", searchQuery ?: "", Case.INSENSITIVE)
|
||||
.or()
|
||||
.contains("notes", searchQuery ?: "", Case.INSENSITIVE)
|
||||
.endGroup()
|
||||
.beginGroup()
|
||||
.contains("text", searchQuery ?: "", Case.INSENSITIVE)
|
||||
.or()
|
||||
.contains("notes", searchQuery ?: "", Case.INSENSITIVE)
|
||||
.endGroup()
|
||||
}
|
||||
if (activeFilter != null && activeFilter != Task.FILTER_ALL) {
|
||||
when (activeFilter) {
|
||||
|
|
|
|||
|
|
@ -128,7 +128,6 @@ class UserStatComputer {
|
|||
attributeRow.summary = false
|
||||
skillRows.add(attributeRow)
|
||||
|
||||
|
||||
val attributeRow2 = AttributeRow()
|
||||
attributeRow2.labelId = R.string.profile_class_bonus
|
||||
attributeRow2.strVal = strClassBonus
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@ package com.habitrpg.android.habitica.helpers.notifications
|
|||
|
||||
import android.content.Context
|
||||
|
||||
class ChangeUsernameLocalNotification(context: Context, identifier: String?) : HabiticaLocalNotification(context, identifier)
|
||||
class ChangeUsernameLocalNotification(context: Context, identifier: String?) : HabiticaLocalNotification(context, identifier)
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ class ChatMentionNotification(context: Context, identifier: String?) : HabiticaL
|
|||
|
||||
override fun configureNotificationBuilder(data: MutableMap<String, String>): NotificationCompat.Builder {
|
||||
val style = NotificationCompat.BigTextStyle()
|
||||
.setBigContentTitle(title)
|
||||
.bigText(message)
|
||||
.setBigContentTitle(title)
|
||||
.bigText(message)
|
||||
return super.configureNotificationBuilder(data)
|
||||
.setStyle(style)
|
||||
.setStyle(style)
|
||||
}
|
||||
|
||||
override fun configureMainIntent(intent: Intent) {
|
||||
|
|
@ -19,4 +19,4 @@ class ChatMentionNotification(context: Context, identifier: String?) : HabiticaL
|
|||
intent.putExtra("type", data?.get("type"))
|
||||
intent.putExtra("groupID", data?.get("groupID"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@ package com.habitrpg.android.habitica.helpers.notifications
|
|||
|
||||
import android.content.Context
|
||||
|
||||
class GenericLocalNotification(context: Context, identifier: String?) : HabiticaLocalNotification(context, identifier)
|
||||
class GenericLocalNotification(context: Context, identifier: String?) : HabiticaLocalNotification(context, identifier)
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@ package com.habitrpg.android.habitica.helpers.notifications
|
|||
|
||||
import android.content.Context
|
||||
|
||||
class GiftOneGetOneLocalNotification(context: Context, identifier: String?) : HabiticaLocalNotification(context, identifier)
|
||||
class GiftOneGetOneLocalNotification(context: Context, identifier: String?) : HabiticaLocalNotification(context, identifier)
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ class GroupActivityNotification(context: Context, identifier: String?) : Habitic
|
|||
val user = Person.Builder().setName("You").build()
|
||||
val message = makeMessageFromData(data)
|
||||
var style = NotificationCompat.MessagingStyle(user)
|
||||
.setGroupConversation(true)
|
||||
.setConversationTitle(data["groupName"])
|
||||
.setGroupConversation(true)
|
||||
.setConversationTitle(data["groupName"])
|
||||
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
|
||||
val existingNotifications = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
|
|
@ -39,8 +39,8 @@ class GroupActivityNotification(context: Context, identifier: String?) : Habitic
|
|||
style = style.addMessage(message)
|
||||
oldMessages.add(data)
|
||||
return super.configureNotificationBuilder(data)
|
||||
.setStyle(style)
|
||||
.setExtras(bundleOf(Pair("messages", bundleOf(Pair("messages", oldMessages)))))
|
||||
.setStyle(style)
|
||||
.setExtras(bundleOf(Pair("messages", bundleOf(Pair("messages", oldMessages)))))
|
||||
}
|
||||
|
||||
private fun makeMessageFromData(data: Map<String, String>): NotificationCompat.MessagingStyle.Message {
|
||||
|
|
@ -49,9 +49,9 @@ class GroupActivityNotification(context: Context, identifier: String?) : Habitic
|
|||
val timestamp = dateFormat.parse(data["timestamp"]) ?: Date()
|
||||
val messageText = EmojiParser.parseEmojis(data["message"]?.trim { it <= ' ' })
|
||||
return NotificationCompat.MessagingStyle.Message(
|
||||
messageText,
|
||||
timestamp.time,
|
||||
sender
|
||||
messageText,
|
||||
timestamp.time,
|
||||
sender
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -69,15 +69,19 @@ class GroupActivityNotification(context: Context, identifier: String?) : Habitic
|
|||
intent.action = actionName
|
||||
intent.putExtra("groupID", groupID)
|
||||
val replyPendingIntent: PendingIntent =
|
||||
PendingIntent.getBroadcast(context, groupID.hashCode(),
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
PendingIntent.getBroadcast(
|
||||
context, groupID.hashCode(),
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
|
||||
val action: NotificationCompat.Action =
|
||||
NotificationCompat.Action.Builder(R.drawable.ic_send_grey_600_24dp,
|
||||
context.getString(R.string.reply), replyPendingIntent)
|
||||
.addRemoteInput(remoteInput)
|
||||
.build()
|
||||
NotificationCompat.Action.Builder(
|
||||
R.drawable.ic_send_grey_600_24dp,
|
||||
context.getString(R.string.reply), replyPendingIntent
|
||||
)
|
||||
.addRemoteInput(remoteInput)
|
||||
.build()
|
||||
notificationBuilder.addAction(action)
|
||||
}
|
||||
|
||||
|
|
@ -86,4 +90,4 @@ class GroupActivityNotification(context: Context, identifier: String?) : Habitic
|
|||
intent.putExtra("type", data?.get("type"))
|
||||
intent.putExtra("groupID", data?.get("groupID"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.habitrpg.android.habitica.helpers.notifications
|
|||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver
|
||||
|
||||
|
|
@ -25,10 +24,10 @@ class GuildInviteLocalNotification(context: Context, identifier: String?) : Habi
|
|||
acceptInviteIntent.action = res.getString(R.string.accept_guild_invite)
|
||||
acceptInviteIntent.putExtra("groupID", this.data?.get("groupID"))
|
||||
val pendingIntentAccept = PendingIntent.getBroadcast(
|
||||
context,
|
||||
3000,
|
||||
acceptInviteIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
context,
|
||||
3000,
|
||||
acceptInviteIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
notificationBuilder.addAction(0, "Accept", pendingIntentAccept)
|
||||
|
||||
|
|
@ -36,10 +35,10 @@ class GuildInviteLocalNotification(context: Context, identifier: String?) : Habi
|
|||
rejectInviteIntent.action = res.getString(R.string.reject_guild_invite)
|
||||
rejectInviteIntent.putExtra("groupID", this.data?.get("groupID"))
|
||||
val pendingIntentReject = PendingIntent.getBroadcast(
|
||||
context,
|
||||
2000,
|
||||
rejectInviteIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
context,
|
||||
2000,
|
||||
rejectInviteIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
notificationBuilder.addAction(0, "Reject", pendingIntentReject)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,12 @@ import com.google.firebase.messaging.FirebaseMessagingService
|
|||
import com.google.firebase.messaging.RemoteMessage
|
||||
import com.habitrpg.android.habitica.HabiticaBaseApplication
|
||||
import com.habitrpg.android.habitica.components.UserComponent
|
||||
import com.habitrpg.android.habitica.data.UserRepository
|
||||
import com.habitrpg.android.habitica.helpers.RxErrorHandler
|
||||
import javax.inject.Inject
|
||||
|
||||
class HabiticaFirebaseMessagingService : FirebaseMessagingService() {
|
||||
|
||||
private val userComponent: UserComponent?
|
||||
get() = HabiticaBaseApplication.userComponent
|
||||
get() = HabiticaBaseApplication.userComponent
|
||||
|
||||
@Inject
|
||||
internal lateinit var pushNotificationManager: PushNotificationManager
|
||||
|
|
@ -23,7 +21,7 @@ class HabiticaFirebaseMessagingService : FirebaseMessagingService() {
|
|||
pushNotificationManager.displayNotification(remoteMessage)
|
||||
|
||||
if (remoteMessage.data["identifier"]?.contains(PushNotificationManager.WON_CHALLENGE_PUSH_NOTIFICATION_KEY) == true) {
|
||||
//userRepository.retrieveUser(true).subscribe({}, RxErrorHandler.handleEmptyError())
|
||||
// userRepository.retrieveUser(true).subscribe({}, RxErrorHandler.handleEmptyError())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,6 +35,5 @@ class HabiticaFirebaseMessagingService : FirebaseMessagingService() {
|
|||
pushNotificationManager.refreshedToken = refreshedToken
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue