From b199c2ea73f4c6eb5d8b9554e04758a17debaf9c Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Wed, 11 Jan 2023 15:44:48 +0100 Subject: [PATCH] Improve event display --- Habitica/res/layout/fragment_subscription.xml | 5 ++++ .../android/habitica/api/ApiService.kt | 2 +- .../android/habitica/data/ApiClient.kt | 2 +- .../android/habitica/data/SocialRepository.kt | 4 +-- .../data/implementation/ApiClientImpl.kt | 4 +-- .../implementation/SocialRepositoryImpl.kt | 2 +- .../data/implementation/UserRepositoryImpl.kt | 6 +++- .../habitica/helpers/PurchaseHandler.kt | 12 ++++++-- .../purchases/GemsPurchaseFragment.kt | 18 ++++++++++++ .../purchases/SubscriptionFragment.kt | 18 ++++++++++++ .../ui/views/promo/BirthdayMenuView.kt | 4 +-- .../ui/views/shops/PurchaseDialogContent.kt | 3 +- .../habitica/ui/views/tasks/AssignedView.kt | 13 ++++++++- .../extensions/Application-Extensions.kt | 1 + .../habitica/extensions/DataBindingUtils.kt | 28 +++++++------------ .../common/habitica/views/AvatarView.kt | 6 +++- 16 files changed, 93 insertions(+), 35 deletions(-) diff --git a/Habitica/res/layout/fragment_subscription.xml b/Habitica/res/layout/fragment_subscription.xml index 951b73876..d2d47c673 100644 --- a/Habitica/res/layout/fragment_subscription.xml +++ b/Habitica/res/layout/fragment_subscription.xml @@ -17,6 +17,11 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> + @POST("user/mark-pms-read") - suspend fun markPrivateMessagesRead(): Void + suspend fun markPrivateMessagesRead(): Void? /* Group API */ diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.kt index 3b1c7e948..2f6060b29 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.kt @@ -131,7 +131,7 @@ interface ApiClient { suspend fun disableClasses(): User? - suspend fun markPrivateMessagesRead(): Void? + suspend fun markPrivateMessagesRead() /* Group API */ 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 bf5e37ecf..af0b2674f 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 @@ -18,7 +18,7 @@ interface SocialRepository : BaseRepository { fun getUserGroups(type: String?): Flow> suspend fun retrieveGroupChat(groupId: String): List? - fun getGroupChat(groupId: String): Flow> + fun getGroupChat(groupId: String): Flow> suspend fun markMessagesSeen(seenGroupId: String) @@ -92,7 +92,7 @@ interface SocialRepository : BaseRepository { id: String? = null ): List? - suspend fun markPrivateMessagesRead(user: User?): Void? + suspend fun markPrivateMessagesRead(user: User?) fun markSomePrivateMessagesAsRead(user: User?, messages: List) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt index 3bce8ab70..446bf4c41 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt @@ -499,8 +499,8 @@ class ApiClientImpl( override suspend fun disableClasses(): User? = process { apiService.disableClasses() } - override suspend fun markPrivateMessagesRead(): Void { - return apiService.markPrivateMessagesRead() + override suspend fun markPrivateMessagesRead() { + apiService.markPrivateMessagesRead() } override suspend fun listGroups(type: String): List? { 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 75933a88e..df5c4589b 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 @@ -274,7 +274,7 @@ class SocialRepositoryImpl( return apiClient.findUsernames(username, context, id) } - override suspend fun markPrivateMessagesRead(user: User?): Void? { + override suspend fun markPrivateMessagesRead(user: User?) { if (user?.isManaged == true) { localRepository.modify(user) { it.inbox?.hasUserSeenInbox = true 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 6aeae16c6..cfbad3f3d 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 @@ -20,9 +20,11 @@ import com.habitrpg.android.habitica.models.user.UserQuestStatus import com.habitrpg.android.habitica.proxy.AnalyticsManager import com.habitrpg.shared.habitica.models.responses.TaskDirection import com.habitrpg.shared.habitica.models.tasks.Attribute +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext import java.util.Date import java.util.GregorianCalendar import java.util.concurrent.TimeUnit @@ -65,7 +67,9 @@ class UserRepositoryImpl( if (forced || this.lastSync == null || Date().time - (this.lastSync?.time ?: 0) > 180000) { val user = apiClient.retrieveUser(withTasks) ?: return null lastSync = Date() - localRepository.saveUser(user) + withContext(Dispatchers.Main) { + localRepository.saveUser(user) + } if (withTasks) { val id = user.id val tasksOrder = user.tasksOrder diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/PurchaseHandler.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/PurchaseHandler.kt index 7c8b3b0e3..76d056f4d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/PurchaseHandler.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/PurchaseHandler.kt @@ -426,11 +426,17 @@ class PurchaseHandler( } } + private val displayedConfirmations = mutableListOf() + private fun displayConfirmationDialog(purchase: Purchase, giftedTo: String? = null) { - CoroutineScope(Dispatchers.Main).launch(ExceptionHandler.coroutine()) { + if (displayedConfirmations.contains(purchase.orderId)) { + return + } + displayedConfirmations.add(purchase.orderId) + CoroutineScope(Dispatchers.Main).launchCatching { val application = (context as? HabiticaBaseApplication) - ?: (context.applicationContext as? HabiticaBaseApplication) ?: return@launch - val sku = purchase.products.firstOrNull() ?: return@launch + ?: (context.applicationContext as? HabiticaBaseApplication) ?: return@launchCatching + val sku = purchase.products.firstOrNull() ?: return@launchCatching var title = context.getString(R.string.successful_purchase_generic) val message = when { PurchaseTypes.allSubscriptionNoRenewTypes.contains(sku) -> { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/GemsPurchaseFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/GemsPurchaseFragment.kt index 118eb8552..9cb17712b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/GemsPurchaseFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/GemsPurchaseFragment.kt @@ -6,6 +6,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.EditText +import androidx.compose.foundation.layout.padding +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.unit.dp +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import com.android.billingclient.api.ProductDetails @@ -26,7 +31,9 @@ import com.habitrpg.android.habitica.ui.activities.GiftGemsActivity import com.habitrpg.android.habitica.ui.fragments.BaseFragment import com.habitrpg.android.habitica.ui.fragments.PromoInfoFragment import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard +import com.habitrpg.android.habitica.ui.theme.HabiticaTheme import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.promo.BirthdayBanner import com.habitrpg.common.habitica.extensions.isUsingNightModeResources import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -92,6 +99,17 @@ class GemsPurchaseFragment : BaseFragment() { binding?.promoBanner?.visibility = View.GONE } + val birthdayEventEnd = appConfigManager.getBirthdayEvent()?.end + if (birthdayEventEnd != null) { + binding?.promoComposeView?.setContent { + HabiticaTheme { + BirthdayBanner(endDate = birthdayEventEnd, Modifier.padding(horizontal = 20.dp).clip(HabiticaTheme.shapes.medium) + .padding(bottom = 20.dp)) + } + } + binding?.promoComposeView?.isVisible = true + } + AmplitudeManager.sendNavigationEvent("gem screen") } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/SubscriptionFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/SubscriptionFragment.kt index d9f6b9820..1665a76c0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/SubscriptionFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/SubscriptionFragment.kt @@ -7,6 +7,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.EditText +import androidx.compose.foundation.layout.padding +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.unit.dp +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import com.android.billingclient.api.ProductDetails @@ -26,7 +31,9 @@ import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.activities.GiftSubscriptionActivity import com.habitrpg.android.habitica.ui.fragments.BaseFragment import com.habitrpg.android.habitica.ui.fragments.PromoInfoFragment +import com.habitrpg.android.habitica.ui.theme.HabiticaTheme import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog +import com.habitrpg.android.habitica.ui.views.promo.BirthdayBanner import com.habitrpg.android.habitica.ui.views.subscriptions.SubscriptionOptionView import com.habitrpg.common.habitica.extensions.isUsingNightModeResources import com.habitrpg.common.habitica.extensions.layoutInflater @@ -87,6 +94,17 @@ class SubscriptionFragment : BaseFragment() { binding?.promoBanner?.visibility = View.GONE } + val birthdayEventEnd = appConfigManager.getBirthdayEvent()?.end + if (birthdayEventEnd != null) { + binding?.promoComposeView?.setContent { + HabiticaTheme { + BirthdayBanner(endDate = birthdayEventEnd, Modifier.padding(horizontal = 20.dp).clip(HabiticaTheme.shapes.medium) + .padding(bottom = 10.dp)) + } + } + binding?.promoComposeView?.isVisible = true + } + binding?.refreshLayout?.setOnRefreshListener { refresh() } lifecycleScope.launchCatching { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/promo/BirthdayMenuView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/promo/BirthdayMenuView.kt index d4ba11603..a7da9773f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/promo/BirthdayMenuView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/promo/BirthdayMenuView.kt @@ -33,7 +33,7 @@ import com.habitrpg.android.habitica.helpers.MainNavigationController import java.util.Date @Composable -fun BirthdayBanner(endDate: Date) { +fun BirthdayBanner(endDate: Date, modifier: Modifier = Modifier) { var value by remember { mutableStateOf(0) } DisposableEffect(Unit) { @@ -50,7 +50,7 @@ fun BirthdayBanner(endDate: Date) { } } Column( - Modifier + modifier .fillMaxWidth() .clickable { MainNavigationController.navigate(R.id.birthdayActivity) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogContent.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogContent.kt index c49a79b95..cedab5f2b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogContent.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialogContent.kt @@ -9,7 +9,6 @@ import com.habitrpg.android.habitica.extensions.fromHtml import com.habitrpg.android.habitica.models.inventory.QuestContent import com.habitrpg.android.habitica.models.shops.ShopItem import com.habitrpg.common.habitica.extensions.dpToPx -import com.habitrpg.common.habitica.extensions.loadGif import com.habitrpg.common.habitica.extensions.loadImage import com.habitrpg.common.habitica.views.PixelArtView @@ -29,7 +28,7 @@ abstract class PurchaseDialogContent @JvmOverloads constructor( open fun setItem(item: ShopItem) { if (item.path?.contains("timeTravelBackgrounds") == true) { - imageView.loadGif(item.imageName?.replace("icon_", "")) + imageView.loadImage(item.imageName?.replace("icon_", "")) val params = imageView.layoutParams params.height = 147.dpToPx(context) params.width = 140.dpToPx(context) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/AssignedView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/AssignedView.kt index 18ca09270..839c3cc4f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/AssignedView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/AssignedView.kt @@ -52,6 +52,13 @@ fun AssignedView( color = color, extraContent = { completedAt[assignable.id]?.let { CompletedAt(completedAt = it) } + }, + endContent = { + completedAt[assignable.id]?.let { + if (showEditButton) { + UndoTaskCompletion() + } + } } ) } @@ -80,4 +87,8 @@ fun AssignedView( } } } -} \ No newline at end of file +} + +@Composable +fun UndoTaskCompletion() { +} diff --git a/common/src/main/java/com/habitrpg/common/habitica/extensions/Application-Extensions.kt b/common/src/main/java/com/habitrpg/common/habitica/extensions/Application-Extensions.kt index 363d913e9..e3101625c 100644 --- a/common/src/main/java/com/habitrpg/common/habitica/extensions/Application-Extensions.kt +++ b/common/src/main/java/com/habitrpg/common/habitica/extensions/Application-Extensions.kt @@ -12,6 +12,7 @@ import com.habitrpg.common.habitica.BuildConfig fun Application.setupCoil() { var builder = ImageLoader.Builder(this) .allowHardware(false) + .crossfade(false) .components { if (Build.VERSION.SDK_INT >= 28) { add(ImageDecoderDecoder.Factory()) diff --git a/common/src/main/java/com/habitrpg/common/habitica/extensions/DataBindingUtils.kt b/common/src/main/java/com/habitrpg/common/habitica/extensions/DataBindingUtils.kt index 1a78961a1..a75c17c87 100644 --- a/common/src/main/java/com/habitrpg/common/habitica/extensions/DataBindingUtils.kt +++ b/common/src/main/java/com/habitrpg/common/habitica/extensions/DataBindingUtils.kt @@ -2,6 +2,7 @@ package com.habitrpg.common.habitica.extensions import android.content.Context import android.graphics.PorterDuff +import android.graphics.drawable.Animatable import android.graphics.drawable.Drawable import android.view.View import android.view.animation.Animation @@ -13,7 +14,6 @@ import coil.imageLoader import coil.request.ImageRequest import com.habitrpg.android.habitica.extensions.setTintWith import com.habitrpg.common.habitica.R -import com.habitrpg.common.habitica.extensions.DataBindingUtils.BASE_IMAGE_URL import com.habitrpg.common.habitica.helpers.AppConfigManager import com.habitrpg.common.habitica.views.PixelArtView import java.util.Collections @@ -26,30 +26,22 @@ fun PixelArtView.loadImage(imageName: String?, imageFormat: String? = null) { return } tag = fullname - bitmap = null + setImageDrawable(null) DataBindingUtils.loadImage(context, imageName, imageFormat) { if (tag == fullname) { - bitmap = it.toBitmap() + if (fullname.endsWith("gif")) { + setImageDrawable(it) + if (it is Animatable) { + it.start() + } + } else { + bitmap = it.toBitmap() + } } } } } -fun PixelArtView.loadGif( - imageName: String?, - builder: ImageRequest.Builder.() -> Unit = {} -) { - if (imageName != null) { - val fullname = BASE_IMAGE_URL + DataBindingUtils.getFullFilename(imageName) - val request = ImageRequest.Builder(context) - .data(fullname) - .target(this) - .apply(builder) - .build() - context.imageLoader.enqueue(request) - } -} - object DataBindingUtils { fun loadImage(context: Context, imageName: String, imageResult: (Drawable) -> Unit) { diff --git a/common/src/main/java/com/habitrpg/common/habitica/views/AvatarView.kt b/common/src/main/java/com/habitrpg/common/habitica/views/AvatarView.kt index 4657863e8..69df63be5 100644 --- a/common/src/main/java/com/habitrpg/common/habitica/views/AvatarView.kt +++ b/common/src/main/java/com/habitrpg/common/habitica/views/AvatarView.kt @@ -7,6 +7,7 @@ import android.graphics.Matrix import android.graphics.PointF import android.graphics.Rect import android.graphics.RectF +import android.graphics.drawable.Animatable import android.graphics.drawable.Drawable import android.text.TextUtils import android.util.AttributeSet @@ -170,6 +171,9 @@ class AvatarView : FrameLayout { result.isFilterBitmap = false super.onSuccess(result) imageView.setImageDrawable(result) + if (result is Animatable) { + result.start() + } val bounds = getLayerBounds(layerKey, layerName, result) imageView.imageMatrix = avatarMatrix val layoutParams = imageView.layoutParams as? LayoutParams @@ -288,7 +292,7 @@ class AvatarView : FrameLayout { val hair = prefs.hair if (!hasVisualBuffs) { - if (!TextUtils.isEmpty(prefs.chair)) { + if (prefs.chair?.isNotBlank() == true && prefs.chair != "chair_none") { layerMap[LayerType.CHAIR] = prefs.chair }