diff --git a/Habitica/build.gradle b/Habitica/build.gradle index 3f8a4662e..3867f06ae 100644 --- a/Habitica/build.gradle +++ b/Habitica/build.gradle @@ -149,7 +149,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 2946 + versionCode 2950 versionName "3.2.3" } diff --git a/Habitica/res/drawable-hdpi/survey_art_left.png b/Habitica/res/drawable-hdpi/survey_art_left.png index 80e64d7e0..7f69af4c8 100644 Binary files a/Habitica/res/drawable-hdpi/survey_art_left.png and b/Habitica/res/drawable-hdpi/survey_art_left.png differ diff --git a/Habitica/res/drawable-hdpi/survey_art_right.png b/Habitica/res/drawable-hdpi/survey_art_right.png index bc1a963c7..1d970d864 100644 Binary files a/Habitica/res/drawable-hdpi/survey_art_right.png and b/Habitica/res/drawable-hdpi/survey_art_right.png differ diff --git a/Habitica/res/drawable-mdpi/survey_art_left.png b/Habitica/res/drawable-mdpi/survey_art_left.png index e09a7d9fb..bd15e885e 100644 Binary files a/Habitica/res/drawable-mdpi/survey_art_left.png and b/Habitica/res/drawable-mdpi/survey_art_left.png differ diff --git a/Habitica/res/drawable-mdpi/survey_art_right.png b/Habitica/res/drawable-mdpi/survey_art_right.png index 8a4966aa9..810ab2212 100644 Binary files a/Habitica/res/drawable-mdpi/survey_art_right.png and b/Habitica/res/drawable-mdpi/survey_art_right.png differ diff --git a/Habitica/res/drawable-xhdpi/survey_art_left.png b/Habitica/res/drawable-xhdpi/survey_art_left.png index d1190d73a..b03e3e95c 100644 Binary files a/Habitica/res/drawable-xhdpi/survey_art_left.png and b/Habitica/res/drawable-xhdpi/survey_art_left.png differ diff --git a/Habitica/res/drawable-xhdpi/survey_art_right.png b/Habitica/res/drawable-xhdpi/survey_art_right.png index ec72f2ef0..bb0304143 100644 Binary files a/Habitica/res/drawable-xhdpi/survey_art_right.png and b/Habitica/res/drawable-xhdpi/survey_art_right.png differ diff --git a/Habitica/res/drawable-xxhdpi/survey_art_left.png b/Habitica/res/drawable-xxhdpi/survey_art_left.png index 26febfbf1..0ffeb8cdd 100644 Binary files a/Habitica/res/drawable-xxhdpi/survey_art_left.png and b/Habitica/res/drawable-xxhdpi/survey_art_left.png differ diff --git a/Habitica/res/drawable-xxhdpi/survey_art_right.png b/Habitica/res/drawable-xxhdpi/survey_art_right.png index 06a149b76..7bba85a64 100644 Binary files a/Habitica/res/drawable-xxhdpi/survey_art_right.png and b/Habitica/res/drawable-xxhdpi/survey_art_right.png differ diff --git a/Habitica/res/drawable-xxxhdpi/survey_art_left.png b/Habitica/res/drawable-xxxhdpi/survey_art_left.png index bf363bfaa..adb55a840 100644 Binary files a/Habitica/res/drawable-xxxhdpi/survey_art_left.png and b/Habitica/res/drawable-xxxhdpi/survey_art_left.png differ diff --git a/Habitica/res/drawable-xxxhdpi/survey_art_right.png b/Habitica/res/drawable-xxxhdpi/survey_art_right.png index d6ad3a200..6fea27797 100644 Binary files a/Habitica/res/drawable-xxxhdpi/survey_art_right.png and b/Habitica/res/drawable-xxxhdpi/survey_art_right.png differ diff --git a/Habitica/res/layout/dialog_purchase_shopitem_header.xml b/Habitica/res/layout/dialog_purchase_shopitem_header.xml index 03a9d8c89..a83d887a8 100644 --- a/Habitica/res/layout/dialog_purchase_shopitem_header.xml +++ b/Habitica/res/layout/dialog_purchase_shopitem_header.xml @@ -51,8 +51,10 @@ android:gravity="center" style="@style/Body1" android:textSize="12sp" - android:padding="7dp" + android:paddingVertical="7dp" + android:paddingHorizontal="16dp" android:background="@color/brand_300" android:textColor="@color/white" + android:visibility="gone" tools:text="Available until May 6"/> \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt index c669ad5ab..86a6c8bb3 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt @@ -124,9 +124,13 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli localRepository.getSpecialItems(user) override fun useSkill(key: String, target: String?, taskId: String): Flowable { - return zipWithLiveUser(apiClient.useSkill(key, target ?: "", taskId)) { skillResponse, user -> - skillResponse.user?.let { mergeUser(user, it) } - skillResponse + return zipWithLiveUser(apiClient.useSkill(key, target ?: "", taskId)) { response, user -> + response.hpDiff = response.user?.stats?.hp ?: 0 - (user.stats?.hp ?: 0.0) + response.expDiff = response.user?.stats?.exp ?: 0 - (user.stats?.exp ?: 0.0) + response.goldDiff = response.user?.stats?.gp ?: 0 - (user.stats?.gp ?: 0.0) + response.damage = (response.user?.party?.quest?.progress?.up ?: 0.0f) - (user.party?.quest?.progress?.up ?: 0.0f) + response.user?.let { mergeUser(user, it) } + response } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/LevelUpUseCase.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/LevelUpUseCase.kt index f560bfbb2..7ae2c0141 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/LevelUpUseCase.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/LevelUpUseCase.kt @@ -1,5 +1,6 @@ package com.habitrpg.android.habitica.interactors +import android.view.ViewGroup import android.widget.ImageView import androidx.appcompat.app.AppCompatActivity import com.habitrpg.android.habitica.R @@ -13,6 +14,7 @@ import com.habitrpg.android.habitica.models.user.Stats import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.AvatarView import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper +import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import io.reactivex.rxjava3.core.Flowable import org.greenrobot.eventbus.EventBus @@ -27,10 +29,6 @@ constructor(private val soundManager: SoundManager, threadExecutor: ThreadExecut soundManager.loadAndPlayAudio(SoundManager.SoundLevelUp) val suppressedModals = requestValues.user.preferences?.suppressModals - if (suppressedModals?.levelUp == true) { - showClassSelection(requestValues) - return@defer Flowable.just(requestValues.user.stats) - } if (requestValues.newLevel == 10) { val binding = DialogLevelup10Binding.inflate(requestValues.activity.layoutInflater) @@ -52,6 +50,12 @@ constructor(private val soundManager: SoundManager, threadExecutor: ThreadExecut alert.enqueue() } } else { + if (suppressedModals?.levelUp == true) { + HabiticaSnackbar.showSnackbar(requestValues.snackbarTargetView, + requestValues.activity.getString(R.string.levelup_header, requestValues.newLevel), + HabiticaSnackbar.SnackbarDisplayType.SUCCESS, true) + return@defer Flowable.just(requestValues.user.stats) + } val customView = requestValues.activity.layoutInflater.inflate(R.layout.dialog_levelup, null) if (customView != null) { val dialogAvatarView = customView.findViewById(R.id.avatarView) @@ -90,7 +94,7 @@ constructor(private val soundManager: SoundManager, threadExecutor: ThreadExecut .subscribe({ }, RxErrorHandler.handleEmptyError()) } - class RequestValues(val user: User, val level: Int?, val activity: AppCompatActivity) : UseCase.RequestValues { + class RequestValues(val user: User, val level: Int?, val activity: AppCompatActivity, val snackbarTargetView: ViewGroup) : UseCase.RequestValues { val newLevel: Int = level ?: 0 } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/NotifyUserUseCase.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/NotifyUserUseCase.kt index 22ec2ce34..ff013867b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/NotifyUserUseCase.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/NotifyUserUseCase.kt @@ -44,7 +44,7 @@ constructor(threadExecutor: ThreadExecutor, postExecutionThread: PostExecutionTh HabiticaSnackbar.showSnackbar(requestValues.snackbarTargetView, null, null, view, type) } if (requestValues.hasLeveledUp == true) { - return@defer levelUpUseCase.observable(LevelUpUseCase.RequestValues(requestValues.user, requestValues.level, requestValues.context)) + return@defer levelUpUseCase.observable(LevelUpUseCase.RequestValues(requestValues.user, requestValues.level, requestValues.context, requestValues.snackbarTargetView)) .flatMap { userRepository.retrieveUser(true) } .map { it.stats } } else { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/promotions/Survey2021Promotion.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/promotions/Survey2021Promotion.kt index b2b0180c0..c401b749a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/promotions/Survey2021Promotion.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/promotions/Survey2021Promotion.kt @@ -46,6 +46,7 @@ class Survey2021Promotion : HabiticaPromotion(), HabiticaWebPromotion { override fun configurePromoMenuView(view: PromoMenuView) { val context = view.context view.canClose = true + view.binding.closeButton.setColorFilter(ContextCompat.getColor(context, R.color.blue_100)) view.setBackgroundColor(ContextCompat.getColor(context, R.color.blue_1)) view.setTitleText(context.getString(R.string.survey_title)) view.setSubtitleText(context.getString(R.string.survey_menu_description)) 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 719c1e5ff..f4b907b4b 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 @@ -20,7 +20,9 @@ import com.habitrpg.android.habitica.ui.adapter.inventory.StableRecyclerAdapter import com.habitrpg.android.habitica.ui.fragments.BaseFragment import com.habitrpg.android.habitica.ui.helpers.MarginDecoration import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator +import io.reactivex.rxjava3.core.Flowable import io.reactivex.rxjava3.core.Maybe +import io.reactivex.rxjava3.kotlin.combineLatest import io.realm.RealmResults import java.util.* import javax.inject.Inject @@ -138,10 +140,10 @@ class StableRecyclerFragment : BaseFragment() { } else { inventoryRepository.getMounts().firstElement() } - val ownedObservable: Maybe> = if ("pets" == itemType) { - inventoryRepository.getOwnedPets().firstElement() + val ownedObservable: Flowable> = if ("pets" == itemType) { + inventoryRepository.getOwnedPets() } else { - inventoryRepository.getOwnedMounts().firstElement() + inventoryRepository.getOwnedMounts() }.map { val animalMap = mutableMapOf() it.forEach { animal -> @@ -162,9 +164,11 @@ class StableRecyclerFragment : BaseFragment() { .subscribe({ adapter?.setEggs(it) }, RxErrorHandler.handleEmptyError())) - compositeSubscription.add(observable.zipWith(ownedObservable, { unsortedAnimals, ownedAnimals -> - mapAnimals(unsortedAnimals, ownedAnimals) - }).subscribe({ items -> adapter?.setItemList(items) }, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(ownedObservable.combineLatest(observable.toFlowable()) + .map { (ownedAnimals, unsortedAnimals) -> + mapAnimals(unsortedAnimals, ownedAnimals) + } + .subscribe({ items -> adapter?.setItemList(items) }, RxErrorHandler.handleEmptyError())) compositeSubscription.add(inventoryRepository.getOwnedItems(true).subscribe({ adapter?.setOwnedItems(it) }, RxErrorHandler.handleEmptyError())) compositeSubscription.add(inventoryRepository.getMounts().subscribe({ adapter?.setExistingMounts(it) }, RxErrorHandler.handleEmptyError())) compositeSubscription.add(inventoryRepository.getOwnedMounts() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillTasksRecyclerViewFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillTasksRecyclerViewFragment.kt index e1dc6412e..8905713ce 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillTasksRecyclerViewFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillTasksRecyclerViewFragment.kt @@ -62,6 +62,7 @@ class SkillTasksRecyclerViewFragment : BaseFragment super.onResume() var tasks = taskRepository.getTasks(taskType ?: "", userId) + tasks.map { it.where().isEmpty("challengeID").and().isNull("group").findAll() } if (taskType == Task.TYPE_TODO) { tasks = tasks.map { it.where().equalTo("completed", false).findAll() } } 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 f19168cad..d068f8b24 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 @@ -12,6 +12,7 @@ import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.databinding.FragmentSkillsBinding import com.habitrpg.android.habitica.extensions.subscribeWithErrorHandler +import com.habitrpg.android.habitica.helpers.MainNavigationController import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.Skill import com.habitrpg.android.habitica.models.responses.SkillResponse @@ -20,12 +21,17 @@ import com.habitrpg.android.habitica.ui.activities.SkillMemberActivity 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.fragments.social.challenges.ChallengesOverviewFragmentDirections import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator 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 io.reactivex.rxjava3.core.Observable +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch class SkillsFragment : BaseMainFragment() { @@ -125,11 +131,14 @@ class SkillsFragment : BaseMainFragment() { } if (response.damage > 0) { context?.let { - showSnackbar(activity.snackbarContainer, null, - context?.getString(R.string.caused_damage), - BitmapDrawable(resources, HabiticaIconsHelper.imageOfDamage()), - ContextCompat.getColor(it, R.color.green_10), "+" + response.damage, - HabiticaSnackbar.SnackbarDisplayType.SUCCESS) + GlobalScope.launch(context = Dispatchers.Main) { + delay(2000L) + showSnackbar(activity.snackbarContainer, null, + context?.getString(R.string.caused_damage), + BitmapDrawable(resources, HabiticaIconsHelper.imageOfDamage()), + ContextCompat.getColor(it, R.color.green_10), "+%.01f".format(response.damage), + HabiticaSnackbar.SnackbarDisplayType.SUCCESS) + } } } compositeSubscription.add(userRepository.retrieveUser(false).subscribe({ }, RxErrorHandler.handleEmptyError())) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaSnackbar.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaSnackbar.kt index 792af4051..8d47a7f4a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaSnackbar.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaSnackbar.kt @@ -155,29 +155,29 @@ private constructor(parent: ViewGroup, content: View, callback: ContentViewCallb if (isCelebratory) { container.postDelayed({ ParticleSystem(container, 30, ContextCompat.getDrawable(container.context, R.drawable.confetti_blue), 6000) - .setAcceleration(0.00020f, 90) + .setAcceleration(0.00070f, 90) .setRotationSpeed(144f) .setSpeedByComponentsRange(-0.15f, 0.15f, -0.15f, -0.45f) .setFadeOut(200, AccelerateInterpolator()) - .emitWithGravity(container, Gravity.BOTTOM, 7, 2000) + .emitWithGravity(container, Gravity.BOTTOM, 7, 1000) ParticleSystem(container, 30, ContextCompat.getDrawable(container.context, R.drawable.confetti_red), 6000) - .setAcceleration(0.00030f, 90) + .setAcceleration(0.00060f, 90) .setRotationSpeed(144f) .setSpeedByComponentsRange(-0.15f, 0.15f, -0.15f, -0.45f) .setFadeOut(200, AccelerateInterpolator()) - .emitWithGravity(container, Gravity.BOTTOM, 7, 2000) + .emitWithGravity(container, Gravity.BOTTOM, 7, 1000) ParticleSystem(container, 30, ContextCompat.getDrawable(container.context, R.drawable.confetti_yellow), 6000) - .setAcceleration(0.00020f, 90) + .setAcceleration(0.00070f, 90) .setRotationSpeed(144f) .setSpeedByComponentsRange(-0.15f, 0.15f, -0.15f, -0.45f) .setFadeOut(200, AccelerateInterpolator()) - .emitWithGravity(container, Gravity.BOTTOM, 7, 2000) + .emitWithGravity(container, Gravity.BOTTOM, 7, 1000) ParticleSystem(container, 30, ContextCompat.getDrawable(container.context, R.drawable.confetti_purple), 6000) - .setAcceleration(0.00030f, 90) + .setAcceleration(0.00090f, 90) .setRotationSpeed(144f) .setSpeedByComponentsRange(-0.15f, 0.15f, -0.15f, -0.45f) .setFadeOut(200, AccelerateInterpolator()) - .emitWithGravity(container, Gravity.BOTTOM, 7, 2000) + .emitWithGravity(container, Gravity.BOTTOM, 7, 1000) }, 500) } } 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 029c5cb1c..b5bfaf6c2 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 @@ -282,6 +282,7 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop if (shopItem.isTypeGear) { checkGearClass() } + setLimitedTextView() } override fun dismiss() { @@ -445,15 +446,16 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop return@filter shouldWarn }.flatMap { inventoryRepository.getOwnedItems("eggs").firstElement() } } else if (item.purchaseType == "hatchingPotions") { - totalCount = 18 + totalCount = if (item.path?.contains("wacky") == true) { + // Wacky pets can't be raised to mounts, so only need half as many + 9 + } else { + 18 + } maybe = inventoryRepository.getPets().firstElement().filter { val filteredPets = it.filter {pet -> pet.type == "premium" || pet.type == "wacky" } - if (it.firstOrNull()?.type == "wacky") { - // Wacky pets can't be raised to mounts, so only need half as many - totalCount = 9 - } shouldWarn = filteredPets.isNotEmpty() return@filter shouldWarn }.flatMap { inventoryRepository.getOwnedItems("hatchingPotions").firstElement() } @@ -464,21 +466,21 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop if (!shouldWarn) { onResult(-1) } - val remaining = 18 - ownedCount + val remaining = totalCount - ownedCount onResult(max(0, remaining)) }.flatMap { - for (thisItem in it) { - if (thisItem.key == item.key) { - ownedCount += thisItem.numberOwned - } - } - inventoryRepository.getOwnedMounts().firstElement() } - .flatMapPublisher { - for (mount in it) { - if (mount.key?.contains(item.key) == true) { - ownedCount += if (mount.owned) 1 else 0 + for (thisItem in it) { + if (thisItem.key == item.key) { + ownedCount += thisItem.numberOwned + } + } + inventoryRepository.getOwnedMounts().firstElement() + }.flatMapPublisher { + for (mount in it) { + if (mount.key?.contains(item.key) == true) { + ownedCount += if (mount.owned) 1 else 0 + } } - } inventoryRepository.getOwnedPets() }.firstElement().subscribe({ for (pet in it) {