feat: make boards drawer width adaptive by screen class

This commit is contained in:
2026-04-30 12:36:35 -04:00
parent 028c05c0c8
commit b6da868103
6 changed files with 126 additions and 10 deletions
@@ -281,7 +281,7 @@ class BoardsFlowTest {
}
@Test
fun drawerWidthNeverExceedsOneThirdOfScreen() {
fun drawerWidthIsAdaptiveForSmallAndLargeScreens() {
MainActivity.dependencies.apiClientFactory = {
FakeBoardsApiClient(
boards = mutableListOf(BoardSummary("1", "Alpha")),
@@ -292,9 +292,19 @@ class BoardsFlowTest {
val scenario = ActivityScenario.launch(BoardsActivity::class.java)
scenario.onActivity { activity ->
val drawerLayout = activity.findViewById<DrawerLayout>(R.id.boardsDrawerLayout)
val drawerContent = activity.findViewById<View>(R.id.boardsDrawerContent)
val displayWidthPx = activity.resources.displayMetrics.widthPixels
assertTrue(drawerContent.layoutParams.width <= displayWidthPx / 3)
val resources = activity.resources
val breakpointSwDp = resources.getInteger(R.integer.boards_drawer_tablet_breakpoint_sw_dp)
val maxWidthPx = resources.getDimensionPixelSize(R.dimen.boards_drawer_max_width)
val isSmallScreen = resources.configuration.smallestScreenWidthDp < breakpointSwDp
val expectedWidth = if (isSmallScreen) {
drawerLayout.width
} else {
minOf((drawerLayout.width * 2) / 3, maxWidthPx)
}
assertEquals(expectedWidth, drawerContent.layoutParams.width)
}
}
@@ -13,6 +13,7 @@ import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.GravityCompat
import androidx.core.view.doOnLayout
import androidx.drawerlayout.widget.DrawerLayout
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
@@ -40,6 +41,7 @@ import space.hackenslacker.kanbn4droid.app.boards.BoardsRepository
import space.hackenslacker.kanbn4droid.app.boards.BoardsUiEvent
import space.hackenslacker.kanbn4droid.app.boards.BoardsUiState
import space.hackenslacker.kanbn4droid.app.boards.BoardsViewModel
import space.hackenslacker.kanbn4droid.app.boards.BoardsDrawerWidthCalculator
import space.hackenslacker.kanbn4droid.app.boards.DrawerDataErrorCode
import space.hackenslacker.kanbn4droid.app.boarddetail.BoardDetailActivity
import space.hackenslacker.kanbn4droid.app.settings.SettingsDialogFragment
@@ -284,11 +286,18 @@ class BoardsActivity : AppCompatActivity() {
}
private fun applyDrawerWidth() {
val maxWidthPx = resources.getDimensionPixelSize(R.dimen.boards_drawer_max_width)
val displayWidthPx = resources.displayMetrics.widthPixels
val computedWidth = minOf(displayWidthPx / 3, maxWidthPx)
drawerContent.layoutParams = drawerContent.layoutParams.apply {
width = computedWidth
drawerLayout.doOnLayout {
val maxWidthPx = resources.getDimensionPixelSize(R.dimen.boards_drawer_max_width)
val breakpointSwDp = resources.getInteger(R.integer.boards_drawer_tablet_breakpoint_sw_dp)
val computedWidth = BoardsDrawerWidthCalculator.computeWidth(
smallestScreenWidthDp = resources.configuration.smallestScreenWidthDp,
tabletBreakpointSwDp = breakpointSwDp,
windowWidthPx = drawerLayout.width,
maxWidthPx = maxWidthPx,
)
drawerContent.layoutParams = drawerContent.layoutParams.apply {
width = computedWidth
}
}
}
@@ -0,0 +1,15 @@
package space.hackenslacker.kanbn4droid.app.boards
object BoardsDrawerWidthCalculator {
fun computeWidth(
smallestScreenWidthDp: Int,
tabletBreakpointSwDp: Int,
windowWidthPx: Int,
maxWidthPx: Int,
): Int {
if (smallestScreenWidthDp < tabletBreakpointSwDp) {
return windowWidthPx
}
return minOf((windowWidthPx * 2) / 3, maxWidthPx)
}
}
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="boards_drawer_tablet_breakpoint_sw_dp">600</integer>
</resources>
@@ -0,0 +1,78 @@
package space.hackenslacker.kanbn4droid.app.boards
import org.junit.Assert.assertEquals
import org.junit.Test
class BoardsDrawerWidthCalculatorTest {
@Test
fun smallScreenUsesFullWidth() {
val result = BoardsDrawerWidthCalculator.computeWidth(
smallestScreenWidthDp = 411,
tabletBreakpointSwDp = 600,
windowWidthPx = 1080,
maxWidthPx = 900,
)
assertEquals(1080, result)
}
@Test
fun smallScreenUsesFullWidthIgnoringCap() {
val result = BoardsDrawerWidthCalculator.computeWidth(
smallestScreenWidthDp = 411,
tabletBreakpointSwDp = 600,
windowWidthPx = 1080,
maxWidthPx = 320,
)
assertEquals(1080, result)
}
@Test
fun boundaryAtBreakpointUsesLargeRule() {
val result = BoardsDrawerWidthCalculator.computeWidth(
smallestScreenWidthDp = 600,
tabletBreakpointSwDp = 600,
windowWidthPx = 1000,
maxWidthPx = 700,
)
assertEquals(666, result)
}
@Test
fun largeScreenAppliesTwoThirdsWithCap() {
val result = BoardsDrawerWidthCalculator.computeWidth(
smallestScreenWidthDp = 1024,
tabletBreakpointSwDp = 600,
windowWidthPx = 1024,
maxWidthPx = 700,
)
assertEquals(682, result)
}
@Test
fun boundaryBelowBreakpointUsesSmallRule() {
val result = BoardsDrawerWidthCalculator.computeWidth(
smallestScreenWidthDp = 599,
tabletBreakpointSwDp = 600,
windowWidthPx = 1000,
maxWidthPx = 700,
)
assertEquals(1000, result)
}
@Test
fun largeScreenUsesCapWhenTwoThirdsExceedsCap() {
val result = BoardsDrawerWidthCalculator.computeWidth(
smallestScreenWidthDp = 840,
tabletBreakpointSwDp = 600,
windowWidthPx = 840,
maxWidthPx = 560,
)
assertEquals(560, result)
}
}