This commit is contained in:
Phillip Thelen 2023-01-09 16:35:04 +01:00
parent a6d16c7e31
commit 4971d4a80a
19 changed files with 125 additions and 40 deletions

View file

@ -179,7 +179,7 @@ android {
buildTypes {
debug {
applicationIdSuffix ".debug"
//applicationIdSuffix ".debug"
debuggable true
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
@ -187,7 +187,8 @@ android {
ext.enableCrashlytics = false
ext.alwaysUpdateBuildId = false
testCoverageEnabled = false
resValue "string", "content_provider", "com.habitrpg.android.habitica.debug.fileprovider"
//resValue "string", "content_provider", "com.habitrpg.android.habitica.debug.fileprovider"
resValue "string", "content_provider", "com.habitrpg.android.habitica.fileprovider"
resValue "string", "app_name", "Habitica Debug"
}
debugIAP {

View file

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View file

@ -8,6 +8,7 @@ import com.google.gson.reflect.TypeToken
import com.habitrpg.android.habitica.BuildConfig
import com.habitrpg.android.habitica.data.ContentRepository
import com.habitrpg.android.habitica.models.WorldState
import com.habitrpg.android.habitica.models.WorldStateEvent
import com.habitrpg.android.habitica.models.promotions.HabiticaPromotion
import com.habitrpg.android.habitica.models.promotions.HabiticaWebPromotion
import com.habitrpg.android.habitica.models.promotions.getHabiticaPromotionFromKey
@ -166,7 +167,8 @@ class AppConfigManager(contentRepository: ContentRepository?): com.habitrpg.comm
return remoteConfig.getBoolean("hideChallenges")
}
fun isBirthday(): Boolean {
return BuildConfig.DEBUG || BuildConfig.TESTING_LEVEL == AppTestingLevel.STAFF.name
fun getBirthdayEvent(): WorldStateEvent? {
val events = ((worldState?.events as? List<WorldStateEvent>) ?: listOf(worldState?.currentEvent))
return events.firstOrNull { it?.eventKey == "birthday10" }
}
}

View file

@ -2,6 +2,7 @@ package com.habitrpg.android.habitica.ui.activities
import android.app.Activity
import android.os.Bundle
import android.text.format.DateFormat
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
@ -52,14 +53,16 @@ import com.android.billingclient.api.ProductDetails
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.InventoryRepository
import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.helpers.MainNavigationController
import com.habitrpg.android.habitica.helpers.PurchaseHandler
import com.habitrpg.android.habitica.helpers.launchCatching
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
import com.habitrpg.android.habitica.ui.views.CurrencyText
import com.habitrpg.common.habitica.extensions.DataBindingUtils
import kotlinx.coroutines.flow.map
import java.util.Date
import javax.inject.Inject
class BirthdayActivity : BaseActivity() {
@ -69,18 +72,22 @@ class BirthdayActivity : BaseActivity() {
lateinit var purchaseHandler: PurchaseHandler
@Inject
lateinit var inventoryRepository: InventoryRepository
@Inject
lateinit var configManager: AppConfigManager
private val price = mutableStateOf("")
private val hasGryphatrice = mutableStateOf(false)
private var gryphatriceProductDetails: ProductDetails? = null
override fun getLayoutResId(): Int? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val event = configManager.getBirthdayEvent()
setContent {
HabiticaTheme {
val user = userViewModel.user.observeAsState()
BirthdayActivityView(user.value, price.value, {
BirthdayActivityView(hasGryphatrice.value, price.value, event?.start ?: Date(), event?.end ?: Date(), {
gryphatriceProductDetails?.let {
purchaseHandler.purchase(this, it)
}
@ -95,6 +102,16 @@ class BirthdayActivity : BaseActivity() {
})
}
}
lifecycleScope.launchCatching {
inventoryRepository.getOwnedPets()
.map { pets ->
pets.firstOrNull { it.key == "Gryphatrice-Jubilant" }
}
.collect {
hasGryphatrice.value = (it?.trained ?: 0) >= 5
}
}
}
override fun injectActivity(component: UserComponent?) {
@ -133,9 +150,11 @@ fun BirthdayTitle(text: String) {
}
}
@Composable
fun BirthdayActivityView(user: User?, price: String, onPurchaseClick: () -> Unit, onGemPurchaseClick: () -> Unit, onEquipClick: () -> Unit) {
fun BirthdayActivityView(hasGryphatrice: Boolean, price: String, startDate: Date, endDate: Date, onPurchaseClick: () -> Unit, onGemPurchaseClick: () -> Unit, onEquipClick: () -> Unit) {
val activity = LocalContext.current as? Activity
val dateFormat = DateFormat.getDateFormat(activity)
val textColor = Color.White
val specialTextColor = colorResource(R.color.yellow_50)
@ -188,7 +207,7 @@ fun BirthdayActivityView(user: User?, price: String, onPurchaseClick: () -> Unit
fontWeight = FontWeight.Bold
)
Text(
"X to Y",
stringResource(R.string.x_to_y, dateFormat.format(startDate), dateFormat.format(endDate)),
fontSize = 12.sp,
color = textColor,
fontWeight = FontWeight.Bold
@ -212,8 +231,8 @@ fun BirthdayActivityView(user: User?, price: String, onPurchaseClick: () -> Unit
BirthdayTitle(stringResource(id = R.string.animated_gryphatrice_pet))
Box(
Modifier
.padding(vertical = 20.dp)
.size(161.dp, 129.dp)
.padding(vertical = 20.dp)
.background(colorResource(R.color.brand_50), RoundedCornerShape(8.dp))
) {
@ -232,8 +251,7 @@ fun BirthdayActivityView(user: User?, price: String, onPurchaseClick: () -> Unit
lineHeight = 20.sp,
modifier = Modifier.padding(bottom = 16.dp)
)
val ownsGryphatrice = false
if (ownsGryphatrice) {
if (hasGryphatrice) {
Text(
stringResource(R.string.thanks_for_support),
fontSize = 12.sp,
@ -355,7 +373,10 @@ fun PotionGrid() {
for (potionGroup in potions) {
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
for (potion in potionGroup) {
Box(Modifier.size(68.dp).background(colorResource(R.color.brand_50), RoundedCornerShape(8.dp))) {
Box(
Modifier
.size(68.dp)
.background(colorResource(R.color.brand_50), RoundedCornerShape(8.dp))) {
AsyncImage(model = DataBindingUtils.BASE_IMAGE_URL + DataBindingUtils.getFullFilename("Pet_HatchingPotion_$potion"), null, Modifier.size(68.dp))
}
}
@ -392,7 +413,7 @@ fun HabiticaButton(
@Preview(device = Devices.PIXEL_4)
@Composable
private fun Preview() {
BirthdayActivityView(null, "", {
BirthdayActivityView(false, "", Date(), Date(), {
}, {}, {})
}

View file

@ -672,6 +672,10 @@ class TaskFormActivity : BaseActivity() {
"assign" to mutableListOf<String>(),
"unassign" to mutableListOf<String>()
)
if (groupID != null && thisTask.group?.groupID == null) {
thisTask.group = TaskGroupPlan()
thisTask.group?.groupID = groupID
}
if (thisTask.isGroupTask) {
for (id in assignedIDs) {
if (thisTask.group?.assignedUsersDetail?.firstOrNull { it.assignedUserID == id } == null) {

View file

@ -8,6 +8,7 @@ import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.models.WorldStateEvent
import com.habitrpg.android.habitica.models.promotions.HabiticaPromotion
import com.habitrpg.android.habitica.ui.menu.HabiticaDrawerItem
import com.habitrpg.android.habitica.ui.viewHolders.ComposableViewHolder
@ -50,6 +51,7 @@ class NavigationDrawerAdapter(tintColor: Int, backgroundTintColor: Int) : Recycl
var promoClosedSubject: ((String) -> Unit)? = null
var activePromo: HabiticaPromotion? = null
var currentEvent: WorldStateEvent? = null
fun getItemWithIdentifier(identifier: String): HabiticaDrawerItem? =
items.find { it.identifier == identifier }
@ -93,8 +95,10 @@ class NavigationDrawerAdapter(tintColor: Int, backgroundTintColor: Int) : Recycl
}
}
getItemViewType(position) == 6 -> {
(holder.itemView as? ComposeView)?.setContent {
BirthdayBanner()
currentEvent?.end?.let {
(holder.itemView as? ComposeView)?.setContent {
BirthdayBanner(it)
}
}
}
}

View file

@ -552,7 +552,7 @@ class NavigationDrawerFragment : DialogFragment() {
items.add(item)
}
if (configManager.isBirthday()) {
configManager.getBirthdayEvent()?.let {
val birthdayItem = HabiticaDrawerItem(R.id.birthdayActivity, SIDEBAR_BIRTHDAY)
birthdayItem.itemViewType = 6
items.add(0, birthdayItem)

View file

@ -3,6 +3,7 @@ package com.habitrpg.android.habitica.ui.fragments.inventory.customization
import android.graphics.PorterDuff
import android.graphics.Typeface
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
@ -70,7 +71,7 @@ class AvatarCustomizationFragment :
internal var adapter: CustomizationRecyclerViewAdapter = CustomizationRecyclerViewAdapter()
internal var layoutManager: FlexboxLayoutManager = FlexboxLayoutManager(activity, ROW)
private val currentFilter = MutableStateFlow(CustomizationFilter(false, type != "background"))
private val currentFilter = MutableStateFlow(CustomizationFilter(false, type == "background"))
private val ownedCustomizations = MutableStateFlow<List<OwnedCustomization>>(emptyList())
override fun onCreateView(
@ -81,7 +82,7 @@ class AvatarCustomizationFragment :
showsBackButton = true
adapter.onCustomizationSelected = { customization ->
lifecycleScope.launchCatching {
if (customization.type == "background") {
if (customization.type == "background" && ownedCustomizations.value.firstOrNull { it.key == customization.identifier } == null) {
userRepository.unlockPath(customization)
userRepository.retrieveUser(false, true, true)
} else {
@ -130,6 +131,12 @@ class AvatarCustomizationFragment :
binding?.recyclerView?.doOnLayout {
adapter.columnCount = it.width / (80.dpToPx(context))
}
lifecycleScope.launchCatching {
currentFilter.collect {
Log.e("NewFilter", it.toString())
}
}
}
override fun onDestroy() {
@ -146,7 +153,7 @@ class AvatarCustomizationFragment :
}
private fun updateFilterIcon() {
if (currentFilter.value.isFiltering != true) {
if (!currentFilter.value.isFiltering) {
filterMenuItem?.setIcon(R.drawable.ic_action_filter_list)
context?.let {
val filterIcon = ContextCompat.getDrawable(it, R.drawable.ic_action_filter_list)
@ -277,14 +284,15 @@ class AvatarCustomizationFragment :
}
fun showFilterDialog() {
val filter = currentFilter.value ?: CustomizationFilter()
val filter = currentFilter.value
val context = context ?: return
val dialog = HabiticaBottomSheetDialog(context)
val binding = BottomSheetBackgroundsFilterBinding.inflate(layoutInflater)
binding.showMeWrapper.check(if (filter.onlyPurchased) R.id.show_purchased_button else R.id.show_all_button)
binding.showMeWrapper.setOnCheckedChangeListener { _, checkedId ->
filter.onlyPurchased = checkedId == R.id.show_purchased_button
currentFilter.value = filter
val newFilter = filter.copy()
newFilter.onlyPurchased = checkedId == R.id.show_purchased_button
currentFilter.value = newFilter
}
binding.clearButton.setOnClickListener {
currentFilter.value = CustomizationFilter(false, type != "background")
@ -293,8 +301,9 @@ class AvatarCustomizationFragment :
if (type == "background") {
binding.sortByWrapper.check(if (filter.ascending) R.id.oldest_button else R.id.newest_button)
binding.sortByWrapper.setOnCheckedChangeListener { _, checkedId ->
filter.ascending = checkedId == R.id.oldest_button
currentFilter.value = filter
val newFilter = filter.copy()
newFilter.ascending = checkedId == R.id.oldest_button
currentFilter.value = newFilter
}
configureMonthFilterButton(binding.januaryButton, 1, filter)
configureMonthFilterButton(binding.febuaryButton, 2, filter)
@ -324,14 +333,15 @@ class AvatarCustomizationFragment :
button.isChecked = filter.months.contains(identifier)
button.text
button.setOnCheckedChangeListener { _, isChecked ->
if (!isChecked && filter.months.contains(identifier)) {
val newFilter = filter.copy()
if (!isChecked && newFilter.months.contains(identifier)) {
button.typeface = Typeface.create("sans-serif", Typeface.NORMAL)
filter.months.remove(identifier)
} else if (isChecked && !filter.months.contains(identifier)) {
newFilter.months.remove(identifier)
} else if (isChecked && !newFilter.months.contains(identifier)) {
button.typeface = Typeface.create("sans-serif-medium", Typeface.NORMAL)
filter.months.add(identifier)
newFilter.months.add(identifier)
}
currentFilter.value = filter
currentFilter.value = newFilter
}
}
}

View file

@ -16,6 +16,7 @@ import com.habitrpg.android.habitica.extensions.getAgoString
import com.habitrpg.android.habitica.extensions.setScaledPadding
import com.habitrpg.android.habitica.models.members.Member
import com.habitrpg.android.habitica.models.social.ChatMessage
import com.habitrpg.android.habitica.models.user.Permission
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar
@ -212,7 +213,7 @@ class ChatRecyclerMessageViewHolder(
}
val flagCount = (chatMessage?.flagCount ?: 0)
if (flagCount > 0) {
if (flagCount > 0 && user?.hasPermission(Permission.MODERATOR) == true) {
binding.flagCountTextview.text = if (flagCount == 10) {
context.getString(R.string.shadow_muted_hidden)
} else {

View file

@ -244,7 +244,8 @@ fun AppHeaderView(
"gold",
user?.stats?.gp ?: 0.0,
modifier = Modifier.padding(end = 12.dp),
decimals = 0
decimals = 0,
minForAbbreviation = 10000
)
CurrencyText(
"gems",

View file

@ -23,10 +23,10 @@ fun CurrencyText(
value: Int,
modifier: Modifier = Modifier,
decimals: Int = 0,
minForAbbrevation: Int = 0,
minForAbbreviation: Int = 0,
animated: Boolean = true
) {
CurrencyText(currency = currency, value = value.toDouble(), modifier, decimals, minForAbbrevation, animated)
CurrencyText(currency = currency, value = value.toDouble(), modifier, decimals, minForAbbreviation, animated)
}
@Composable
fun CurrencyText(
@ -34,7 +34,7 @@ fun CurrencyText(
value: Double,
modifier: Modifier = Modifier,
decimals: Int = 0,
minForAbbrevation: Int = 0,
minForAbbreviation: Int = 0,
animated: Boolean = true
) {
val animatedValue = if (animated) animateFloatAsState(
@ -49,7 +49,7 @@ fun CurrencyText(
else -> null
}?.asImageBitmap()?.let { Image(it, null, Modifier.padding(end = 5.dp)) }
Text(
NumberAbbreviator.abbreviate(null, animatedValue, decimals, minForAbbrevation),
NumberAbbreviator.abbreviate(null, animatedValue, decimals, minForAbbreviation),
color = when (currency) {
"gold" -> colorResource(R.color.text_gold)
"gems" -> colorResource(R.color.text_green)

View file

@ -1,5 +1,7 @@
package com.habitrpg.android.habitica.ui.views.promo
import android.os.Handler
import android.os.Looper
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@ -12,6 +14,11 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource
@ -21,10 +28,27 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.extensions.getShortRemainingString
import com.habitrpg.android.habitica.helpers.MainNavigationController
import java.util.Date
@Composable
fun BirthdayBanner() {
fun BirthdayBanner(endDate: Date) {
var value by remember { mutableStateOf(0) }
DisposableEffect(Unit) {
val handler = Handler(Looper.getMainLooper())
val runnable = {
value += 1
}
handler.postDelayed(runnable, 1000)
onDispose {
handler.removeCallbacks(runnable)
}
}
Column(
Modifier
.fillMaxWidth()
@ -59,7 +83,7 @@ fun BirthdayBanner() {
.padding(horizontal = 10.dp)
) {
Text(
stringResource(R.string.ends_in_x).uppercase(),
stringResource(R.string.ends_in_x, endDate.getShortRemainingString()).uppercase(),
color = colorResource(R.color.yellow_50),
fontSize = 12.sp,
fontWeight = FontWeight.Bold

View file

@ -123,7 +123,8 @@ class SubscriptionDetailsView : LinearLayout {
}
val nextHourglassMonth = nextHourglassDate.format(DateTimeFormatter.ofPattern(format))
nextHourglassMonth?.let { binding.nextHourglassTextview.text = it }
binding.nextHourglassContainer.isVisible = true
// TODO: Unhide once we figured out discrepancies.
binding.nextHourglassContainer.isVisible = false
} else {
binding.nextHourglassContainer.isVisible = false
}

View file

@ -177,6 +177,12 @@ class CustomizationDeserializer : JsonDeserializer<List<Customization>> {
customization.identifier = key
}
when (setName) {
"eventBackgrounds" -> {
customization.customizationSetName = "EVENT BACKGROUNDS"
customization.price = 0
customization.setPrice = 0
customization.isBuyable = false
}
"incentiveBackgrounds" -> {
customization.customizationSetName = "PLAIN BACKGROUND SET"
customization.price = 0

View file

@ -16,6 +16,10 @@ android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debugIAP {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}

View file

@ -70,7 +70,7 @@
<item quantity="other">%d Rewards</item>
</plurals>
<plurals name="flagged_count">
<item quantity="one">Flagged %d tim2</item>
<item quantity="one">Flagged %d time</item>
<item quantity="other">Flagged %d times, hidden</item>
</plurals>
<string name="create_task_title">Create a Task</string>

View file

@ -60,5 +60,11 @@ android {
minSdk = 21
targetSdk = 33
}
buildTypes {
release {
}
}
namespace = "com.habitrpg.shared.habitica"
}

View file

@ -1,2 +1,2 @@
NAME=4.1
CODE=4961
CODE=4971