diff --git a/Habitica/res/drawable-hdpi/customization_background.png b/Habitica/res/drawable-hdpi/customization_background.png
new file mode 100644
index 000000000..898b3976f
Binary files /dev/null and b/Habitica/res/drawable-hdpi/customization_background.png differ
diff --git a/Habitica/res/drawable-hdpi/customization_mix.png b/Habitica/res/drawable-hdpi/customization_mix.png
new file mode 100644
index 000000000..eeaa15008
Binary files /dev/null and b/Habitica/res/drawable-hdpi/customization_mix.png differ
diff --git a/Habitica/res/drawable-mdpi/customization_background.png b/Habitica/res/drawable-mdpi/customization_background.png
new file mode 100644
index 000000000..5e7dcae61
Binary files /dev/null and b/Habitica/res/drawable-mdpi/customization_background.png differ
diff --git a/Habitica/res/drawable-mdpi/customization_mix.png b/Habitica/res/drawable-mdpi/customization_mix.png
new file mode 100644
index 000000000..0dd5aa4cf
Binary files /dev/null and b/Habitica/res/drawable-mdpi/customization_mix.png differ
diff --git a/Habitica/res/drawable-xhdpi/customization_background.png b/Habitica/res/drawable-xhdpi/customization_background.png
new file mode 100644
index 000000000..83c6baf54
Binary files /dev/null and b/Habitica/res/drawable-xhdpi/customization_background.png differ
diff --git a/Habitica/res/drawable-xhdpi/customization_mix.png b/Habitica/res/drawable-xhdpi/customization_mix.png
new file mode 100644
index 000000000..e2f14931d
Binary files /dev/null and b/Habitica/res/drawable-xhdpi/customization_mix.png differ
diff --git a/Habitica/res/drawable-xxhdpi/customization_background.png b/Habitica/res/drawable-xxhdpi/customization_background.png
new file mode 100644
index 000000000..b9999cf4d
Binary files /dev/null and b/Habitica/res/drawable-xxhdpi/customization_background.png differ
diff --git a/Habitica/res/drawable-xxhdpi/customization_mix.png b/Habitica/res/drawable-xxhdpi/customization_mix.png
new file mode 100644
index 000000000..1729c7032
Binary files /dev/null and b/Habitica/res/drawable-xxhdpi/customization_mix.png differ
diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index 42969a340..d3b4af9ec 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -1489,6 +1489,10 @@
Beards
Standard Backgrounds
Hair Colors
+ Looking for more?
+ Check out the Customization Shop for even more ways to customize your avatar!
+ You don’t own any of these items
+ Head over to the Customization Shop to browse the many ways you can customize your avatar!
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 0b1c0f755..d7b6b99cb 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
@@ -53,7 +53,8 @@ class UserRepositoryImpl(
override suspend fun syncUserStats(): User? {
val user = apiClient.syncUserStats()
- if (user?.stats?.toNextLevel != null) {
+ if (user != null && (user.stats?.toNextLevel ?: 0) > 1
+ && (user.stats?.maxMP ?: 0) > 1) {
localRepository.saveUser(user)
} else {
retrieveUser(false, true)
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 967cbda67..3ad1ff41c 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
@@ -17,7 +17,10 @@ import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.grid.GridCells
@@ -28,6 +31,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Alignment
@@ -41,6 +45,7 @@ import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -55,11 +60,13 @@ import com.habitrpg.android.habitica.data.InventoryRepository
import com.habitrpg.android.habitica.databinding.BottomSheetBackgroundsFilterBinding
import com.habitrpg.android.habitica.databinding.FragmentComposeBinding
import com.habitrpg.android.habitica.helpers.Analytics
+import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.models.CustomizationFilter
import com.habitrpg.android.habitica.models.inventory.Customization
import com.habitrpg.android.habitica.models.user.OwnedCustomization
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
+import com.habitrpg.android.habitica.ui.helpers.ToolbarColorHelper
import com.habitrpg.android.habitica.ui.theme.colors
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
import com.habitrpg.android.habitica.ui.views.PixelArtView
@@ -67,8 +74,11 @@ import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaBottomSheetDialog
import com.habitrpg.common.habitica.extensions.getThemeColor
import com.habitrpg.common.habitica.extensions.setTintWith
import com.habitrpg.common.habitica.helpers.ExceptionHandler
+import com.habitrpg.common.habitica.helpers.MainNavigationController
import com.habitrpg.common.habitica.helpers.launchCatching
import com.habitrpg.common.habitica.theme.HabiticaTheme
+import com.habitrpg.common.habitica.views.ComposableAvatarView
+import com.habitrpg.shared.habitica.models.Avatar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
@@ -124,6 +134,9 @@ class AvatarCustomizationFragment :
return FragmentComposeBinding.inflate(inflater, container, false)
}
+ @Inject
+ lateinit var configManager: AppConfigManager
+
@Inject
lateinit var customizationRepository: CustomizationRepository
@@ -146,6 +159,7 @@ class AvatarCustomizationFragment :
savedInstanceState: Bundle?
): View? {
showsBackButton = true
+ hidesToolbar = true
val view = super.onCreateView(inflater, container, savedInstanceState)
binding?.composeView?.apply {
@@ -155,7 +169,8 @@ class AvatarCustomizationFragment :
val userSize by viewModel.userSize
val hairColor by viewModel.hairColor
val activeCustomization by viewModel.activeCustomization
- AvatarCustomizationView(viewModel.customizations, userSize, hairColor, stringResource(viewModel.typeNameId), activeCustomization) { customization ->
+ val avatar by userViewModel.user.observeAsState()
+ AvatarCustomizationView(avatar = avatar, configManager = configManager, viewModel.customizations, userSize, hairColor, type, stringResource(viewModel.typeNameId), activeCustomization) { customization ->
lifecycleScope.launchCatching {
if (customization.identifier?.isNotBlank() != true) {
userRepository.useCustomization(type ?: "", category, activeCustomization ?: "")
@@ -217,6 +232,12 @@ class AvatarCustomizationFragment :
} else {
filterMenuItem?.isVisible = false
}
+
+ mainActivity?.toolbar?.let {
+ val color = ContextCompat.getColor(requireContext(), R.color.window_background)
+ ToolbarColorHelper.colorizeToolbar(it, mainActivity, backgroundColor = color)
+ requireActivity().window.statusBarColor = color
+ }
}
private fun updateFilterIcon() {
@@ -397,43 +418,80 @@ class AvatarCustomizationFragment :
}
@Composable
-private fun AvatarCustomizationView(customizations: List, userSize: String, hairColor: String?, typeName: String, activeCustomization: String?, onSelect: (Customization) -> Unit) {
+private fun AvatarCustomizationView(avatar: Avatar?, configManager: AppConfigManager, customizations: List, userSize: String, hairColor: String?, type: String?, typeName: String, activeCustomization: String?, onSelect: (Customization) -> Unit) {
val nestedScrollInterop = rememberNestedScrollInteropConnection()
val totalWidth = LocalConfiguration.current.screenWidthDp.dp
val horizontalPadding = (totalWidth - (84.dp * 3)) / 2
- LazyVerticalGrid(
- columns = GridCells.Adaptive(76.dp),
- horizontalArrangement = Arrangement.Center,
- contentPadding = PaddingValues(horizontal = horizontalPadding),
- modifier = Modifier.nestedScroll(nestedScrollInterop)
- ) {
- item(span = { GridItemSpan(3) }) {
- Text(
- typeName.uppercase(),
- fontSize = 12.sp,
- color = colorResource(id = R.color.text_ternary),
- textAlign = TextAlign.Center,
- modifier = Modifier.padding(10.dp)
+ Column(horizontalAlignment = Alignment.CenterHorizontally) {
+ Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.background(colorResource(R.color.window_background))) {
+ ComposableAvatarView(
+ avatar = avatar, configManager = configManager, modifier = Modifier
+ .padding(vertical = 24.dp)
+ .size(140.dp, 147.dp)
+ )
+ Box(
+ Modifier
+ .background(colorResource(R.color.content_background), RoundedCornerShape(topStart = 22.dp, topEnd = 22.dp))
+ .fillMaxWidth()
+ .height(22.dp)
)
}
- items(customizations) { customization ->
- Box(
- contentAlignment = Alignment.Center,
- modifier = Modifier
- .padding(4.dp)
- .border(if (activeCustomization == customization.identifier) 2.dp else 0.dp, if (activeCustomization == customization.identifier) HabiticaTheme.colors.tintedUiMain else colorResource(R.color.transparent), RoundedCornerShape(8.dp))
- .clip(RoundedCornerShape(8.dp))
- .clickable {
- onSelect(customization)
+ LazyVerticalGrid(
+ columns = GridCells.Adaptive(76.dp),
+ horizontalArrangement = Arrangement.Center,
+ contentPadding = PaddingValues(horizontal = horizontalPadding),
+ modifier = Modifier
+ .nestedScroll(nestedScrollInterop)
+ .background(colorResource(R.color.content_background))
+ ) {
+ item(span = { GridItemSpan(3) }) {
+ Text(
+ typeName.uppercase(),
+ fontSize = 12.sp,
+ fontWeight = FontWeight.Medium,
+ color = colorResource(id = R.color.text_ternary),
+ textAlign = TextAlign.Center,
+ modifier = Modifier.padding(10.dp)
+ )
+ }
+ if (customizations.size > 1) {
+ items(customizations) { customization ->
+ Box(
+ contentAlignment = Alignment.Center,
+ modifier = Modifier
+ .padding(4.dp)
+ .border(if (activeCustomization == customization.identifier) 2.dp else 0.dp, if (activeCustomization == customization.identifier) HabiticaTheme.colors.tintedUiMain else colorResource(R.color.transparent), RoundedCornerShape(8.dp))
+ .clip(RoundedCornerShape(8.dp))
+ .clickable {
+ onSelect(customization)
+ }
+ .background(colorResource(id = R.color.window_background))) {
+ if (customization.identifier.isNullOrBlank() || customization.identifier == "0") {
+ Image(painterResource(R.drawable.empty_slot), contentDescription = null, contentScale = ContentScale.None, modifier = Modifier.size(68.dp))
+ } else {
+ PixelArtView(
+ imageName = customization.getImageName(userSize, hairColor),
+ Modifier.size(68.dp)
+ )
+ }
}
- .background(colorResource(id = R.color.window_background))) {
- if (customization.identifier.isNullOrBlank() || customization.identifier == "0") {
- Image(painterResource(R.drawable.empty_slot), contentDescription = null, contentScale = ContentScale.None, modifier = Modifier.size(68.dp))
- } else {
- PixelArtView(
- imageName = customization.getImageName(userSize, hairColor),
- Modifier.size(68.dp)
+ }
+ }
+ item(span = { GridItemSpan(3) }) {
+ Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(top = 40.dp).clickable {
+ MainNavigationController.navigate(R.id.customizationsShopFragment)
+ }) {
+ Image(
+ painterResource(if (type == "backgrounds") R.drawable.customization_background else R.drawable.customization_mix),
+ null, modifier = Modifier.padding(bottom = 12.dp)
)
+ if (customizations.size <= 1) {
+ Text(stringResource(R.string.customizations_no_owned), fontSize = 13.sp, fontWeight = FontWeight.SemiBold, color = colorResource(R.color.text_secondary))
+ Text(stringResource(R.string.customization_shop_check_out), fontSize = 13.sp, color = colorResource(R.color.text_ternary), textAlign = TextAlign.Center)
+ } else {
+ Text(stringResource(R.string.looking_for_more), fontSize = 13.sp, fontWeight = FontWeight.SemiBold, color = colorResource(R.color.text_secondary))
+ Text(stringResource(R.string.customization_shop_more), fontSize = 13.sp, color = colorResource(R.color.text_ternary), textAlign = TextAlign.Center)
+ }
}
}
}
diff --git a/version.properties b/version.properties
index a25009fd3..f0b3b37ea 100644
--- a/version.properties
+++ b/version.properties
@@ -1,2 +1,2 @@
NAME=4.3.6
-CODE=7101
\ No newline at end of file
+CODE=7181
\ No newline at end of file