diff --git a/Habitica/AndroidManifest.xml b/Habitica/AndroidManifest.xml index 128c8bab5..d453c944a 100644 --- a/Habitica/AndroidManifest.xml +++ b/Habitica/AndroidManifest.xml @@ -7,6 +7,7 @@ + diff --git a/Habitica/build.gradle b/Habitica/build.gradle index 9b19c603b..38e49f375 100644 --- a/Habitica/build.gradle +++ b/Habitica/build.gradle @@ -51,10 +51,10 @@ dependencies { compileOnly 'javax.annotation:javax.annotation-api:1.3.2' compileOnly 'com.github.pengrad:jdk9-deps:1.0' //App Compatibility and Material Design - implementation 'androidx.appcompat:appcompat:1.4.0' - implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.appcompat:appcompat:1.4.1' + implementation 'com.google.android.material:material:1.5.0' implementation 'androidx.recyclerview:recyclerview:1.2.1' - implementation "androidx.preference:preference-ktx:1.1.1" + implementation "androidx.preference:preference-ktx:1.2.0" // Markdown @@ -121,10 +121,10 @@ dependencies { implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0" implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0" implementation "androidx.lifecycle:lifecycle-common-java8:2.4.0" - implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5' - implementation 'androidx.navigation:navigation-ui-ktx:2.3.5' + implementation 'androidx.navigation:navigation-fragment-ktx:2.4.0' + implementation 'androidx.navigation:navigation-ui-ktx:2.4.0' implementation 'com.plattysoft.leonids:LeonidsLib:1.3.2' - implementation "androidx.fragment:fragment-ktx:1.4.0" + implementation "androidx.fragment:fragment-ktx:1.4.1" implementation "androidx.paging:paging-runtime-ktx:3.1.0" implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0' @@ -142,7 +142,7 @@ dependencies { android { compileSdkVersion 32 - buildToolsVersion '30.0.2' + buildToolsVersion '30.0.3' testOptions { unitTests { includeAndroidResources = true @@ -157,7 +157,7 @@ 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 3218 + versionCode 3223 versionName "3.5" targetSdkVersion 32 @@ -382,8 +382,8 @@ def mainSrc = "${project.projectDir}/src/main/java" task jacocoTestReport(type: JacocoReport, dependsOn: 'testProdDebugUnitTest') { group = "Reporting" reports { - html.enabled = true - xml.enabled = true + html.required.set(true) + xml.required.set(true) //html.destination = "${buildDir}/reports/jacoco" } @@ -404,7 +404,6 @@ task jacocoTestReport(type: JacocoReport, dependsOn: 'testProdDebugUnitTest') { task ktlint(type: JavaExec, group: "verification") { description = "Check Kotlin code style." classpath = configurations.ktlint - main = "com.pinterest.ktlint.Main" args "--disabled_rules=no-wildcard-imports", "--reporter=plain?group_by_file", "src/**/*.kt" // to generate report in checkstyle format prepend following args: // "--reporter=plain", "--reporter=checkstyle,output=${buildDir}/ktlint.xml" @@ -417,6 +416,5 @@ check.dependsOn ktlint task ktlintFormat(type: JavaExec, group: "formatting") { description = "Fix Kotlin code style deviations." classpath = configurations.ktlint - main = "com.pinterest.ktlint.Main" args "--disabled_rules=no-wildcard-imports", "-F", "src/**/*.kt" } diff --git a/Habitica/res/drawable-hdpi/gift_sub_gift.png b/Habitica/res/drawable-hdpi/gift_sub_gift.png index 30842a74b..278e05552 100644 Binary files a/Habitica/res/drawable-hdpi/gift_sub_gift.png and b/Habitica/res/drawable-hdpi/gift_sub_gift.png differ diff --git a/Habitica/res/drawable-mdpi/gift_sub_gift.png b/Habitica/res/drawable-mdpi/gift_sub_gift.png index fd10d6689..d13327594 100644 Binary files a/Habitica/res/drawable-mdpi/gift_sub_gift.png and b/Habitica/res/drawable-mdpi/gift_sub_gift.png differ diff --git a/Habitica/res/drawable-xhdpi/gift_sub_gift.png b/Habitica/res/drawable-xhdpi/gift_sub_gift.png index cb0b08379..f13dbf105 100644 Binary files a/Habitica/res/drawable-xhdpi/gift_sub_gift.png and b/Habitica/res/drawable-xhdpi/gift_sub_gift.png differ diff --git a/Habitica/res/drawable-xxhdpi/gift_sub_gift.png b/Habitica/res/drawable-xxhdpi/gift_sub_gift.png index f5fc9dbe5..6e7180dd5 100644 Binary files a/Habitica/res/drawable-xxhdpi/gift_sub_gift.png and b/Habitica/res/drawable-xxhdpi/gift_sub_gift.png differ diff --git a/Habitica/res/layout/fragment_gem_purchase.xml b/Habitica/res/layout/fragment_gem_purchase.xml index 1e910c52e..1333f53b4 100644 --- a/Habitica/res/layout/fragment_gem_purchase.xml +++ b/Habitica/res/layout/fragment_gem_purchase.xml @@ -233,11 +233,12 @@ android:layout_width="wrap_content" android:paddingStart="41dp" android:paddingEnd="41dp" - android:paddingBottom="20dp" + android:paddingBottom="30dp" android:paddingTop="70dp" android:text="@string/gem_purchase_title" android:layout_gravity="center_horizontal" android:gravity="center" + android:lineSpacingExtra="3dp" android:textColor="@color/white" style="@style/Caption2" android:drawablePadding="@dimen/spacing_medium"/> diff --git a/Habitica/res/layout/purchase_gem_view.xml b/Habitica/res/layout/purchase_gem_view.xml index 454c3e295..b83800c33 100644 --- a/Habitica/res/layout/purchase_gem_view.xml +++ b/Habitica/res/layout/purchase_gem_view.xml @@ -17,19 +17,37 @@ android:contentDescription="@string/gems" android:layout_marginTop="20dp"/> - + android:orientation="horizontal"> + + + - + Rewards Yes No + Discard Quest Body Hair @@ -378,7 +379,7 @@ Google play services could not be found. Purchase Buying gems supports the developers and helps keep Habitica running - Gems allow you to buy fun extras for your account: + Gems allow you to buy fun extras for your account Cool costumes for your avatar Awesome backgrounds Quests that reward you with pet eggs @@ -470,6 +471,7 @@ Each month, subscribers will receive a mystery item. This is usually released about one week before the end of the month. Open> Open + Use Item on party member> You earned a %1$s as a reward for your devotion to improving your life. Next prize in %1$d Check-Ins pending approval @@ -527,6 +529,7 @@ Your device does not have any of the supported payment methods. Please use the habitica website if you want to purchase gems. Your device does not have any of the supported payment methods. Please use the habitica website if you want to purchase a subscription. Save + Unsaved Changes Location Gem prize Tasks @@ -551,6 +554,7 @@ Start My Day Are you sure you want to leave this party? Do you want to keep participating in the Challenge when leaving the Party? + Are you sure you want to discard changes to this task? You will not be able to rejoin this party unless invited. Pending Accepted diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/components/UserComponent.java b/Habitica/src/main/java/com/habitrpg/android/habitica/components/UserComponent.java index bf889d2f4..128148286 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/components/UserComponent.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/components/UserComponent.java @@ -103,6 +103,7 @@ import com.habitrpg.android.habitica.ui.viewmodels.AuthenticationViewModel; import com.habitrpg.android.habitica.ui.viewmodels.GroupViewModel; import com.habitrpg.android.habitica.ui.viewmodels.InboxViewModel; import com.habitrpg.android.habitica.ui.viewmodels.MainActivityViewModel; +import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel; import com.habitrpg.android.habitica.ui.viewmodels.NotificationsViewModel; import com.habitrpg.android.habitica.ui.viewmodels.inventory.equipment.EquipmentOverviewViewModel; import com.habitrpg.android.habitica.ui.views.insufficientCurrency.InsufficientGemsDialog; @@ -352,4 +353,6 @@ public interface UserComponent { void inject(@NotNull MainActivityViewModel mainActivityViewModel); void inject(@NotNull GuidelinesActivity guidelinesActivity); + + void inject(@NotNull MainUserViewModel mainUserViewModel); } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/SocialRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/SocialRepository.kt index 721e7ace7..af3994412 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/SocialRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/SocialRepository.kt @@ -84,6 +84,5 @@ interface SocialRepository : BaseRepository { fun getGroupMembership(id: String): Flowable fun getGroupMemberships(): Flowable> - fun getChatmessage(messageID: String): Flowable fun blockMember(userID: String): Flowable> } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ContentRepositoryImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ContentRepositoryImpl.kt index fd4c8cb9e..94c363df5 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ContentRepositoryImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ContentRepositoryImpl.kt @@ -9,7 +9,6 @@ import com.habitrpg.android.habitica.models.ContentResult import com.habitrpg.android.habitica.models.WorldState import com.habitrpg.android.habitica.models.inventory.SpecialItem import io.reactivex.rxjava3.core.Flowable -import io.realm.RealmList import java.util.* class ContentRepositoryImpl(localRepository: T, apiClient: ApiClient, context: Context) : BaseRepositoryImpl(localRepository, apiClient), ContentRepository { @@ -24,7 +23,6 @@ class ContentRepositoryImpl(localRepository: T, apiC return if (forced || now - this.lastContentSync > 300000) { lastContentSync = now apiClient.content.doOnNext { - it.special = RealmList() it.special.add(mysteryItem) localRepository.saveContent(it) } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/SocialRepositoryImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/SocialRepositoryImpl.kt index acfbb2bde..954164dd4 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/SocialRepositoryImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/SocialRepositoryImpl.kt @@ -37,10 +37,6 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap } } - override fun getChatmessage(messageID: String): Flowable { - return localRepository.getChatMessage(messageID) - } - override fun blockMember(userID: String): Flowable> { return apiClient.blockMember(userID) } @@ -92,7 +88,9 @@ class SocialRepositoryImpl(localRepository: SocialLocalRepository, apiClient: Ap return Flowable.empty() } val liked = chatMessage.userLikesMessage(userID) - localRepository.likeMessage(chatMessage, userID, !liked) + if (chatMessage.isManaged) { + localRepository.likeMessage(chatMessage, userID, !liked) + } return apiClient.likeMessage(chatMessage.groupId ?: "", chatMessage.id) } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/SocialLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/SocialLocalRepository.kt index aebf06a4b..2dd96f015 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/SocialLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/SocialLocalRepository.kt @@ -47,5 +47,4 @@ interface SocialLocalRepository : BaseLocalRepository { fun saveGroupMemberships(userID: String?, memberships: List) fun saveInboxMessages(userID: String, recipientID: String, messages: List, page: Int) fun saveInboxConversations(userID: String, conversations: List) - fun getChatMessage(messageID: String): Flowable } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmContentLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmContentLocalRepository.kt index da558dc96..042f35b2f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmContentLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmContentLocalRepository.kt @@ -28,6 +28,7 @@ open class RealmContentLocalRepository(realm: Realm) : RealmBaseLocalRepository( realm1.insertOrUpdate(contentResult.mounts) realm1.insertOrUpdate(contentResult.spells) + realm1.insertOrUpdate(contentResult.special) realm1.insertOrUpdate(contentResult.appearances) realm1.insertOrUpdate(contentResult.backgrounds) realm1.insertOrUpdate(contentResult.faq) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmInventoryLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmInventoryLocalRepository.kt index 9375752f6..cd739e699 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmInventoryLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmInventoryLocalRepository.kt @@ -96,7 +96,7 @@ class RealmInventoryLocalRepository(realm: Realm) : RealmContentLocalRepository( "hatchingPotions" -> it.items?.hatchingPotions "food" -> it.items?.food "quests" -> it.items?.quests - "special" -> it.items?.special?.ownedItems + "special" -> it.items?.special else -> emptyList() } ?: emptyList() if (includeZero) { @@ -286,7 +286,7 @@ class RealmInventoryLocalRepository(realm: Realm) : RealmContentLocalRepository( return } val liveUser = getLiveObject(user) - val ownedItems = liveUser?.items?.special?.ownedItems + val ownedItems = liveUser?.items?.special val item = ownedItems?.firstOrNull() { it.key == "inventory_present" } executeTransaction { if (item != null && item.isValid) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmSocialLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmSocialLocalRepository.kt index 07329b047..2bac1fc16 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmSocialLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmSocialLocalRepository.kt @@ -12,14 +12,6 @@ import io.realm.Sort import java.util.* class RealmSocialLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm), SocialLocalRepository { - override fun getChatMessage(messageID: String): Flowable = RxJavaBridge.toV3Flowable( - realm.where(ChatMessage::class.java) - .equalTo("id", messageID) - .findAll() - .asFlowable() - .filter { it.isLoaded && it.isNotEmpty() } - .map { it.first() } - ) override fun getGroupMembership(userId: String, id: String): Flowable = RxJavaBridge.toV3Flowable( realm.where(GroupMembership::class.java) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmUserLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmUserLocalRepository.kt index 455c2b00d..ad7040b3a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmUserLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmUserLocalRepository.kt @@ -146,22 +146,10 @@ class RealmUserLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm), override fun getSpecialItems(user: User): Flowable> { val specialItems = user.items?.special val ownedItems = ArrayList() - if (specialItems != null) { - if (specialItems.snowball > 0) { - ownedItems.add("snowball") + for (key in listOf("snowball", "shinySeed", "seafoam", "spookySparkles")) { + if (specialItems?.firstOrNull() { it.key == key }?.numberOwned ?: 0 > 0) { + ownedItems.add(key) } - if (specialItems.shinySeed > 0) { - ownedItems.add("shinySeed") - } - if (specialItems.seafoam > 0) { - ownedItems.add("seafoam") - } - if (specialItems.spookySparkles > 0) { - ownedItems.add("spookySparkles") - } - } - if (ownedItems.size == 0) { - ownedItems.add("") } return RxJavaBridge.toV3Flowable( realm.where(Skill::class.java) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskAlarmManager.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskAlarmManager.kt index ce2a67a2a..23861569d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskAlarmManager.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskAlarmManager.kt @@ -1,6 +1,7 @@ package com.habitrpg.android.habitica.helpers import android.app.AlarmManager +import android.app.AlarmManager.AlarmClockInfo import android.app.PendingIntent import android.content.Context import android.content.Intent @@ -121,6 +122,7 @@ class TaskAlarmManager(private var context: Context, private var taskRepository: const val TASK_NAME_INTENT_KEY = "TASK_NAME" fun scheduleDailyReminder(context: Context?) { + if (context == null) return val prefs = PreferenceManager.getDefaultSharedPreferences(context) if (prefs.getBoolean("use_reminder", false)) { val timeval = prefs.getString("reminder_time", "19:00") @@ -174,7 +176,7 @@ class TaskAlarmManager(private var context: Context, private var taskRepository: if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { alarmManager?.setWindow(AlarmManager.RTC_WAKEUP, time, 60000, pendingIntent) } else { - alarmManager?.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, pendingIntent) + alarmManager?.setAlarmClock(AlarmClockInfo(time, pendingIntent), pendingIntent) } } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/SpecialItem.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/SpecialItem.kt index 061955b30..521388af6 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/SpecialItem.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/SpecialItem.kt @@ -15,6 +15,7 @@ open class SpecialItem : RealmObject(), Item { internal var notes: String = "" override var value: Int = 0 override var event: ItemEvent? = null + var target: String? = null var isMysteryItem: Boolean = false companion object { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt index 7a1b66989..ebcfa2949 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt @@ -256,6 +256,47 @@ open class Task : RealmObject, BaseMainObject, Parcelable { } } + fun isBeingEdited(task: Task): Boolean { + + when { + text != task.text -> return true + notes != task.notes -> return true + reminders != task.reminders -> return true + checklist != task.checklist -> return true + priority != task.priority -> return true + attribute != task.attribute && attribute != null -> return true + tags != task.tags -> return true + } + if (type == TaskType.HABIT) { + return when { + up != task.up -> true + down != task.down -> true + frequency != task.frequency -> true + counterUp != task.counterUp -> true + counterDown != task.counterDown -> true + else -> false + } + } else if (type == TaskType.DAILY) { + return when { + startDate != task.startDate -> true + everyX != task.everyX -> true + frequency != task.frequency -> true + repeat != task.repeat -> true + streak != task.streak -> true + else -> false + } + + } else if (type == TaskType.TODO) { + return dueDate != task.dueDate + + } else if (type == TaskType.REWARD) { + return value != task.value + + } else { + return false + } + } + override fun hashCode(): Int { return id?.hashCode() ?: 0 } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Items.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Items.kt index 049378511..d4d52ad47 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Items.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Items.kt @@ -13,6 +13,7 @@ open class Items : RealmObject, BaseObject { eggs?.forEach { it.itemType = "eggs" } food?.forEach { it.itemType = "food" } quests?.forEach { it.itemType = "quests" } + special?.forEach { it.itemType = "special" } } var eggs: RealmList? = null @@ -35,6 +36,12 @@ open class Items : RealmObject, BaseObject { field = value field?.forEach { it.itemType = "quests" } } + var special: RealmList? = null + set(value) { + field = value + field?.forEach { it.itemType = "special" } + } + var pets: RealmList? = null var mounts: RealmList? = null var currentMount: String? = null @@ -44,7 +51,6 @@ open class Items : RealmObject, BaseObject { // private QuestContent quest; var gear: Gear? = null - var special: SpecialItems? = null constructor(currentMount: String, currentPet: String, lastDropCount: Int, lastDropDate: Date) { this.currentMount = currentMount @@ -54,4 +60,14 @@ open class Items : RealmObject, BaseObject { } constructor() + + val hasTransformationItems: Boolean + get() { + return special?.any { transformationItem -> + transformationItem.key == ("seafoam") && transformationItem.numberOwned > 0|| + transformationItem.key == ("shinySeed") && transformationItem.numberOwned > 0|| + transformationItem.key == ("snowball") && transformationItem.numberOwned > 0|| + transformationItem.key == ("spookySparkles") && transformationItem.numberOwned > 0 + } ?: false + } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SpecialItems.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SpecialItems.kt deleted file mode 100644 index 681e158eb..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SpecialItems.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.habitrpg.android.habitica.models.user - -import com.habitrpg.android.habitica.models.BaseObject -import io.realm.RealmList -import io.realm.RealmObject -import io.realm.annotations.RealmClass - -@RealmClass(embedded = true) -open class SpecialItems : RealmObject(), BaseObject { - var ownedItems: RealmList? = null - var seafoam: Int = 0 - var shinySeed: Int = 0 - var snowball: Int = 0 - var spookySparkles: Int = 0 - - val hasSpecialItems: Boolean - get() { - return seafoam > 0 || shinySeed > 0 || snowball > 0 || spookySparkles > 0 - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.kt index b4a8d3de5..ddb99448a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/AppModule.kt @@ -34,7 +34,7 @@ class AppModule(private val application: Application) { @Provides @Singleton - fun provideSharedPreferences(context: Context?): SharedPreferences { + fun provideSharedPreferences(context: Context): SharedPreferences { return PreferenceManager.getDefaultSharedPreferences(context) } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/UserModule.java b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/UserModule.java index e6ac9f658..e6e231245 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/UserModule.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/UserModule.java @@ -4,8 +4,10 @@ import android.content.Context; import android.content.SharedPreferences; import com.habitrpg.android.habitica.data.TaskRepository; +import com.habitrpg.android.habitica.data.UserRepository; import com.habitrpg.android.habitica.helpers.TaskAlarmManager; import com.habitrpg.android.habitica.helpers.UserScope; +import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel; import javax.inject.Named; @@ -28,4 +30,10 @@ public class UserModule { public String providesUserID(SharedPreferences sharedPreferences) { return sharedPreferences.getString("UserID", ""); } + + @Provides + @UserScope + MainUserViewModel providesUserViewModel(UserRepository userRepository) { + return new MainUserViewModel(userRepository); + } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/prefs/TimePreference.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/prefs/TimePreference.kt index 7635262ad..fb2900833 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/prefs/TimePreference.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/prefs/TimePreference.kt @@ -7,7 +7,7 @@ import androidx.preference.DialogPreference import java.text.DateFormat import java.util.* -class TimePreference(ctxt: Context?, attrs: AttributeSet?) : DialogPreference(ctxt, attrs) { +class TimePreference(ctxt: Context, attrs: AttributeSet?) : DialogPreference(ctxt, attrs) { private var timeval: String? = null override fun onGetDefaultValue(a: TypedArray, index: Int): Any { return a.getString(index)!! @@ -39,7 +39,7 @@ class TimePreference(ctxt: Context?, attrs: AttributeSet?) : DialogPreference(ct } } - override fun setSummary(summary: CharSequence) { + override fun setSummary(summary: CharSequence?) { val calendar = Calendar.getInstance(Locale.getDefault()) calendar.set(Calendar.HOUR_OF_DAY, getHour(timeval)) calendar.set(Calendar.MINUTE, getMinute(timeval)) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt index ccb64cf42..e51369eb5 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt @@ -73,9 +73,9 @@ class AvatarWithBarsViewModel(private val context: Context, private val binding: if (!stats.isBuffed) { binding.buffImageView.visibility = View.GONE } - - binding.currencyView.gold = stats.gp ?: 0.0 + if (user is User) { + binding.currencyView.gold = stats.gp ?: 0.0 binding.currencyView.hourglasses = user.hourglassCount.toDouble() binding.currencyView.gems = user.gemCount.toDouble() } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/GemPurchaseOptionsView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/GemPurchaseOptionsView.kt index 89dd9db5a..6f3e7a308 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/GemPurchaseOptionsView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/GemPurchaseOptionsView.kt @@ -20,7 +20,7 @@ class GemPurchaseOptionsView(context: Context, attrs: AttributeSet) : FrameLayou 0, 0 ) - binding.gemAmount.text = "${a.getText(R.styleable.GemPurchaseOptionsView_gemAmount)} GEMS" + binding.gemAmount.text = a.getText(R.styleable.GemPurchaseOptionsView_gemAmount) val iconRes = a.getDrawable(R.styleable.GemPurchaseOptionsView_gemDrawable) if (iconRes != null) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt index 23f799a37..7e02ed842 100755 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt @@ -273,7 +273,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction, Snack navigationController.addOnDestinationChangedListener { _, destination, arguments -> updateToolbarTitle(destination, arguments) } if (launchScreen == "/party") { - if (viewModel.isUserInParty) { + if (viewModel.userViewModel.isUserInParty) { MainNavigationController.navigate(R.id.partyFragment) } } @@ -430,7 +430,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction, Snack } private fun displayDeathDialogIfNeeded() { - if (!viewModel.isUserFainted) { + if (!viewModel.userViewModel.isUserFainted) { return } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt index edd88c8e3..d8c1b69b2 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt @@ -1,6 +1,7 @@ package com.habitrpg.android.habitica.ui.activities import android.app.Activity +import android.content.DialogInterface import android.content.Intent import android.content.SharedPreferences import android.content.res.ColorStateList @@ -13,6 +14,7 @@ import android.widget.CheckBox import android.widget.TextView import androidx.appcompat.widget.AppCompatCheckBox import androidx.core.content.ContextCompat +import androidx.core.os.bundleOf import androidx.core.view.children import androidx.core.view.forEachIndexed import androidx.core.widget.NestedScrollView @@ -21,7 +23,6 @@ import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.ChallengeRepository import com.habitrpg.android.habitica.data.TagRepository import com.habitrpg.android.habitica.data.TaskRepository -import com.habitrpg.android.habitica.data.UserRepository import com.habitrpg.android.habitica.databinding.ActivityTaskFormBinding import com.habitrpg.android.habitica.extensions.OnChangeTextWatcher import com.habitrpg.android.habitica.extensions.addCancelButton @@ -64,6 +65,7 @@ class TaskFormActivity : BaseActivity() { private var isChallengeTask = false private var usesTaskAttributeStats = false private var task: Task? = null + private var initialTaskInstance: Task? = null private var taskType: TaskType = TaskType.HABIT private var tags = listOf() private var preselectedTags: ArrayList? = null @@ -74,6 +76,7 @@ class TaskFormActivity : BaseActivity() { setSelectedAttribute(value) } + private var isDiscardCancelled: Boolean = false private var canSave: Boolean = false private var tintColor: Int = 0 @@ -198,6 +201,7 @@ class TaskFormActivity : BaseActivity() { { if (!it.isValid) return@subscribe task = it + initialTaskInstance = it // tintColor = ContextCompat.getColor(this, it.mediumTaskColor) fillForm(it) it.challengeID?.let { challengeID -> @@ -224,17 +228,21 @@ class TaskFormActivity : BaseActivity() { task = bundle.getParcelable(PARCELABLE_TASK) task?.let { fillForm(it) } } - else -> title = getString( - R.string.create_task, - getString( - when (taskType) { - TaskType.DAILY -> R.string.daily - TaskType.TODO -> R.string.todo - TaskType.REWARD -> R.string.reward - else -> R.string.habit - } + else -> { + title = getString( + R.string.create_task, + getString( + when (taskType) { + TaskType.DAILY -> R.string.daily + TaskType.TODO -> R.string.todo + TaskType.REWARD -> R.string.reward + else -> R.string.habit + } + ) ) - ) + initialTaskInstance = configureTask(Task()) + } + } configureForm() } @@ -252,6 +260,29 @@ class TaskFormActivity : BaseActivity() { } } + override fun onBackPressed() { + val currentTaskInstance = configureTask(Task()) + if (initialTaskInstance?.isBeingEdited(currentTaskInstance) == true) { + val alert = HabiticaAlertDialog(this) + alert.setTitle(R.string.unsaved_changes) + alert.setMessage(R.string.discard_changes_to_task_message) + alert.addButton(R.string.discard, true, true) { _, _ -> + analyticsManager.logEvent("discard_task", bundleOf(Pair("is_creating", isCreating))) + super.onBackPressed() + } + alert.addButton(R.string.cancel, false) { _, _ -> + isDiscardCancelled = true + alert.dismiss() + } + alert.setOnDismissListener(DialogInterface.OnDismissListener { + isDiscardCancelled = true + }) + alert.show() + } else { + super.onBackPressed() + } + } + override fun onCreateOptionsMenu(menu: Menu): Boolean { if (isCreating) { menuInflater.inflate(R.menu.menu_task_create, menu) @@ -437,19 +468,10 @@ class TaskFormActivity : BaseActivity() { } } - private fun saveTask() { - if (isSaving) { - return - } - isSaving = true - var thisTask = task - if (thisTask == null) { - thisTask = Task() - thisTask.type = taskType - thisTask.dateCreated = Date() - } else { - if (!thisTask.isValid) return - } + private fun configureTask(thisTask: Task): Task { + thisTask.type = taskType + thisTask.dateCreated = Date() + thisTask.text = binding.textEditText.text.toString() thisTask.notes = binding.notesEditText.text.toString() thisTask.priority = binding.taskDifficultyButtons.selectedDifficulty @@ -460,8 +482,10 @@ class TaskFormActivity : BaseActivity() { thisTask.up = binding.habitScoringButtons.isPositive thisTask.down = binding.habitScoringButtons.isNegative thisTask.frequency = binding.habitResetStreakButtons.selectedResetOption.value - if (binding.habitAdjustPositiveStreakView.text?.isNotEmpty() == true) thisTask.counterUp = binding.habitAdjustPositiveStreakView.text.toString().toIntCatchOverflow() - if (binding.habitAdjustNegativeStreakView.text?.isNotEmpty() == true) thisTask.counterDown = binding.habitAdjustNegativeStreakView.text.toString().toIntCatchOverflow() + if (binding.habitAdjustPositiveStreakView.text?.isNotEmpty() == true) thisTask.counterUp = + binding.habitAdjustPositiveStreakView.text.toString().toIntCatchOverflow() + if (binding.habitAdjustNegativeStreakView.text?.isNotEmpty() == true) thisTask.counterDown = + binding.habitAdjustNegativeStreakView.text.toString().toIntCatchOverflow() } else if (taskType == TaskType.DAILY) { thisTask.startDate = binding.taskSchedulingControls.startDate thisTask.everyX = binding.taskSchedulingControls.everyX @@ -469,15 +493,13 @@ class TaskFormActivity : BaseActivity() { thisTask.repeat = binding.taskSchedulingControls.weeklyRepeat thisTask.setDaysOfMonth(binding.taskSchedulingControls.daysOfMonth) thisTask.setWeeksOfMonth(binding.taskSchedulingControls.weeksOfMonth) - if (binding.habitAdjustPositiveStreakView.text?.isNotEmpty() == true) thisTask.streak = binding.habitAdjustPositiveStreakView.text.toString().toIntCatchOverflow() + if (binding.habitAdjustPositiveStreakView.text?.isNotEmpty() == true) thisTask.streak = + binding.habitAdjustPositiveStreakView.text.toString().toIntCatchOverflow() } else if (taskType == TaskType.TODO) { thisTask.dueDate = binding.taskSchedulingControls.dueDate } else if (taskType == TaskType.REWARD) { thisTask.value = binding.rewardValue.value } - - val resultIntent = Intent() - resultIntent.putExtra(TASK_TYPE_KEY, taskType) if (!isChallengeTask) { if (taskType == TaskType.DAILY || taskType == TaskType.TODO) { thisTask.checklist = RealmList() @@ -492,10 +514,40 @@ class TaskFormActivity : BaseActivity() { thisTask.tags?.add(tags[index]) } } + } + return thisTask + } + + private fun saveTask() { + if (isSaving) { + return + } + isSaving = true + var thisTask = task + if (thisTask == null) { + thisTask = Task() + thisTask.type = taskType + thisTask.dateCreated = Date() + } else { + if (!thisTask.isValid) return + } + + thisTask = configureTask(thisTask) + + val resultIntent = Intent() + resultIntent.putExtra(TASK_TYPE_KEY, taskType) + if (!isChallengeTask) { if (isCreating) { + if (isDiscardCancelled){ + analyticsManager.logEvent("back_to_task", bundleOf(Pair("is_creating", isCreating))) + } taskRepository.createTaskInBackground(thisTask) + } else { + if (isDiscardCancelled){ + analyticsManager.logEvent("back_to_task", bundleOf(Pair("is_creating", isCreating))) + } taskRepository.updateTaskInBackground(thisTask) } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/SkillsRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/SkillsRecyclerViewAdapter.kt index 423793985..6b64fa8b0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/SkillsRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/SkillsRecyclerViewAdapter.kt @@ -12,12 +12,13 @@ import com.habitrpg.android.habitica.databinding.SkillListItemBinding import com.habitrpg.android.habitica.extensions.inflate import com.habitrpg.android.habitica.extensions.isUsingNightModeResources import com.habitrpg.android.habitica.models.Skill -import com.habitrpg.android.habitica.models.user.SpecialItems +import com.habitrpg.android.habitica.models.user.OwnedItem import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import io.reactivex.rxjava3.core.BackpressureStrategy import io.reactivex.rxjava3.core.Flowable import io.reactivex.rxjava3.subjects.PublishSubject +import io.realm.RealmList class SkillsRecyclerViewAdapter : RecyclerView.Adapter() { @@ -34,7 +35,7 @@ class SkillsRecyclerViewAdapter : RecyclerView.Adapter?? = null set(value) { field = value notifyDataSetChanged() @@ -134,13 +135,7 @@ class SkillsRecyclerViewAdapter : RecyclerView.Adapter specialItems?.snowball - "shinySeed" -> specialItems?.shinySeed - "seafoam" -> specialItems?.seafoam - "spookySparkles" -> specialItems?.spookySparkles - else -> 0 - } ?: 0 + return specialItems?.firstOrNull() { it.key == key }?.numberOwned ?: 0 } } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ItemRecyclerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ItemRecyclerAdapter.kt index 88143efb8..d13f80c92 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ItemRecyclerAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ItemRecyclerAdapter.kt @@ -47,6 +47,7 @@ class ItemRecyclerAdapter(val context: Context, val user: User?) : BaseRecyclerV private val hatchPetSubject = PublishSubject.create>() private val feedPetSubject = PublishSubject.create() private val createNewPartySubject = PublishSubject.create() + private val useSpecialSubject = PublishSubject.create() fun getSellItemFlowable(): Flowable { return sellItemEvents.toFlowable(BackpressureStrategy.DROP) @@ -63,6 +64,7 @@ class ItemRecyclerAdapter(val context: Context, val user: User?) : BaseRecyclerV val hatchPetEvents: Flowable> = hatchPetSubject.toFlowable(BackpressureStrategy.DROP) val feedPetEvents: Flowable = feedPetSubject.toFlowable(BackpressureStrategy.DROP) val startNewPartyEvents: Flowable = createNewPartySubject.toFlowable(BackpressureStrategy.DROP) + val useSpecialEvents: Flowable = useSpecialSubject.toFlowable(BackpressureStrategy.DROP) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { return ItemViewHolder(ItemItemBinding.inflate(context.layoutInflater, parent, false)) @@ -115,9 +117,14 @@ class ItemRecyclerAdapter(val context: Context, val user: User?) : BaseRecyclerV if (item is QuestContent) { imageName = "inventory_quest_scroll_" + ownedItem.key } else if (item is SpecialItem) { - val sdf = SimpleDateFormat("MM", Locale.getDefault()) - val month = sdf.format(Date()) - imageName = "inventory_present_$month" + if (item.key == "inventory_present") { + val sdf = SimpleDateFormat("MM", Locale.getDefault()) + val month = sdf.format(Date()) + imageName = "inventory_present_$month" + } else { + imageName = "shop_" + ownedItem.key + } + } else { val type = when (ownedItem.itemType) { "eggs" -> "Egg" @@ -164,7 +171,10 @@ class ItemRecyclerAdapter(val context: Context, val user: User?) : BaseRecyclerV val specialItem = item as SpecialItem if (specialItem.isMysteryItem && ownedItem?.numberOwned ?: 0 > 0) { menu.addMenuItem(BottomSheetMenuItem(resources.getString(R.string.open))) + } else if (ownedItem?.numberOwned ?: 0 > 0){ + menu.addMenuItem(BottomSheetMenuItem(resources.getString(R.string.use_item))) } + } menu.setSelectionRunnable { index -> item?.let { selectedItem -> @@ -189,7 +199,12 @@ class ItemRecyclerAdapter(val context: Context, val user: User?) : BaseRecyclerV } } - is SpecialItem -> openMysteryItemEvents.onNext(selectedItem) + is SpecialItem -> + if (item?.key != "inventory_present") { + useSpecialSubject.onNext(selectedItem) + } else { + openMysteryItemEvents.onNext(selectedItem) + } } } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/MountDetailRecyclerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/MountDetailRecyclerAdapter.kt index 462627480..69e9bcbda 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/MountDetailRecyclerAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/MountDetailRecyclerAdapter.kt @@ -15,7 +15,11 @@ class MountDetailRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Ada private var ownedMounts: Map? = null private val equipEvents = PublishSubject.create() - private var user: User? = null + var currentMount: String? = null + set(value) { + field = value + notifyDataSetChanged() + } private var itemList: List = ArrayList() @@ -37,7 +41,7 @@ class MountDetailRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Ada override fun onBindViewHolder(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder, position: Int) { when (val obj = this.itemList[position]) { is StableSection -> (holder as? SectionViewHolder)?.bind(obj) - is Mount -> (holder as? MountViewHolder)?.bind(obj, ownedMounts?.get(obj.key ?: "")?.owned == true, user) + is Mount -> (holder as? MountViewHolder)?.bind(obj, ownedMounts?.get(obj.key ?: "")?.owned == true, currentMount) } } @@ -49,9 +53,4 @@ class MountDetailRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Ada this.ownedMounts = ownedMounts notifyDataSetChanged() } - - fun setUser(user: User) { - this.user = user - notifyDataSetChanged() - } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/PetDetailRecyclerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/PetDetailRecyclerAdapter.kt index ffc74fe7d..cfb6b1279 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/PetDetailRecyclerAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/PetDetailRecyclerAdapter.kt @@ -17,7 +17,11 @@ class PetDetailRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapt private var ownedPets: Map? = null private var ownedMounts: Map? = null private var ownedItems: Map? = null - private var user: User? = null + var currentPet: String? = null + set(value) { + field = value + notifyDataSetChanged() + } private val equipEvents = PublishSubject.create() private val feedEvents = PublishSubject.create>() private var ownsSaddles: Boolean = false @@ -29,11 +33,6 @@ class PetDetailRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapt this.notifyDataSetChanged() } - fun setUser(user: User) { - this.user = user - notifyDataSetChanged() - } - fun getEquipFlowable(): Flowable { return equipEvents.toFlowable(BackpressureStrategy.DROP) } @@ -81,7 +80,7 @@ class PetDetailRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapt ownedItems?.get(obj.animal + "-eggs") != null, ownedItems?.get(obj.color + "-hatchingPotions") != null, ownedMounts?.containsKey(obj.key) == true, - user + currentPet ) } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/StableRecyclerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/StableRecyclerAdapter.kt index 90b2da691..ea2d6fb92 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/StableRecyclerAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/StableRecyclerAdapter.kt @@ -31,7 +31,16 @@ class StableRecyclerAdapter : RecyclerView.Adapter() { var animalIngredientsRetriever: ((Animal, ((Pair) -> Unit)) -> Unit)? = null private val feedEvents = PublishSubject.create>() var itemType: String? = null - private var user: User? = null + var currentPet: String? = null + set(value) { + field = value + notifyDataSetChanged() + } + var currentMount: String? = null + set(value) { + field = value + notifyDataSetChanged() + } private val equipEvents = PublishSubject.create() private var existingMounts: List? = null private var ownedMounts: Map? = null @@ -43,11 +52,6 @@ class StableRecyclerAdapter : RecyclerView.Adapter() { return equipEvents.toFlowable(BackpressureStrategy.DROP) } - fun setUser(user: User) { - this.user = user - notifyDataSetChanged() - } - private fun canRaiseToMount(pet: Pet): Boolean { if (pet.type == "special") return false for (mount in existingMounts ?: emptyList()) { @@ -122,10 +126,10 @@ class StableRecyclerAdapter : RecyclerView.Adapter() { hasUnlockedEgg = ownedItems?.get(item.animal + "-eggs") != null, hasUnlockedPotion = ownedItems?.get(item.color + "-hatchingPotions") != null, hasMount = ownedMounts?.containsKey(item.key) == true, - user = user + currentPet = currentPet ) } else if (item is Mount) { - (holder as? MountViewHolder)?.bind(item, item.numberOwned > 0, user) + (holder as? MountViewHolder)?.bind(item, item.numberOwned > 0, currentMount) } return } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/AchievementsFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/AchievementsFragment.kt index 640535294..b77c3c20f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/AchievementsFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/AchievementsFragment.kt @@ -14,6 +14,7 @@ import com.habitrpg.android.habitica.databinding.FragmentRefreshRecyclerviewBind import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.ui.adapter.AchievementsAdapter import com.habitrpg.android.habitica.ui.helpers.ToolbarColorHelper +import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import io.reactivex.rxjava3.kotlin.Flowables import io.reactivex.rxjava3.kotlin.combineLatest import javax.inject.Inject @@ -22,6 +23,8 @@ class AchievementsFragment : BaseMainFragment 0) { entries.add(Pair("Challenges won", challengeAchievementCount)) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseMainFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseMainFragment.kt index 9fe7288b5..0d1289d7b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseMainFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseMainFragment.kt @@ -39,23 +39,12 @@ abstract class BaseMainFragment : BaseFragment() { var usesTabLayout: Boolean = false var hidesToolbar: Boolean = false var usesBottomNavigation = false - open var user: User? = null - - override fun onAttach(context: Context) { - super.onAttach(context) - - if (activity is MainActivity) { - user = activity?.viewModel?.user?.value - } - } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { - compositeSubscription.add(userRepository.getUser().subscribe({ user = it }, RxErrorHandler.handleEmptyError())) - if (this.usesBottomNavigation) { bottomNavigation?.visibility = View.VISIBLE } else { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt index 90164183a..0eb00cb47 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt @@ -28,7 +28,6 @@ import com.habitrpg.android.habitica.extensions.* import com.habitrpg.android.habitica.helpers.AppConfigManager import com.habitrpg.android.habitica.helpers.MainNavigationController import com.habitrpg.android.habitica.helpers.RxErrorHandler -import com.habitrpg.android.habitica.models.WorldState import com.habitrpg.android.habitica.models.WorldStateEvent import com.habitrpg.android.habitica.models.inventory.Item import com.habitrpg.android.habitica.models.inventory.Quest @@ -41,7 +40,6 @@ import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.activities.MainActivity import com.habitrpg.android.habitica.ui.activities.NotificationsActivity import com.habitrpg.android.habitica.ui.adapter.NavigationDrawerAdapter -import com.habitrpg.android.habitica.ui.fragments.social.TavernDetailFragment import com.habitrpg.android.habitica.ui.menu.HabiticaDrawerItem import com.habitrpg.android.habitica.ui.viewmodels.NotificationsViewModel import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar @@ -339,10 +337,10 @@ class NavigationDrawerFragment : DialogFragment() { tavernItem?.subtitle = null } - val specialItems = user.items?.special + val userItems = user.items var hasSpecialItems = false - if (specialItems != null) { - hasSpecialItems = specialItems.hasSpecialItems + if (userItems != null) { + hasSpecialItems = userItems.hasTransformationItems } val item = getItemWithIdentifier(SIDEBAR_SKILLS) if (item != null) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/customization/AvatarCustomizationFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/customization/AvatarCustomizationFragment.kt index e89ab1837..4a94dad1e 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/customization/AvatarCustomizationFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/customization/AvatarCustomizationFragment.kt @@ -18,6 +18,7 @@ import com.habitrpg.android.habitica.ui.adapter.CustomizationRecyclerViewAdapter import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment import com.habitrpg.android.habitica.ui.helpers.MarginDecoration import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator +import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import javax.inject.Inject class AvatarCustomizationFragment : @@ -34,6 +35,8 @@ class AvatarCustomizationFragment : lateinit var customizationRepository: CustomizationRepository @Inject lateinit var inventoryRepository: InventoryRepository + @Inject + lateinit var userViewModel: MainUserViewModel var type: String? = null var category: String? = null @@ -52,7 +55,7 @@ class AvatarCustomizationFragment : adapter.getSelectCustomizationEvents() .flatMap { customization -> if (customization.type == "background") { - userRepository.unlockPath(user, customization) + userRepository.unlockPath(userViewModel.user.value, customization) .flatMap { userRepository.retrieveUser(false, true, true) } } else { userRepository.useCustomization(customization.type ?: "", customization.category, customization.identifier ?: "") @@ -63,7 +66,7 @@ class AvatarCustomizationFragment : compositeSubscription.add( adapter.getUnlockCustomizationEvents() .flatMap { customization -> - userRepository.unlockPath(user, customization) + userRepository.unlockPath(userViewModel.user.value, customization) } .flatMap { userRepository.retrieveUser(withTasks = false, forced = true) } .flatMap { inventoryRepository.retrieveInAppRewards() } @@ -112,11 +115,7 @@ class AvatarCustomizationFragment : binding?.recyclerView?.itemAnimator = SafeDefaultItemAnimator() this.loadCustomizations() - compositeSubscription.add( - userRepository.getUser().subscribeWithErrorHandler { - updateUser(it) - } - ) + userViewModel.user.observe(viewLifecycleOwner) { updateUser(it) } } override fun onDestroy() { @@ -153,7 +152,8 @@ class AvatarCustomizationFragment : layoutManager.spanCount = spanCount } - fun updateUser(user: User) { + fun updateUser(user: User?) { + if (user == null) return this.updateActiveCustomization(user) if (adapter.customizationList.size != 0) { val ownedCustomizations = ArrayList() @@ -162,8 +162,8 @@ class AvatarCustomizationFragment : } else { this.loadCustomizations() } - this.adapter.userSize = this.user?.preferences?.size - this.adapter.hairColor = this.user?.preferences?.hair?.color + this.adapter.userSize = user.preferences?.size + this.adapter.hairColor = user.preferences?.hair?.color this.adapter.gemBalance = user.gemCount adapter.notifyDataSetChanged() } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/customization/AvatarEquipmentFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/customization/AvatarEquipmentFragment.kt index 7808822ea..2f5e9d9b6 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/customization/AvatarEquipmentFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/customization/AvatarEquipmentFragment.kt @@ -18,6 +18,7 @@ import com.habitrpg.android.habitica.ui.adapter.CustomizationEquipmentRecyclerVi import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment import com.habitrpg.android.habitica.ui.helpers.MarginDecoration import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator +import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import io.reactivex.rxjava3.core.Flowable import javax.inject.Inject @@ -27,6 +28,8 @@ class AvatarEquipmentFragment : @Inject lateinit var inventoryRepository: InventoryRepository + @Inject + lateinit var userViewModel: MainUserViewModel override var binding: FragmentRefreshRecyclerviewBinding? = null @@ -51,7 +54,7 @@ class AvatarEquipmentFragment : adapter.getSelectCustomizationEvents() .flatMap { equipment -> val key = (if (equipment.key?.isNotBlank() != true) activeEquipment else equipment.key) ?: "" - inventoryRepository.equip(user, if (user?.preferences?.costume == true) "costume" else "equipped", key) + inventoryRepository.equip(userViewModel.user.value, if (userViewModel.user.value?.preferences?.costume == true) "costume" else "equipped", key) } .subscribe({ }, RxErrorHandler.handleEmptyError()) ) @@ -143,7 +146,7 @@ class AvatarEquipmentFragment : if (this.type == null || user.preferences == null) { return } - val outfit = if (user.preferences?.costume == true) this.user?.items?.gear?.costume else this.user?.items?.gear?.equipped + val outfit = if (user.preferences?.costume == true) user.items?.gear?.costume else user.items?.gear?.equipped val activeEquipment = when (this.type) { "headAccessory" -> outfit?.headAccessory "back" -> outfit?.back diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/equipment/EquipmentDetailFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/equipment/EquipmentDetailFragment.kt index 665316463..f7c278f11 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/equipment/EquipmentDetailFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/equipment/EquipmentDetailFragment.kt @@ -44,7 +44,7 @@ class EquipmentDetailFragment : savedInstanceState: Bundle? ): View? { compositeSubscription.add( - this.adapter.equipEvents.flatMapMaybe { key -> inventoryRepository.equipGear(user, key, isCostume ?: false).firstElement() } + this.adapter.equipEvents.flatMapMaybe { key -> inventoryRepository.equipGear(null, key, isCostume ?: false).firstElement() } .subscribe({ }, RxErrorHandler.handleEmptyError()) ) return super.onCreateView(inflater, container, savedInstanceState) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/equipment/EquipmentOverviewFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/equipment/EquipmentOverviewFragment.kt index 2d0fb80de..a18122de8 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/equipment/EquipmentOverviewFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/equipment/EquipmentOverviewFragment.kt @@ -45,10 +45,10 @@ class EquipmentOverviewFragment : BaseMainFragment(), SwipeRefreshLayout.OnRefreshListener { @@ -41,11 +50,15 @@ class ItemRecyclerFragment : BaseFragment(), SwipeRefreshL lateinit var userRepository: UserRepository @Inject internal lateinit var hatchPetUseCase: HatchPetUseCase + @Inject + lateinit var userViewModel: MainUserViewModel var adapter: ItemRecyclerAdapter? = null var itemType: String? = null + var transformationItems: MutableList = mutableListOf() var itemTypeText: String? = null var user: User? = null + private var selectedSpecialItem: SpecialItem? = null internal var layoutManager: androidx.recyclerview.widget.LinearLayoutManager? = null override var binding: FragmentItemsBinding? = null @@ -91,7 +104,7 @@ class ItemRecyclerFragment : BaseFragment(), SwipeRefreshL adapter = ItemRecyclerAdapter(context, user) } binding?.recyclerView?.adapter = adapter - + adapter?.useSpecialEvents?.subscribeWithErrorHandler { onSpecialItemSelected(it) }?.let { compositeSubscription.add(it) } adapter?.let { adapter -> compositeSubscription.add( adapter.getSellItemFlowable() @@ -112,7 +125,7 @@ class ItemRecyclerFragment : BaseFragment(), SwipeRefreshL ) compositeSubscription.add( adapter.getOpenMysteryItemFlowable() - .flatMap { inventoryRepository.openMysteryItem(user) } + .flatMap { inventoryRepository.openMysteryItem(userViewModel.user.value) } .doOnNext { val activity = activity as? MainActivity if (activity != null) { @@ -123,7 +136,7 @@ class ItemRecyclerFragment : BaseFragment(), SwipeRefreshL dialog.binding.titleView.text = it.text dialog.binding.descriptionView.text = it.notes dialog.addButton(R.string.equip, true) { _, _ -> - inventoryRepository.equip(user, "equipped", it.key ?: "").subscribe({}, RxErrorHandler.handleEmptyError()) + inventoryRepository.equip(userViewModel.user.value, "equipped", it.key ?: "").subscribe({}, RxErrorHandler.handleEmptyError()) } dialog.addCloseButton() dialog.enqueue() @@ -253,7 +266,9 @@ class ItemRecyclerFragment : BaseFragment(), SwipeRefreshL adapter?.data = items } .map { items -> items.mapNotNull { it.key } } - .flatMap { inventoryRepository.getItems(itemClass, it.toTypedArray()) } + .flatMap { + inventoryRepository.getItems(itemClass, it.toTypedArray()) + } .map { val itemMap = mutableMapOf() for (item in it) { @@ -268,6 +283,7 @@ class ItemRecyclerFragment : BaseFragment(), SwipeRefreshL RxErrorHandler.handleEmptyError() ) ) + } compositeSubscription.add(inventoryRepository.getPets().subscribe({ adapter?.setExistingPets(it) }, RxErrorHandler.handleEmptyError())) @@ -286,6 +302,51 @@ class ItemRecyclerFragment : BaseFragment(), SwipeRefreshL MainNavigationController.navigate(R.id.marketFragment) } + private fun onSpecialItemSelected(specialItem: SpecialItem) { + selectedSpecialItem = specialItem + val intent = Intent(activity, SkillMemberActivity::class.java) + memberSelectionResult.launch(intent) + } + + private val memberSelectionResult = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + if (it.resultCode == Activity.RESULT_OK) { + useSpecialItem(selectedSpecialItem, it.data?.getStringExtra("member_id")) + } + } + + private fun useSpecialItem(specialItem: SpecialItem?, memberID: String? = null) { + if (specialItem == null || memberID == null) { + return + } + + val observable: Flowable = + userRepository.useSkill(specialItem.key, specialItem.target, memberID) + + compositeSubscription.add( + observable.subscribe( + { skillResponse -> this.displaySpecialItemResult(specialItem) }, + RxErrorHandler.handleEmptyError() + ) + ) + } + + private fun displaySpecialItemResult(specialItem: SpecialItem?) { + if (!isAdded) return + + val activity = activity as? MainActivity + activity?.let { + HabiticaSnackbar.showSnackbar( + it.snackbarContainer, + context?.getString(R.string.used_skill_without_mana, specialItem?.text), + HabiticaSnackbar.SnackbarDisplayType.BLUE + ) + } + + loadItems() + + } + companion object { private const val ITEM_TYPE_KEY = "CLASS_TYPE_KEY" diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemsFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemsFragment.kt index df4293962..374f1efa3 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemsFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/items/ItemsFragment.kt @@ -68,7 +68,6 @@ class ItemsFragment : BaseMainFragment() { 4 -> "special" else -> "" } - fragment.user = this@ItemsFragment.user fragment.itemTypeText = if (position == 4 && isAdded) getString(R.string.special_items) else getPageTitle(position) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt index f007fb066..9d8333152 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/shops/ShopFragment.kt @@ -24,6 +24,7 @@ import com.habitrpg.android.habitica.ui.adapter.inventory.ShopRecyclerAdapter import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment import com.habitrpg.android.habitica.ui.helpers.RecyclerViewState import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator +import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import com.habitrpg.android.habitica.ui.views.CurrencyViews import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import javax.inject.Inject @@ -44,6 +45,8 @@ open class ShopFragment : BaseMainFragment() lateinit var socialRepository: SocialRepository @Inject lateinit var configManager: AppConfigManager + @Inject + lateinit var userViewModel: MainUserViewModel private var layoutManager: GridLayoutManager? = null @@ -106,7 +109,7 @@ open class ShopFragment : BaseMainFragment() this.shopIdentifier = savedInstanceState.getString(SHOP_IDENTIFIER_KEY, "") } - adapter?.selectedGearCategory = user?.stats?.habitClass ?: "" + adapter?.selectedGearCategory = userViewModel.user.value?.stats?.habitClass ?: "" if (shop != null) { adapter?.setShop(shop) @@ -122,15 +125,10 @@ open class ShopFragment : BaseMainFragment() } } - compositeSubscription.add( - userRepository.getUser().subscribe( - { - adapter?.user = user - updateCurrencyView(it) - }, - RxErrorHandler.handleEmptyError() - ) - ) + userViewModel.user.observe(viewLifecycleOwner) { + adapter?.user = it + updateCurrencyView(it) + } compositeSubscription.add( socialRepository.getGroup(Group.TAVERN_ID) @@ -183,7 +181,7 @@ open class ShopFragment : BaseMainFragment() this.inventoryRepository.retrieveShopInventory(shopUrl) .map { shop1 -> if (shop1.identifier == Shop.MARKET) { - val user = user + val user = userViewModel.user.value val specialCategory = ShopCategory() specialCategory.text = getString(R.string.special) if (user?.isValid == true && user.purchased?.plan?.isActive == true) { @@ -315,9 +313,9 @@ open class ShopFragment : BaseMainFragment() private const val SHOP_IDENTIFIER_KEY = "SHOP_IDENTIFIER_KEY" } - private fun updateCurrencyView(user: User) { - currencyView.gold = user.stats?.gp ?: 0.0 - currencyView.gems = user.gemCount.toDouble() - currencyView.hourglasses = user.hourglassCount.toDouble() + private fun updateCurrencyView(user: User?) { + currencyView.gold = user?.stats?.gp ?: 0.0 + currencyView.gems = user?.gemCount?.toDouble() ?: 0.0 + currencyView.hourglasses = user?.hourglassCount?.toDouble() ?: 0.0 } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/MountDetailRecyclerFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/MountDetailRecyclerFragment.kt index e476df24b..5c385c316 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/MountDetailRecyclerFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/MountDetailRecyclerFragment.kt @@ -18,6 +18,7 @@ import com.habitrpg.android.habitica.ui.adapter.inventory.MountDetailRecyclerAda import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment import com.habitrpg.android.habitica.ui.helpers.MarginDecoration import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator +import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import javax.inject.Inject class MountDetailRecyclerFragment : @@ -26,6 +27,8 @@ class MountDetailRecyclerFragment : @Inject internal lateinit var inventoryRepository: InventoryRepository + @Inject + lateinit var userViewModel: MainUserViewModel var adapter: MountDetailRecyclerAdapter? = null var animalType: String? = null @@ -86,14 +89,15 @@ class MountDetailRecyclerFragment : binding?.recyclerView?.itemAnimator = SafeDefaultItemAnimator() this.loadItems() - adapter?.getEquipFlowable()?.flatMap { key -> inventoryRepository.equip(user, "mount", key) } + adapter?.getEquipFlowable()?.flatMap { key -> inventoryRepository.equip(null, "mount", key) } ?.subscribe( { - user?.let { updatedUser -> adapter?.setUser(updatedUser) } + adapter?.currentMount = it.currentMount }, RxErrorHandler.handleEmptyError() )?.let { compositeSubscription.add(it) } } + userViewModel.user.observe(viewLifecycleOwner) { adapter?.currentMount = it?.currentMount } if (savedInstanceState != null) { this.animalType = savedInstanceState.getString(ANIMAL_TYPE_KEY, "") @@ -134,7 +138,6 @@ class MountDetailRecyclerFragment : return@map mountMap }.doOnNext { adapter?.setOwnedMounts(it) - user?.let { updatedUser -> adapter?.setUser(updatedUser) } }, { unsortedAnimals, ownedAnimals -> val items = mutableListOf() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/PetDetailRecyclerFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/PetDetailRecyclerFragment.kt index a0d655fa4..3bbe400c7 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/PetDetailRecyclerFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/PetDetailRecyclerFragment.kt @@ -22,6 +22,7 @@ import com.habitrpg.android.habitica.ui.adapter.inventory.PetDetailRecyclerAdapt import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment import com.habitrpg.android.habitica.ui.fragments.inventory.items.ItemDialogFragment import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator +import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import io.reactivex.rxjava3.core.Maybe import io.reactivex.rxjava3.kotlin.Flowables import javax.inject.Inject @@ -34,6 +35,8 @@ class PetDetailRecyclerFragment : lateinit var inventoryRepository: InventoryRepository @Inject lateinit var feedPetUseCase: FeedPetUseCase + @Inject + lateinit var userViewModel: MainUserViewModel var adapter: PetDetailRecyclerAdapter = PetDetailRecyclerAdapter() private var animalType: String? = null @@ -109,14 +112,15 @@ class PetDetailRecyclerFragment : compositeSubscription.add( adapter.getEquipFlowable() - .flatMap { key -> inventoryRepository.equip(user, "pet", key) } + .flatMap { key -> inventoryRepository.equip(null, "pet", key) } .subscribe( { - user?.let { updatedUser -> adapter.setUser(updatedUser) } + adapter.currentPet = it.currentPet }, RxErrorHandler.handleEmptyError() ) ) + userViewModel.user.observe(viewLifecycleOwner) { adapter.currentPet = it?.currentPet } compositeSubscription.add(adapter.feedFlowable.subscribe({ showFeedingDialog(it.first, it.second) }, RxErrorHandler.handleEmptyError())) view.post { setGridSpanCount(view.width) } @@ -168,7 +172,6 @@ class PetDetailRecyclerFragment : return@map petMap }.doOnNext { adapter.setOwnedPets(it) - user?.let { updatedUser -> adapter.setUser(updatedUser) } } ).map { val items = mutableListOf() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableFragment.kt index 32e34d316..ee8fff172 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableFragment.kt @@ -56,8 +56,7 @@ class StableFragment : BaseMainFragment() { fragment.itemType = "mounts" } } - fragment.user = this@StableFragment.user - fragment.itemTypeText = getPageTitle(position).toString() + fragment.itemTypeText = getPageTitle(position) return fragment } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.kt index bd88b672f..84a2a1f79 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.kt @@ -23,6 +23,7 @@ import com.habitrpg.android.habitica.ui.fragments.BaseFragment import com.habitrpg.android.habitica.ui.helpers.EmptyItem import com.habitrpg.android.habitica.ui.helpers.MarginDecoration import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator +import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import io.reactivex.rxjava3.core.Flowable import io.reactivex.rxjava3.core.Maybe import io.reactivex.rxjava3.kotlin.combineLatest @@ -39,11 +40,12 @@ class StableRecyclerFragment : lateinit var userRepository: UserRepository @Inject lateinit var configManager: AppConfigManager + @Inject + lateinit var userViewModel: MainUserViewModel var adapter: StableRecyclerAdapter? = null var itemType: String? = null var itemTypeText: String? = null - var user: User? = null internal var layoutManager: androidx.recyclerview.widget.GridLayoutManager? = null override var binding: FragmentRefreshRecyclerviewBinding? = null @@ -96,7 +98,6 @@ class StableRecyclerFragment : adapter = binding?.recyclerView?.adapter as? StableRecyclerAdapter if (adapter == null) { adapter = StableRecyclerAdapter() - user?.let { adapter?.setUser(it) } adapter?.animalIngredientsRetriever = { animal, callback -> Maybe.zip( inventoryRepository.getItems(Egg::class.java, arrayOf(animal.animal)).firstElement(), @@ -119,11 +120,15 @@ class StableRecyclerFragment : adapter?.let { compositeSubscription.add( it.getEquipFlowable() - .flatMap { key -> inventoryRepository.equip(user, if (itemType == "pets") "pet" else "mount", key) } + .flatMap { key -> inventoryRepository.equip(null, if (itemType == "pets") "pet" else "mount", key) } .subscribe({ }, RxErrorHandler.handleEmptyError()) ) } } + userViewModel.user.observe(viewLifecycleOwner) { + adapter?.currentPet = it?.currentPet + adapter?.currentMount = it?.currentMount + } this.loadItems() view.post { setGridSpanCount(view.width) } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountPreferenceFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountPreferenceFragment.kt index 1ef0a9cb9..57e75fbd0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountPreferenceFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountPreferenceFragment.kt @@ -64,11 +64,11 @@ class AccountPreferenceFragment: BasePreferencesFragment(), override fun onResume() { super.onResume() - preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this) + preferenceManager.sharedPreferences?.registerOnSharedPreferenceChangeListener(this) } override fun onPause() { - preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) + preferenceManager.sharedPreferences?.unregisterOnSharedPreferenceChangeListener(this) super.onPause() } @@ -130,8 +130,8 @@ class AccountPreferenceFragment: BasePreferencesFragment(), preference?.summary = value } - override fun onPreferenceTreeClick(preference: Preference?): Boolean { - when(preference?.key) { + override fun onPreferenceTreeClick(preference: Preference): Boolean { + when(preference.key) { "username" -> showLoginNameDialog() "confirm_username" -> showConfirmUsernameDialog() "email" -> { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/DayStartPreferenceDialogFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/DayStartPreferenceDialogFragment.kt index ddfecaa8c..b7f33cdff 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/DayStartPreferenceDialogFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/DayStartPreferenceDialogFragment.kt @@ -33,7 +33,7 @@ class DayStartPreferenceDialogFragment : PreferenceDialogFragmentCompat() { return lastHour.toString() + ":00" } - override fun onCreateDialogView(context: Context?): View { + override fun onCreateDialogView(context: Context): View { val wrapper = LinearLayout(context) wrapper.orientation = LinearLayout.VERTICAL picker = TimePicker(context) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/EmailNotificationsPreferencesFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/EmailNotificationsPreferencesFragment.kt index 7d81ddb33..0e1910c6c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/EmailNotificationsPreferencesFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/EmailNotificationsPreferencesFragment.kt @@ -19,12 +19,12 @@ class EmailNotificationsPreferencesFragment : BasePreferencesFragment(), SharedP override fun onResume() { super.onResume() - preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this) + preferenceScreen.sharedPreferences?.registerOnSharedPreferenceChangeListener(this) } override fun onPause() { super.onPause() - preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) + preferenceScreen.sharedPreferences?.unregisterOnSharedPreferenceChangeListener(this) } override fun setupPreferences() { /* no-on */ } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PreferencesFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PreferencesFragment.kt index 1c289f462..6702d0374 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PreferencesFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PreferencesFragment.kt @@ -62,16 +62,16 @@ class PreferencesFragment : BasePreferencesFragment(), SharedPreferences.OnShare override fun setupPreferences() { timePreference = findPreference("reminder_time") as? TimePreference - val useReminder = preferenceManager.sharedPreferences.getBoolean("use_reminder", false) - timePreference?.isEnabled = useReminder + val useReminder = preferenceManager.sharedPreferences?.getBoolean("use_reminder", false) + timePreference?.isEnabled = useReminder ?: false pushNotificationsPreference = findPreference("pushNotifications") as? PreferenceScreen - val usePushNotifications = preferenceManager.sharedPreferences.getBoolean("usePushNotifications", true) - pushNotificationsPreference?.isEnabled = usePushNotifications + val usePushNotifications = preferenceManager.sharedPreferences?.getBoolean("usePushNotifications", true) + pushNotificationsPreference?.isEnabled = usePushNotifications ?: false emailNotificationsPreference = findPreference("emailNotifications") as? PreferenceScreen - val useEmailNotifications = preferenceManager.sharedPreferences.getBoolean("useEmailNotifications", true) - emailNotificationsPreference?.isEnabled = useEmailNotifications + val useEmailNotifications = preferenceManager.sharedPreferences?.getBoolean("useEmailNotifications", true) + emailNotificationsPreference?.isEnabled = useEmailNotifications ?: false classSelectionPreference = findPreference("choose_class") @@ -80,7 +80,7 @@ class PreferencesFragment : BasePreferencesFragment(), SharedPreferences.OnShare serverUrlPreference = findPreference("server_url") as? ListPreference serverUrlPreference?.isVisible = false - serverUrlPreference?.summary = preferenceManager.sharedPreferences.getString("server_url", "") + serverUrlPreference?.summary = preferenceManager.sharedPreferences?.getString("server_url", "") val themePreference = findPreference("theme_name") as? ListPreference themePreference?.summary = themePreference?.entry ?: "Default" @@ -101,11 +101,11 @@ class PreferencesFragment : BasePreferencesFragment(), SharedPreferences.OnShare override fun onResume() { super.onResume() - preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this) + preferenceManager.sharedPreferences?.registerOnSharedPreferenceChangeListener(this) } override fun onPause() { - preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) + preferenceManager.sharedPreferences?.unregisterOnSharedPreferenceChangeListener(this) super.onPause() } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PushNotificationsPreferencesFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PushNotificationsPreferencesFragment.kt index 4de688c49..97a6eb276 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PushNotificationsPreferencesFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PushNotificationsPreferencesFragment.kt @@ -19,12 +19,12 @@ class PushNotificationsPreferencesFragment : BasePreferencesFragment(), SharedPr override fun onResume() { super.onResume() - preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this) + preferenceScreen.sharedPreferences?.registerOnSharedPreferenceChangeListener(this) } override fun onPause() { super.onPause() - preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) + preferenceScreen.sharedPreferences?.unregisterOnSharedPreferenceChangeListener(this) } override fun setupPreferences() { /* no-on */ } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/TimePreferenceDialogFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/TimePreferenceDialogFragment.kt index b9dc928a5..d7c97b50d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/TimePreferenceDialogFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/TimePreferenceDialogFragment.kt @@ -34,7 +34,7 @@ class TimePreferenceDialogFragment : PreferenceDialogFragmentCompat() { return lastHour.toString() + ":" + String.format(Locale.UK, "%02d", lastMinute) } - override fun onCreateDialogView(context: Context?): View { + override fun onCreateDialogView(context: Context): View { picker = TimePicker(context) picker.setIs24HourView(android.text.format.DateFormat.is24HourFormat(context)) return picker diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillsFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillsFragment.kt index 1451d75c2..cca68dcd0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillsFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillsFragment.kt @@ -23,12 +23,14 @@ import com.habitrpg.android.habitica.ui.activities.SkillTasksActivity import com.habitrpg.android.habitica.ui.adapter.SkillsRecyclerViewAdapter import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator +import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar.Companion.showSnackbar import io.reactivex.rxjava3.core.Flowable import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import javax.inject.Inject class SkillsFragment : BaseMainFragment() { internal var adapter: SkillsRecyclerViewAdapter? = null @@ -36,20 +38,16 @@ class SkillsFragment : BaseMainFragment() { override var binding: FragmentSkillsBinding? = null + @Inject + lateinit var userViewModel: MainUserViewModel + override fun createBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSkillsBinding { return FragmentSkillsBinding.inflate(inflater, container, false) } - override var user: User? = null - set(value) { - field = value - checkUserLoadSkills() - } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { adapter = SkillsRecyclerViewAdapter() adapter?.useSkillEvents?.subscribeWithErrorHandler { onSkillSelected(it) }?.let { compositeSubscription.add(it) } - checkUserLoadSkills() this.tutorialStepIdentifier = "skills" this.tutorialText = getString(R.string.tutorial_skills) @@ -62,20 +60,21 @@ class SkillsFragment : BaseMainFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - + userViewModel.user.observe(viewLifecycleOwner) { user -> + user?.let { checkUserLoadSkills(it) } + } binding?.recyclerView?.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(activity) binding?.recyclerView?.adapter = adapter binding?.recyclerView?.itemAnimator = SafeDefaultItemAnimator() } - private fun checkUserLoadSkills() { - if (user == null || adapter == null) { + private fun checkUserLoadSkills(user: User) { + if (adapter == null) { return } - adapter?.mana = this.user?.stats?.mp ?: 0.0 - adapter?.level = this.user?.stats?.lvl ?: 0 - adapter?.specialItems = this.user?.items?.special - user?.let { user -> + adapter?.mana = user.stats?.mp ?: 0.0 + adapter?.level = user.stats?.lvl ?: 0 + adapter?.specialItems = user.items?.special Flowable.combineLatest( userRepository.getSkills(user), userRepository.getSpecialItems(user), @@ -89,9 +88,7 @@ class SkillsFragment : BaseMainFragment() { } return@combineLatest allEntries } - ) - .subscribe({ skills -> adapter?.setSkillList(skills) }, RxErrorHandler.handleEmptyError()) - } + ).subscribe({ skills -> adapter?.setSkillList(skills) }, RxErrorHandler.handleEmptyError()) } private fun onSkillSelected(skill: Skill) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxMessageListFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxMessageListFragment.kt index 5abbb4fa1..78f11d71c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxMessageListFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxMessageListFragment.kt @@ -7,6 +7,7 @@ import android.os.Bundle import android.view.* import androidx.appcompat.app.AlertDialog import androidx.fragment.app.viewModels +import androidx.recyclerview.widget.RecyclerView import com.habitrpg.android.habitica.MainNavDirections import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent @@ -88,7 +89,14 @@ class InboxMessageListFragment : BaseMainFragment setReceivingUser(member.username, member.id) activity?.title = member.displayName - chatAdapter = InboxAdapter(user, member) + chatAdapter = InboxAdapter(viewModel.user.value, member) + chatAdapter?.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { + override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { + if (positionStart == 0) { + binding?.recyclerView?.scrollToPosition(0) + } + } + }) viewModel.messages.observe(this.viewLifecycleOwner) { markMessagesAsRead(it) chatAdapter?.submitList(it) @@ -170,7 +178,7 @@ class InboxMessageListFragment : BaseMainFragment) { - socialRepository.markSomePrivateMessagesAsRead(user, messages) + socialRepository.markSomePrivateMessagesAsRead(viewModel.user.value, messages) } private fun startAutoRefreshing() { @@ -215,7 +223,6 @@ class InboxMessageListFragment : BaseMainFragment diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxOverviewFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxOverviewFragment.kt index d42ca5996..ec808c326 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxOverviewFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/InboxOverviewFragment.kt @@ -41,7 +41,7 @@ class InboxOverviewFragment : BaseMainFragment(), androidx override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { this.hidesToolbar = true - compositeSubscription.add(this.socialRepository.markPrivateMessagesRead(user).subscribe({ }, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(this.socialRepository.markPrivateMessagesRead(null).subscribe({ }, RxErrorHandler.handleEmptyError())) return super.onCreateView(inflater, container, savedInstanceState) } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.kt index 1768723bf..226e6a294 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/QuestDetailFragment.kt @@ -26,6 +26,7 @@ import com.habitrpg.android.habitica.modules.AppModule import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils import com.habitrpg.android.habitica.ui.helpers.MarkdownParser +import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import javax.inject.Inject import javax.inject.Named @@ -38,6 +39,8 @@ class QuestDetailFragment : BaseMainFragment() { lateinit var inventoryRepository: InventoryRepository @field:[Inject Named(AppModule.NAMED_USER_ID)] lateinit var userId: String + @Inject + lateinit var userViewModel: MainUserViewModel override var binding: FragmentQuestDetailBinding? = null @@ -101,7 +104,7 @@ class QuestDetailFragment : BaseMainFragment() { compositeSubscription.add( socialRepository.getMember(quest?.leader).subscribe( { member -> - if (context != null && binding?.questLeaderView != null && member != null) { + if (context != null && binding?.questLeaderView != null) { binding?.questLeaderView?.text = context?.getString(R.string.quest_leader_header, member.displayName) } }, @@ -109,6 +112,7 @@ class QuestDetailFragment : BaseMainFragment() { ) ) + val user = userViewModel.user.value if (binding?.questResponseWrapper != null) { if (userId != party?.quest?.leader && user?.party?.quest?.key == group.quest?.key && user?.party?.quest?.RSVPNeeded == false) { binding?.questLeaveButton?.visibility = View.VISIBLE diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt index 7e61daf32..943295fc7 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt @@ -29,6 +29,7 @@ import com.habitrpg.android.habitica.ui.viewHolders.tasks.DailyViewHolder import com.habitrpg.android.habitica.ui.viewHolders.tasks.HabitViewHolder import com.habitrpg.android.habitica.ui.viewHolders.tasks.RewardViewHolder import com.habitrpg.android.habitica.ui.viewHolders.tasks.TodoViewHolder +import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import retrofit2.HttpException @@ -41,6 +42,9 @@ class ChallengeDetailFragment : BaseMainFragment lateinit var challengeRepository: ChallengeRepository @Inject lateinit var socialRepository: SocialRepository + @Inject + lateinit var userViewModel: MainUserViewModel + override var binding: FragmentChallengeDetailBinding? = null @@ -236,7 +240,7 @@ class ChallengeDetailFragment : BaseMainFragment binding?.creatorAvatarview?.setAvatar(creator) binding?.creatorLabel?.tier = creator.contributor?.level ?: 0 binding?.creatorLabel?.username = creator.displayName - isCreator = creator.id == user?.id + isCreator = creator.id == userViewModel.userID this.activity?.invalidateOptionsMenu() } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/NoPartyFragmentFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/NoPartyFragmentFragment.kt index a92ee5ee9..8ca468010 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/NoPartyFragmentFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/NoPartyFragmentFragment.kt @@ -30,6 +30,7 @@ import com.habitrpg.android.habitica.ui.activities.GroupFormActivity import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils import com.habitrpg.android.habitica.ui.helpers.setMarkdown +import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar import javax.inject.Inject import kotlin.math.roundToInt @@ -40,6 +41,8 @@ class NoPartyFragmentFragment : BaseMainFragment() { lateinit var socialRepository: SocialRepository @Inject lateinit var configManager: AppConfigManager + @Inject + lateinit var userViewModel: MainUserViewModel override var binding: FragmentNoPartyBinding? = null @@ -65,7 +68,7 @@ class NoPartyFragmentFragment : BaseMainFragment() { parentFragmentManager.popBackStack() MainNavigationController.navigate( R.id.partyFragment, - bundleOf(Pair("partyID", user?.party?.id)) + bundleOf(Pair("partyID", userViewModel.partyID)) ) }, RxErrorHandler.handleEmptyError() @@ -92,7 +95,7 @@ class NoPartyFragmentFragment : BaseMainFragment() { binding?.usernameTextview?.setOnClickListener { val clipboard = context?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager - val clip = ClipData.newPlainText(context?.getString(R.string.username), user?.username) + val clip = ClipData.newPlainText(context?.getString(R.string.username), userViewModel.username) clipboard?.setPrimaryClip(clip) val activity = activity if (activity != null) { @@ -103,7 +106,7 @@ class NoPartyFragmentFragment : BaseMainFragment() { binding?.createPartyButton?.setOnClickListener { val bundle = Bundle() bundle.putString("groupType", "party") - bundle.putString("leader", user?.id) + bundle.putString("leader", userViewModel.userID) val intent = Intent(activity, GroupFormActivity::class.java) intent.putExtras(bundle) intent.flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT @@ -132,14 +135,15 @@ class NoPartyFragmentFragment : BaseMainFragment() { } } - if ((user?.invitations?.parties?.count() ?: 0) > 0) { + val partyInvitations = userViewModel.partyInvitations + if (partyInvitations.size > 0) { binding?.invitationWrapper?.visibility = View.VISIBLE - user?.invitations?.parties?.let { binding?.invitationsView?.setInvitations(it) } + binding?.invitationsView?.setInvitations(partyInvitations) } else { binding?.invitationWrapper?.visibility = View.GONE } - binding?.usernameTextview?.text = user?.formattedUsername + binding?.usernameTextview?.text = userViewModel.formattedUsername } private val groupFormResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { @@ -164,7 +168,7 @@ class NoPartyFragmentFragment : BaseMainFragment() { } MainNavigationController.navigate( R.id.partyFragment, - bundleOf(Pair("partyID", user?.party?.id)) + bundleOf(Pair("partyID", userViewModel.partyID)) ) }, RxErrorHandler.handleEmptyError() @@ -196,12 +200,11 @@ class NoPartyFragmentFragment : BaseMainFragment() { companion object { - fun newInstance(user: User?): NoPartyFragmentFragment { + fun newInstance(): NoPartyFragmentFragment { val args = Bundle() val fragment = NoPartyFragmentFragment() fragment.arguments = args - fragment.user = user return fragment } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyFragment.kt index 62eea83b3..9aa943813 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyFragment.kt @@ -96,15 +96,11 @@ class PartyFragment : BaseMainFragment() { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { val group = viewModel.getGroupData().value - if (group != null && this.user != null) { - if (group.leaderID == this.user?.id) { - inflater.inflate(R.menu.menu_party_admin, menu) - if (group.memberCount > 1) { - menu.findItem(R.id.menu_guild_leave).isVisible = false - } - } else { - inflater.inflate(R.menu.menu_party, menu) - } + if (viewModel.isLeader) { + inflater.inflate(R.menu.menu_party_admin, menu) + menu.findItem(R.id.menu_guild_leave).isVisible = group?.memberCount != 1 + } else { + inflater.inflate(R.menu.menu_party, menu) } } @@ -159,7 +155,7 @@ class PartyFragment : BaseMainFragment() { private val sendInvitesResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { if (it.resultCode == Activity.RESULT_OK) { val inviteData = HashMap() - inviteData["inviter"] = user?.profile?.name ?: "" + inviteData["inviter"] = viewModel.user.value?.profile?.name ?: "" val emails = it.data?.getStringArrayExtra(GroupInviteActivity.EMAILS_KEY) if (emails != null && emails.isNotEmpty()) { val invites = ArrayList>() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/support/BugFixFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/support/BugFixFragment.kt index 3c63575f8..53e4b2036 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/support/BugFixFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/support/BugFixFragment.kt @@ -20,6 +20,7 @@ import com.habitrpg.android.habitica.helpers.DeviceName import com.habitrpg.android.habitica.helpers.MainNavigationController import com.habitrpg.android.habitica.modules.AppModule import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment +import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.schedulers.Schedulers import javax.inject.Inject @@ -42,6 +43,8 @@ class BugFixFragment : BaseMainFragment() { @Inject lateinit var appConfigManager: AppConfigManager + @Inject + lateinit var userViewModel: MainUserViewModel override fun injectFragment(component: UserComponent) { component.inject(this) @@ -124,8 +127,7 @@ class BugFixFragment : BaseMainFragment() { } bodyOfEmail += newLine + Uri.encode("User ID: $userId") - val user = this.user - if (user != null) { + userViewModel.user.value?.let { user -> bodyOfEmail += newLine + Uri.encode("Level: " + (user.stats?.lvl ?: 0)) + newLine + Uri.encode( "Class: " + (if (user.preferences?.disableClasses == true) "Disabled" else (user.stats?.habitClass diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/MountViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/MountViewHolder.kt index 27aab30e1..8a4e33a69 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/MountViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/MountViewHolder.kt @@ -19,7 +19,7 @@ class MountViewHolder(parent: ViewGroup, private val equipEvents: PublishSubject private var binding: MountOverviewItemBinding = MountOverviewItemBinding.bind(itemView) private var owned: Boolean = false var animal: Mount? = null - private var user: User? = null + private var currentMount: String? = null var resources: Resources = itemView.resources @@ -27,10 +27,10 @@ class MountViewHolder(parent: ViewGroup, private val equipEvents: PublishSubject itemView.setOnClickListener(this) } - fun bind(item: Mount, owned: Boolean, user: User?) { + fun bind(item: Mount, owned: Boolean, currentMount: String?) { animal = item this.owned = owned - this.user = user + this.currentMount = currentMount binding.titleTextView.visibility = View.GONE binding.ownedTextView.visibility = View.GONE val imageName = "stable_Mount_Icon_" + item.animal + "-" + item.color @@ -39,7 +39,7 @@ class MountViewHolder(parent: ViewGroup, private val equipEvents: PublishSubject binding.imageView.alpha = 0.2f } binding.imageView.background = null - binding.activeIndicator.visibility = if (user?.currentMount.equals(animal?.key)) View.VISIBLE else View.GONE + binding.activeIndicator.visibility = if (currentMount.equals(animal?.key)) View.VISIBLE else View.GONE DataBindingUtils.loadImage(itemView.context, imageName) { val drawable = if (owned) it else BitmapDrawable(itemView.context.resources, it.toBitmap().extractAlpha()) binding.imageView.background = drawable @@ -53,7 +53,7 @@ class MountViewHolder(parent: ViewGroup, private val equipEvents: PublishSubject val menu = BottomSheetMenu(itemView.context) menu.setTitle(animal?.text) - val hasCurrentMount = user?.currentMount.equals(animal?.key) + val hasCurrentMount = currentMount.equals(animal?.key) val labelId = if (hasCurrentMount) R.string.unequip else R.string.equip menu.addMenuItem(BottomSheetMenuItem(resources.getString(labelId))) menu.setSelectionRunnable { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/PetViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/PetViewHolder.kt index ff7f5f0dc..f4bb3c0c2 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/PetViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/PetViewHolder.kt @@ -24,7 +24,7 @@ class PetViewHolder(parent: ViewGroup, private val equipEvents: PublishSubject 0 @@ -61,7 +61,7 @@ class PetViewHolder(parent: ViewGroup, private val equipEvents: PublishSubject by lazy { - loadUserFromLocal() - MutableLiveData() - } val user: LiveData by lazy { - _user + userViewModel.user } init { @@ -47,11 +40,6 @@ abstract class BaseViewModel(initializeComponent: Boolean = true) : ViewModel() internal val disposable = CompositeDisposable() - internal fun loadUserFromLocal() { - disposable.add(userRepository.getUser().observeOn(AndroidSchedulers.mainThread()) - .subscribe({ _user.value = it }, RxErrorHandler.handleEmptyError())) - } - fun updateUser(path: String, value: Any) { disposable.add(userRepository.updateUser(path, value) .subscribe({ }, RxErrorHandler.handleEmptyError())) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/GroupViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/GroupViewModel.kt index ceee471c5..81f5a3c27 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/GroupViewModel.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/GroupViewModel.kt @@ -249,7 +249,8 @@ open class GroupViewModel(initializeComponent: Boolean) : BaseViewModel(initiali } fun likeMessage(message: ChatMessage) { - val index = _chatMessages.value?.indexOf(message) ?: return + val index = _chatMessages.value?.indexOf(message) + if (index == null || index < 0) return disposable.add(socialRepository.likeMessage(message).subscribe( { val list = _chatMessages.value?.toMutableList() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainUserViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainUserViewModel.kt new file mode 100644 index 000000000..d921c4694 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainUserViewModel.kt @@ -0,0 +1,62 @@ +package com.habitrpg.android.habitica.ui.viewmodels + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +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 com.habitrpg.android.habitica.models.invitations.GenericInvitation +import com.habitrpg.android.habitica.models.invitations.PartyInvite +import com.habitrpg.android.habitica.models.user.User +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.disposables.CompositeDisposable +import javax.inject.Inject + +class MainUserViewModel(val userRepository: UserRepository) { + + val formattedUsername: CharSequence? + get() = user.value?.formattedUsername + val partyInvitations: List + get() = user.value?.invitations?.parties ?: emptyList() + val userID: String? + get() = user.value?.id + val username: CharSequence + get() = user.value?.username ?: "" + val partyID: String? + get() = user.value?.party?.id + val isUserFainted: Boolean + get() = (user.value?.stats?.hp ?: 1.0) == 0.0 + val isUserInParty: Boolean + get() = user.value?.hasParty == true + + private val _user: MutableLiveData by lazy { + loadUserFromLocal() + MutableLiveData() + } + val user: LiveData by lazy { + _user + } + + init { + HabiticaBaseApplication.userComponent?.inject(this) + } + + fun onCleared() { + userRepository.close() + disposable.clear() + } + + internal val disposable = CompositeDisposable() + + internal fun loadUserFromLocal() { + disposable.add(userRepository.getUser().observeOn(AndroidSchedulers.mainThread()) + .subscribe({ _user.value = it }, RxErrorHandler.handleEmptyError())) + } + + fun updateUser(path: String, value: Any) { + disposable.add(userRepository.updateUser(path, value) + .subscribe({ }, RxErrorHandler.handleEmptyError())) + } +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/inventory/equipment/EquipmentOverviewViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/inventory/equipment/EquipmentOverviewViewModel.kt index ebc740ec1..1d2f454e3 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/inventory/equipment/EquipmentOverviewViewModel.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/inventory/equipment/EquipmentOverviewViewModel.kt @@ -9,6 +9,10 @@ import com.habitrpg.android.habitica.ui.viewmodels.BaseViewModel import javax.inject.Inject class EquipmentOverviewViewModel(savedStateHandle: SavedStateHandle): BaseViewModel() { + val usesAutoEquip: Boolean + get() = user.value?.preferences?.autoEquip == true + val usesCostume: Boolean + get() = user.value?.preferences?.costume == true @Inject lateinit var inventoryRepository: InventoryRepository diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/ExtraLabelPreference.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/ExtraLabelPreference.kt index 54ba9940e..4a5a5cdc7 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/ExtraLabelPreference.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/ExtraLabelPreference.kt @@ -8,7 +8,7 @@ import androidx.preference.PreferenceViewHolder import com.habitrpg.android.habitica.R class ExtraLabelPreference( - context: Context?, + context: Context, attrs: AttributeSet? ) : Preference(context, attrs) { var extraText: String? = null @@ -18,9 +18,9 @@ class ExtraLabelPreference( layoutResource = R.layout.preference_button } - override fun onBindViewHolder(holder: PreferenceViewHolder?) { + override fun onBindViewHolder(holder: PreferenceViewHolder) { super.onBindViewHolder(holder) - val textView = holder?.itemView?.findViewById(R.id.extra_label) + val textView = holder.itemView.findViewById(R.id.extra_label) textView?.text = extraText extraTextColor?.let { textView?.setTextColor(it) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/PetSuggestHatchDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/PetSuggestHatchDialog.kt index 1358370e3..408825289 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/PetSuggestHatchDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/PetSuggestHatchDialog.kt @@ -6,6 +6,7 @@ import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout import androidx.core.graphics.drawable.toBitmap +import com.habitrpg.android.habitica.HabiticaBaseApplication import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.databinding.DialogPetSuggestHatchBinding import com.habitrpg.android.habitica.extensions.subscribeWithErrorHandler @@ -36,6 +37,7 @@ class PetSuggestHatchDialog(context: Context) : HabiticaAlertDialog(context) { val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as? LayoutInflater inflater?.let { binding = DialogPetSuggestHatchBinding.inflate(it) } setAdditionalContentView(binding.root) + HabiticaBaseApplication.userComponent?.inject(this) } fun configure(pet: Animal, egg: Egg?, potion: HatchingPotion?, eggCount: Int, potionCount: Int, hasUnlockedEgg: Boolean, hasUnlockedPotion: Boolean, hasMount: Boolean) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt index 95dd40dbf..19674690a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt @@ -11,6 +11,7 @@ import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.toDrawable import androidx.core.os.bundleOf import com.google.firebase.analytics.FirebaseAnalytics +import com.habitrpg.android.habitica.HabiticaBaseApplication import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.InventoryRepository @@ -319,6 +320,7 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop } private fun buyItem(quantity: Int) { + val application = ownerActivity?.application as? HabiticaBaseApplication FirebaseAnalytics.getInstance(context).logEvent( "item_purchased", bundleOf( @@ -373,7 +375,7 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop "hourglasses" -> ContextCompat.getColor(context, R.color.text_brand) else -> 0 } - (ownerActivity as? SnackbarActivity)?.showSnackbar( + ((application?.currentActivity?.get() ?: getActivity() ?: ownerActivity) as? SnackbarActivity)?.showSnackbar( content = text, rightIcon = priceLabel.compoundDrawables[0], rightTextColor = rightTextColor, diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/yesterdailies/YesterdailyDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/yesterdailies/YesterdailyDialog.kt index 2ec30a1ce..2f075e230 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/yesterdailies/YesterdailyDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/yesterdailies/YesterdailyDialog.kt @@ -158,7 +158,8 @@ class YesterdailyDialog private constructor(context: Context, private val userRe private fun configureTaskView(taskView: View, task: Task) { val completed = !task.isDisplayedActive - val checkmark = taskView.findViewById(R.id.checkmark) + val checkmark = taskView.findViewById(R.id.checkmark) + checkmark?.drawable?.setTint(ContextCompat.getColor(context, R.color.gray_400)) val checkboxHolder = taskView.findViewById(R.id.checkBoxHolder) val checkboxBackground = taskView.findViewById(R.id.checkbox_background) checkmark?.visibility = if (completed) View.VISIBLE else View.GONE diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/ContentDeserializer.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/ContentDeserializer.kt index 815dc0ed2..b413e31dd 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/ContentDeserializer.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/ContentDeserializer.kt @@ -11,14 +11,7 @@ import com.habitrpg.android.habitica.models.ContentGear import com.habitrpg.android.habitica.models.ContentResult import com.habitrpg.android.habitica.models.FAQArticle import com.habitrpg.android.habitica.models.Skill -import com.habitrpg.android.habitica.models.inventory.Customization -import com.habitrpg.android.habitica.models.inventory.Egg -import com.habitrpg.android.habitica.models.inventory.Equipment -import com.habitrpg.android.habitica.models.inventory.Food -import com.habitrpg.android.habitica.models.inventory.HatchingPotion -import com.habitrpg.android.habitica.models.inventory.Mount -import com.habitrpg.android.habitica.models.inventory.Pet -import com.habitrpg.android.habitica.models.inventory.QuestContent +import com.habitrpg.android.habitica.models.inventory.* import io.realm.RealmList import java.lang.reflect.Type @@ -101,6 +94,13 @@ class ContentDeserializer : JsonDeserializer { result.spells.add(skill) } } + + if (obj.has("special")) { + for (entry in obj.get("special").asJsonObject.entrySet()) { + result.special.add(context.deserialize(entry.value, SpecialItem::class.java)) + } + } + result.appearances = context.deserialize(obj.get("appearances"), object : TypeToken>() {}.type) result.backgrounds = context.deserialize(obj.get("backgrounds"), object : TypeToken>() {}.type) val noBackground = Customization() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/OwnedItemListDeserializer.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/OwnedItemListDeserializer.kt index 814063d64..0e8de546d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/OwnedItemListDeserializer.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/OwnedItemListDeserializer.kt @@ -13,10 +13,12 @@ class OwnedItemListDeserializer : JsonDeserializer> { val entrySet = json?.asJsonObject?.entrySet() if (entrySet != null) { for (entry in entrySet) { - val item = OwnedItem() - item.key = entry.key - item.numberOwned = entry.value.asInt - ownedItems.add(item) + if (entry.value.isJsonPrimitive){ + val item = OwnedItem() + item.key = entry.key + item.numberOwned = entry.value.asInt + ownedItems.add(item) + } } } return ownedItems diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/UserDeserializer.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/UserDeserializer.kt index 186339f11..a7eee286a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/UserDeserializer.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/UserDeserializer.kt @@ -99,8 +99,7 @@ class UserDeserializer : JsonDeserializer { item.key = "inventory_present" item.userID = user.id item.numberOwned = user.purchased?.plan?.mysteryItemCount ?: 0 - user.items?.special?.ownedItems = RealmList() - user.items?.special?.ownedItems?.add(item) + user.items?.special?.add(item) user.items?.setItemTypes() } if (obj.has("auth")) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/AddTaskWidgetProvider.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/AddTaskWidgetProvider.kt index 9bff91d95..923b83bad 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/AddTaskWidgetProvider.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/AddTaskWidgetProvider.kt @@ -61,7 +61,7 @@ class AddTaskWidgetProvider : BaseWidgetProvider() { } private fun getSelectedTaskType(widgetId: Int): TaskType { - val preferences = PreferenceManager.getDefaultSharedPreferences(this.context) - return TaskType.from(preferences.getString("add_task_widget_$widgetId", TaskType.HABIT.value)) ?: TaskType.HABIT + val preferences = context?.let { PreferenceManager.getDefaultSharedPreferences(it) } + return TaskType.from(preferences?.getString("add_task_widget_$widgetId", TaskType.HABIT.value)) ?: TaskType.HABIT } } diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/models/user/SpecialItemsTest.kt b/Habitica/src/test/java/com/habitrpg/android/habitica/models/user/SpecialItemsTest.kt deleted file mode 100644 index b459b4afd..000000000 --- a/Habitica/src/test/java/com/habitrpg/android/habitica/models/user/SpecialItemsTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.habitrpg.android.habitica.models.user - -import io.kotest.common.ExperimentalKotest -import io.kotest.core.spec.style.WordSpec -import io.kotest.datatest.withData -import io.kotest.matchers.shouldBe - -@ExperimentalKotest -class SpecialItemsTest : WordSpec({ - data class SpecialItemsData(val snowBalls: Int, val seafoam: Int, val shinyseed: Int, val spookySparkles: Int) - lateinit var items: SpecialItems - beforeEach { - items = SpecialItems() - } - "hasSpecialItems" should { - "false if none are owned" { - items.hasSpecialItems shouldBe false - } - "true if any are owned" { - items.snowball = 4 - items.hasSpecialItems shouldBe true - } - withData( - SpecialItemsData(1, 0, 0, 0), - SpecialItemsData(0, 1, 0, 0), - SpecialItemsData(0, 0, 1, 0), - SpecialItemsData(0, 0, 0, 1), - SpecialItemsData(1, 3, 4, 8) - ) { (snowballs, seafoam, shinyseeds, spookySparkles) -> - items.snowball = snowballs - items.seafoam = seafoam - items.shinySeed = shinyseeds - items.spookySparkles = spookySparkles - items.hasSpecialItems shouldBe true - } - } -})