Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d03bedb9 authored by Fabián Kozynski's avatar Fabián Kozynski
Browse files

Add a PaginatedGridLayout

The layout delegates to other layouts to show each page, as well the
edit mode.

Right now, the delegation is hardcoded in PanelsModule.

Test: atest com.android.systemui.qs.panels
Test: manual
Fixes: 347915821
Flag: com.android.systemui.qs_ui_refactor
Change-Id: I6a0dc3d4b2b56a5f3a41d366706839fe3c393b29
parent f43c3308
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -155,6 +155,7 @@ private fun QuickSettingsLayout(
            viewModel = viewModel.tileGridViewModel,
            modifier =
                Modifier.fillMaxWidth().heightIn(max = QuickSettingsShade.Dimensions.GridMaxHeight),
            viewModel.editModeViewModel::startEditing,
        )
        Button(
            onClick = { viewModel.editModeViewModel.startEditing() },
@@ -169,7 +170,7 @@ object QuickSettingsShade {
    object Dimensions {
        val Padding = 16.dp
        val BrightnessSliderHeight = 64.dp
        val GridMaxHeight = 400.dp
        val GridMaxHeight = 800.dp
    }

    object Transitions {
+62 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.panels.data.repository

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testCase
import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class PaginatedGridRepositoryTest : SysuiTestCase() {
    private val kosmos = testKosmos()

    val underTest = kosmos.paginatedGridRepository

    @Test
    fun rows_followsConfig() =
        with(kosmos) {
            testScope.runTest {
                val rows by collectLastValue(underTest.rows)

                setRowsInConfig(3)
                assertThat(rows).isEqualTo(3)

                setRowsInConfig(6)
                assertThat(rows).isEqualTo(6)
            }
        }

    private fun setRowsInConfig(rows: Int) =
        with(kosmos) {
            testCase.context.orCreateTestableResources.addOverride(
                R.integer.quick_settings_max_rows,
                rows,
            )
            fakeConfigurationRepository.onConfigurationChange()
        }
}
+123 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.panels.ui.compose

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.testScope
import com.android.systemui.qs.panels.data.repository.IconTilesRepository
import com.android.systemui.qs.panels.data.repository.iconTilesRepository
import com.android.systemui.qs.panels.ui.viewmodel.MockTileViewModel
import com.android.systemui.qs.panels.ui.viewmodel.fixedColumnsSizeViewModel
import com.android.systemui.qs.panels.ui.viewmodel.iconTilesViewModel
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class InfiniteGridLayoutTest : SysuiTestCase() {
    private val kosmos =
        testKosmos().apply {
            iconTilesRepository =
                object : IconTilesRepository {
                    override fun isIconTile(spec: TileSpec): Boolean {
                        return spec.spec.startsWith("small")
                    }
                }
        }

    private val underTest =
        with(kosmos) {
            InfiniteGridLayout(
                iconTilesViewModel,
                fixedColumnsSizeViewModel,
            )
        }

    @Test
    fun correctPagination_underOnePage_sameOrder() =
        with(kosmos) {
            testScope.runTest {
                val rows = 3
                val columns = 4

                val tiles =
                    listOf(
                        largeTile(),
                        smallTile(),
                        smallTile(),
                        largeTile(),
                        largeTile(),
                        smallTile()
                    )

                val pages = underTest.splitIntoPages(tiles, rows = rows, columns = columns)

                assertThat(pages).hasSize(1)
                assertThat(pages[0]).isEqualTo(tiles)
            }
        }

    @Test
    fun correctPagination_twoPages_sameOrder() =
        with(kosmos) {
            testScope.runTest {
                val rows = 3
                val columns = 4

                val tiles =
                    listOf(
                        largeTile(),
                        smallTile(),
                        smallTile(),
                        largeTile(),
                        largeTile(),
                        smallTile(),
                        smallTile(),
                        largeTile(),
                        largeTile(),
                        smallTile(),
                        smallTile(),
                        largeTile(),
                    )
                // --- Page 1 ---
                // [L L] [S] [S]
                // [L L] [L L]
                // [S] [S] [L L]
                // --- Page 2 ---
                // [L L] [S] [S]
                // [L L]

                val pages = underTest.splitIntoPages(tiles, rows = rows, columns = columns)

                assertThat(pages).hasSize(2)
                assertThat(pages[0]).isEqualTo(tiles.take(8))
                assertThat(pages[1]).isEqualTo(tiles.drop(8))
            }
        }

    companion object {
        fun largeTile() = MockTileViewModel(TileSpec.create("large"))

        fun smallTile() = MockTileViewModel(TileSpec.create("small"))
    }
}
+81 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.panels.ui.compose

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.qs.panels.shared.model.SizedTile
import com.android.systemui.qs.panels.ui.viewmodel.MockTileViewModel
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class PaginatableGridLayoutTest : SysuiTestCase() {
    @Test
    fun correctRows_gapsAtEnd() {
        val columns = 6

        val sizedTiles =
            listOf(
                largeTile(),
                extraLargeTile(),
                largeTile(),
                smallTile(),
                largeTile(),
            )

        // [L L] [XL XL XL]
        // [L L] [S] [L L]

        val rows = PaginatableGridLayout.splitInRows(sizedTiles, columns)

        assertThat(rows).hasSize(2)
        assertThat(rows[0]).isEqualTo(sizedTiles.take(2))
        assertThat(rows[1]).isEqualTo(sizedTiles.drop(2))
    }

    @Test
    fun correctRows_fullLastRow_noEmptyRow() {
        val columns = 6

        val sizedTiles =
            listOf(
                largeTile(),
                extraLargeTile(),
                smallTile(),
            )

        // [L L] [XL XL XL] [S]

        val rows = PaginatableGridLayout.splitInRows(sizedTiles, columns)

        assertThat(rows).hasSize(1)
        assertThat(rows[0]).isEqualTo(sizedTiles)
    }

    companion object {
        fun extraLargeTile() = SizedTile(MockTileViewModel(TileSpec.create("XLarge")), 3)

        fun largeTile() = SizedTile(MockTileViewModel(TileSpec.create("large")), 2)

        fun smallTile() = SizedTile(MockTileViewModel(TileSpec.create("small")), 1)
    }
}
+125 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.panels.ui.compose

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.testScope
import com.android.systemui.qs.panels.data.repository.IconTilesRepository
import com.android.systemui.qs.panels.data.repository.iconTilesRepository
import com.android.systemui.qs.panels.ui.viewmodel.MockTileViewModel
import com.android.systemui.qs.panels.ui.viewmodel.iconTilesViewModel
import com.android.systemui.qs.panels.ui.viewmodel.partitionedGridViewModel
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.testKosmos
import com.google.common.truth.Truth
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class PartitionedGridLayoutTest : SysuiTestCase() {
    private val kosmos =
        testKosmos().apply {
            iconTilesRepository =
                object : IconTilesRepository {
                    override fun isIconTile(spec: TileSpec): Boolean {
                        return spec.spec.startsWith("small")
                    }
                }
        }

    private val underTest = with(kosmos) { PartitionedGridLayout(partitionedGridViewModel) }

    @Test
    fun correctPagination_underOnePage_partitioned_sameRelativeOrder() =
        with(kosmos) {
            testScope.runTest {
                val rows = 3
                val columns = 4

                val tiles =
                    listOf(
                        largeTile(),
                        smallTile(),
                        smallTile(),
                        largeTile(),
                        largeTile(),
                        smallTile()
                    )
                val (smallTiles, largeTiles) =
                    tiles.partition { iconTilesViewModel.isIconTile(it.spec) }

                // [L L] [L L]
                // [L L]
                // [S] [S] [S]

                val pages = underTest.splitIntoPages(tiles, rows = rows, columns = columns)

                Truth.assertThat(pages).hasSize(1)
                Truth.assertThat(pages[0]).isEqualTo(largeTiles + smallTiles)
            }
        }

    @Test
    fun correctPagination_twoPages_partitioned_sameRelativeOrder() =
        with(kosmos) {
            testScope.runTest {
                val rows = 3
                val columns = 4

                val tiles =
                    listOf(
                        largeTile(),
                        smallTile(),
                        smallTile(),
                        largeTile(),
                        smallTile(),
                        smallTile(),
                        largeTile(),
                        smallTile(),
                        smallTile(),
                    )
                // --- Page 1 ---
                // [L L] [L L]
                // [L L]
                // [S] [S] [S] [S]
                // --- Page 2 ---
                // [S] [S]

                val (smallTiles, largeTiles) =
                    tiles.partition { iconTilesViewModel.isIconTile(it.spec) }

                val pages = underTest.splitIntoPages(tiles, rows = rows, columns = columns)

                val expectedPage0 = largeTiles + smallTiles.take(4)
                val expectedPage1 = smallTiles.drop(4)

                Truth.assertThat(pages).hasSize(2)
                Truth.assertThat(pages[0]).isEqualTo(expectedPage0)
                Truth.assertThat(pages[1]).isEqualTo(expectedPage1)
            }
        }

    companion object {
        fun largeTile() = MockTileViewModel(TileSpec.create("large"))

        fun smallTile() = MockTileViewModel(TileSpec.create("small"))
    }
}
Loading