fix various layout issues

This commit is contained in:
Phillip Thelen 2025-02-10 16:54:03 +01:00
parent 5c1b835454
commit be7d5f9a5d
14 changed files with 103 additions and 41 deletions

View file

@ -140,8 +140,7 @@
android:id="@+id/snackbar_container" android:id="@+id/snackbar_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="400dp" android:layout_height="400dp"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true" />
android:paddingBottom="50dp" />
<com.habitrpg.android.habitica.ui.views.navigation.HabiticaBottomNavigationView <com.habitrpg.android.habitica.ui.views.navigation.HabiticaBottomNavigationView
android:id="@+id/bottom_navigation" android:id="@+id/bottom_navigation"

View file

@ -33,6 +33,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout <LinearLayout
android:id="@+id/main_form_content"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

View file

@ -17,6 +17,7 @@
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal" android:orientation="horizontal"
android:background="?colorPrimaryOffset" android:background="?colorPrimaryOffset"
android:clipToPadding="false"
android:baselineAligned="false"> android:baselineAligned="false">
<com.habitrpg.android.habitica.ui.RoundedFrameLayout <com.habitrpg.android.habitica.ui.RoundedFrameLayout
@ -175,5 +176,6 @@
android:id="@+id/recyclerView" android:id="@+id/recyclerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?attr/colorContentBackground" /> android:background="?attr/colorContentBackground"
android:clipToPadding="false"/>
</LinearLayout> </LinearLayout>

View file

@ -9,8 +9,7 @@
android:paddingEnd="0dp" android:paddingEnd="0dp"
android:gravity="center" android:gravity="center"
tools:background="@drawable/snackbar_background_green" tools:background="@drawable/snackbar_background_green"
android:layout_marginBottom="32dp" android:layout_gravity="center_horizontal|bottom"
android:layout_gravity="center_horizontal"
android:elevation="24dp" android:elevation="24dp"
android:clipToPadding="false"> android:clipToPadding="false">
<ImageView <ImageView

View file

@ -2,16 +2,19 @@ package com.habitrpg.android.habitica.ui.activities
import android.graphics.Paint import android.graphics.Paint
import android.graphics.PorterDuff import android.graphics.PorterDuff
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.TextView import android.widget.TextView
import androidx.core.app.NavUtils import androidx.core.app.NavUtils
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.ActivityAdventureGuideBinding import com.habitrpg.android.habitica.databinding.ActivityAdventureGuideBinding
import com.habitrpg.android.habitica.databinding.AdventureGuideItemBinding import com.habitrpg.android.habitica.databinding.AdventureGuideItemBinding
import com.habitrpg.android.habitica.extensions.consumeWindowInsetsAbove30
import com.habitrpg.android.habitica.helpers.Analytics import com.habitrpg.android.habitica.helpers.Analytics
import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
@ -73,6 +76,23 @@ class AdventureGuideActivity : BaseActivity() {
} }
} }
override fun onAttachedToWindow() {
super.onAttachedToWindow()
ViewCompat.setOnApplyWindowInsetsListener(binding.nestedScrollView) { v, insets ->
val bars = insets.getInsets(
WindowInsetsCompat.Type.systemBars()
or WindowInsetsCompat.Type.displayCutout()
)
v.updatePadding(
top = bars.top,
bottom = bars.bottom,
left = bars.left,
right = bars.right
)
consumeWindowInsetsAbove30(insets)
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
return if (item.itemId == android.R.id.home) { return if (item.itemId == android.R.id.home) {
NavUtils.navigateUpFromSameTask(this) NavUtils.navigateUpFromSameTask(this)

View file

@ -15,7 +15,6 @@ import android.view.LayoutInflater
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup.MarginLayoutParams
import androidx.activity.SystemBarStyle import androidx.activity.SystemBarStyle
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@ -24,16 +23,11 @@ import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.ViewGroupCompat
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.android.material.appbar.AppBarLayout
import com.habitrpg.android.habitica.HabiticaApplication import com.habitrpg.android.habitica.HabiticaApplication
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.data.UserRepository import com.habitrpg.android.habitica.data.UserRepository
@ -52,7 +46,6 @@ import com.habitrpg.common.habitica.extensions.isUsingNightModeResources
import com.habitrpg.common.habitica.helpers.ExceptionHandler import com.habitrpg.common.habitica.helpers.ExceptionHandler
import com.habitrpg.common.habitica.helpers.LanguageHelper import com.habitrpg.common.habitica.helpers.LanguageHelper
import com.habitrpg.common.habitica.helpers.launchCatching import com.habitrpg.common.habitica.helpers.launchCatching
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
@ -147,8 +140,13 @@ abstract class BaseActivity : AppCompatActivity() {
findViewById<View>(R.id.appbar)?.let { appbar -> findViewById<View>(R.id.appbar)?.let { appbar ->
val paddingTop = appbar.paddingTop val paddingTop = appbar.paddingTop
ViewCompat.setOnApplyWindowInsetsListener(appbar) { v, windowInsets -> ViewCompat.setOnApplyWindowInsetsListener(appbar) { v, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) val insets = windowInsets.getInsets(
v.updatePadding(top = insets.top + paddingTop) WindowInsetsCompat.Type.systemBars()
+ WindowInsetsCompat.Type.displayCutout()
)
v.updatePadding(top = insets.top + paddingTop,
left = insets.left,
right = insets.right)
consumeWindowInsetsAbove30(windowInsets) consumeWindowInsetsAbove30(windowInsets)
} }
} }

View file

@ -31,10 +31,13 @@ import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.toMutableStateList import androidx.compose.runtime.toMutableStateList
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.children import androidx.core.view.children
import androidx.core.view.forEachIndexed import androidx.core.view.forEachIndexed
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.iterator import androidx.core.view.iterator
import androidx.core.view.updatePadding
import androidx.core.widget.NestedScrollView import androidx.core.widget.NestedScrollView
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
@ -45,6 +48,7 @@ import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.databinding.ActivityTaskFormBinding import com.habitrpg.android.habitica.databinding.ActivityTaskFormBinding
import com.habitrpg.android.habitica.extensions.OnChangeTextWatcher import com.habitrpg.android.habitica.extensions.OnChangeTextWatcher
import com.habitrpg.android.habitica.extensions.addCancelButton import com.habitrpg.android.habitica.extensions.addCancelButton
import com.habitrpg.android.habitica.extensions.consumeWindowInsetsAbove30
import com.habitrpg.android.habitica.helpers.AppConfigManager import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.helpers.TaskAlarmManager import com.habitrpg.android.habitica.helpers.TaskAlarmManager
import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager
@ -221,8 +225,8 @@ class TaskFormActivity : BaseActivity() {
ContextCompat.getColor(this, R.color.white), ContextCompat.getColor(this, R.color.white),
upperTintColor upperTintColor
) )
binding.appbar.setBackgroundColor(upperTintColor)
} }
binding.appbar.setBackgroundColor(upperTintColor)
supportActionBar?.setBackgroundDrawable(ColorDrawable(upperTintColor)) supportActionBar?.setBackgroundDrawable(ColorDrawable(upperTintColor))
binding.upperTextWrapper.setBackgroundColor(upperTintColor) binding.upperTextWrapper.setBackgroundColor(upperTintColor)
@ -427,21 +431,20 @@ class TaskFormActivity : BaseActivity() {
configureForm() configureForm()
} }
override fun onAttachedToWindow() {
super.onAttachedToWindow()
ViewCompat.setOnApplyWindowInsetsListener(binding.mainFormContent) { v, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
v.updatePadding(bottom = insets.bottom)
consumeWindowInsetsAbove30(windowInsets)
}
}
override fun onResume() { override fun onResume() {
checkIfShowNotifLayout() checkIfShowNotifLayout()
super.onResume() super.onResume()
} }
override fun loadTheme(
sharedPreferences: SharedPreferences,
forced: Boolean
) {
super.loadTheme(sharedPreferences, forced)
val upperTintColor =
if (forcedTheme == "taskform") getThemeColor(R.attr.taskFormTint) else getThemeColor(R.attr.colorAccent)
window.statusBarColor = upperTintColor
}
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
if (isCreating) { if (isCreating) {

View file

@ -9,7 +9,6 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout
@ -21,6 +20,7 @@ import com.habitrpg.android.habitica.helpers.SoundManager
import com.habitrpg.android.habitica.ui.activities.MainActivity import com.habitrpg.android.habitica.ui.activities.MainActivity
import com.habitrpg.android.habitica.ui.helpers.ToolbarColorHelper import com.habitrpg.android.habitica.ui.helpers.ToolbarColorHelper
import com.habitrpg.common.habitica.extensions.getThemeColor import com.habitrpg.common.habitica.extensions.getThemeColor
import com.habitrpg.common.habitica.extensions.isUsingNightModeResources
import javax.inject.Inject import javax.inject.Inject
abstract class BaseMainFragment<VB : ViewBinding> : BaseFragment<VB>() { abstract class BaseMainFragment<VB : ViewBinding> : BaseFragment<VB>() {
@ -58,7 +58,7 @@ abstract class BaseMainFragment<VB : ViewBinding> : BaseFragment<VB>() {
windowInsetsController.isAppearanceLightNavigationBars = false windowInsetsController.isAppearanceLightNavigationBars = false
} else { } else {
bottomNavigation?.visibility = View.GONE bottomNavigation?.visibility = View.GONE
windowInsetsController.isAppearanceLightNavigationBars = true windowInsetsController.isAppearanceLightNavigationBars = requireActivity().isUsingNightModeResources()
} }
} }

View file

@ -10,9 +10,11 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.replace
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.android.billingclient.api.ProductDetails import com.android.billingclient.api.ProductDetails
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
@ -20,6 +22,7 @@ import com.habitrpg.android.habitica.data.UserRepository
import com.habitrpg.android.habitica.databinding.FragmentGemPurchaseBinding import com.habitrpg.android.habitica.databinding.FragmentGemPurchaseBinding
import com.habitrpg.android.habitica.extensions.addCancelButton import com.habitrpg.android.habitica.extensions.addCancelButton
import com.habitrpg.android.habitica.extensions.addCloseButton import com.habitrpg.android.habitica.extensions.addCloseButton
import com.habitrpg.android.habitica.extensions.consumeWindowInsetsAbove30
import com.habitrpg.android.habitica.helpers.Analytics import com.habitrpg.android.habitica.helpers.Analytics
import com.habitrpg.android.habitica.helpers.AppConfigManager import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.helpers.PurchaseHandler import com.habitrpg.android.habitica.helpers.PurchaseHandler
@ -124,6 +127,20 @@ class GemsPurchaseFragment : BaseFragment<FragmentGemPurchaseBinding>() {
} }
loadInventory() loadInventory()
binding?.supportTextView?.let {
val paddingBottom = it.paddingBottom
ViewCompat.setOnApplyWindowInsetsListener(it) { v, insets ->
val bars = insets.getInsets(
WindowInsetsCompat.Type.systemBars()
or WindowInsetsCompat.Type.displayCutout()
)
v.updatePadding(
bottom = bars.bottom + paddingBottom,
)
consumeWindowInsetsAbove30(insets)
}
}
Analytics.sendNavigationEvent("gem screen") Analytics.sendNavigationEvent("gem screen")
} }

View file

@ -18,16 +18,20 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.systemBarsIgnoringVisibility
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
@ -119,6 +123,7 @@ fun getTranslatedClassNamePlural(
} }
} }
@OptIn(ExperimentalLayoutApi::class)
@Composable @Composable
fun AppHeaderView( fun AppHeaderView(
user: Avatar?, user: Avatar?,
@ -132,7 +137,8 @@ fun AppHeaderView(
configManager: AppConfigManager? = null configManager: AppConfigManager? = null
) { ) {
val isPlayerOptedOutOfClass = user?.preferences?.disableClasses ?: false val isPlayerOptedOutOfClass = user?.preferences?.disableClasses ?: false
Column(modifier) { Column(modifier
.windowInsetsPadding(WindowInsets.systemBarsIgnoringVisibility)) {
Row { Row {
ComposableAvatarView( ComposableAvatarView(
user, user,

View file

@ -53,7 +53,6 @@ fun Fragment.showAsBottomSheet(content: @Composable (() -> Unit) -> Unit) {
} }
// Helper method // Helper method
@OptIn(ExperimentalLayoutApi::class)
private fun addContentToView( private fun addContentToView(
viewGroup: ViewGroup, viewGroup: ViewGroup,
content: @Composable (() -> Unit) -> Unit content: @Composable (() -> Unit) -> Unit

View file

@ -8,7 +8,6 @@ import android.view.ViewGroup
import android.view.animation.AccelerateInterpolator import android.view.animation.AccelerateInterpolator
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
@ -100,11 +99,11 @@ private constructor(parent: ViewGroup, content: View, callback: ContentViewCallb
) { ) {
content.scaleY = 0f content.scaleY = 0f
content.scaleX = 0f content.scaleX = 0f
ViewCompat.animate(content).scaleY(1f).setDuration(duration.toLong()).startDelay = content.animate().scaleY(1f).setDuration(duration.toLong()).startDelay =
delay.toLong() delay.toLong()
ViewCompat.animate(content).scaleX(1f).setDuration(duration.toLong()).startDelay = content.animate().scaleX(1f).setDuration(duration.toLong()).startDelay =
delay.toLong() delay.toLong()
ViewCompat.animate(content).alpha(1f).setDuration(duration.toLong()).startDelay = content.animate().alpha(1f).setDuration(duration.toLong()).startDelay =
delay.toLong() delay.toLong()
} }
@ -114,11 +113,11 @@ private constructor(parent: ViewGroup, content: View, callback: ContentViewCallb
) { ) {
content.scaleY = 1f content.scaleY = 1f
content.scaleX = 1f content.scaleX = 1f
ViewCompat.animate(content).scaleY(0f).setDuration(duration.toLong()).startDelay = content.animate().scaleY(0f).setDuration(duration.toLong()).startDelay =
delay.toLong() delay.toLong()
ViewCompat.animate(content).scaleX(0f).setDuration(duration.toLong()).startDelay = content.animate().scaleX(0f).setDuration(duration.toLong()).startDelay =
delay.toLong() delay.toLong()
ViewCompat.animate(content).alpha(0f).setDuration(duration.toLong()).startDelay = content.animate().alpha(0f).setDuration(duration.toLong()).startDelay =
delay.toLong() delay.toLong()
} }
} }

View file

@ -113,6 +113,8 @@ fun LabeledBar(
.clip(CircleShape) .clip(CircleShape)
.height(barHeight), .height(barHeight),
trackColor = barColor, trackColor = barColor,
drawStopIndicator = {},
gapSize = -barHeight,
color = color color = color
) )
AnimatedVisibility(visible = !displayCompact) { AnimatedVisibility(visible = !displayCompact) {
@ -179,6 +181,14 @@ private fun Preview() {
maxValue = 50.0, maxValue = 50.0,
displayCompact = compact displayCompact = compact
) )
LabeledBar(
icon = HabiticaIconsHelper.imageOfExperience(),
label = stringResource(id = R.string.XP_default),
color = colorResource(R.color.xpColor),
value = 100.0,
maxValue = 300.0,
displayCompact = compact
)
LabeledBar( LabeledBar(
icon = HabiticaIconsHelper.imageOfExperience(), icon = HabiticaIconsHelper.imageOfExperience(),
label = stringResource(id = R.string.XP_default), label = stringResource(id = R.string.XP_default),

View file

@ -2,12 +2,13 @@ package com.habitrpg.android.habitica.ui.views.dialogs
import android.content.Context import android.content.Context
import android.view.View import android.view.View
import androidx.core.view.WindowCompat import androidx.core.view.ViewCompat
import androidx.core.view.updateLayoutParams import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.internal.ViewUtils.doOnApplyWindowInsets
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.BottomSheetWrapperBinding import com.habitrpg.android.habitica.databinding.BottomSheetWrapperBinding
import com.habitrpg.android.habitica.extensions.consumeWindowInsetsAbove30
open class HabiticaBottomSheetDialog(context: Context) : open class HabiticaBottomSheetDialog(context: Context) :
BottomSheetDialog(context, R.style.SheetDialog) { BottomSheetDialog(context, R.style.SheetDialog) {
@ -15,6 +16,14 @@ open class HabiticaBottomSheetDialog(context: Context) :
init { init {
behavior.peekHeight = context.resources.displayMetrics.heightPixels / 2 behavior.peekHeight = context.resources.displayMetrics.heightPixels / 2
ViewCompat.setOnApplyWindowInsetsListener(wrapperBinding.container) { v, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
v.updatePadding(
left = insets.left,
right = insets.right,
bottom = insets.bottom)
consumeWindowInsetsAbove30(windowInsets)
}
} }
var grabberVisibility: Int var grabberVisibility: Int