diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml
index 96637de..0829d0e 100644
--- a/.idea/appInsightsSettings.xml
+++ b/.idea/appInsightsSettings.xml
@@ -8,7 +8,7 @@
@@ -17,6 +17,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/migrations.xml b/.idea/migrations.xml
new file mode 100644
index 0000000..f8051a6
--- /dev/null
+++ b/.idea/migrations.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index e55c309..efbce73 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,7 @@ DataTable(
}
```
-Draw a paginated table
+Draw a paginated table with fixed size
```kotlin
PaginatedDataTable(
columns = listOf(
@@ -70,7 +70,7 @@ PaginatedDataTable(
Text("Column3")
},
),
- state = rememberPaginatedDataTableState(5),
+ state = rememberPaginatedDataTableState(initialSize = PageSize.FixedSize(5)),
) {
for (rowIndex in 0 until 100) {
row {
@@ -88,3 +88,39 @@ PaginatedDataTable(
}
}
```
+
+
+Draw paginated table with dynamic size (fill available height)
+
+```kotlin
+PaginatedDataTable(
+ columns = listOf(
+ DataColumn {
+ Text("Column1")
+ },
+ DataColumn {
+ Text("Column2")
+ },
+ DataColumn {
+ Text("Column3")
+ },
+ ),
+ state = rememberPaginatedDataTableState(initialSize = PageSize.FillMaxHeight),
+) {
+ for (rowIndex in 0 until 100) {
+ row {
+ onClick = { println("Row clicked: $rowIndex") }
+ cell {
+ Text("Row $rowIndex, column 1")
+ }
+ cell {
+ Text("Row $rowIndex, column 2")
+ }
+ cell {
+ Text("Row $rowIndex, column 3")
+ }
+ }
+ }
+}
+```
+
diff --git a/datatable-material3/src/commonMain/kotlin/com/seanproctor/datatable/material3/PaginatedDataTable.kt b/datatable-material3/src/commonMain/kotlin/com/seanproctor/datatable/material3/PaginatedDataTable.kt
index d56805f..c7c9bd5 100644
--- a/datatable-material3/src/commonMain/kotlin/com/seanproctor/datatable/material3/PaginatedDataTable.kt
+++ b/datatable-material3/src/commonMain/kotlin/com/seanproctor/datatable/material3/PaginatedDataTable.kt
@@ -3,6 +3,7 @@ package com.seanproctor.datatable.material3
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
@@ -12,15 +13,20 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalWindowInfo
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.seanproctor.datatable.DataColumn
import com.seanproctor.datatable.DataTableScope
import com.seanproctor.datatable.paging.BasicPaginatedDataTable
import com.seanproctor.datatable.paging.PaginatedDataTableState
+import com.seanproctor.datatable.paging.rememberPaginatedDataTableState
import com.seanproctor.datatable_material3.generated.resources.Res
import com.seanproctor.datatable_material3.generated.resources.chevron_left
import com.seanproctor.datatable_material3.generated.resources.chevron_right
@@ -55,15 +61,15 @@ fun PaginatedDataTable(
headerBackgroundColor = headerBackgroundColor,
footerBackgroundColor = footerBackgroundColor,
state = state,
- footer = {
+ footer = { pageSize ->
Row(
modifier = Modifier.height(rowHeight).padding(horizontal = 16.dp).fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(16.dp, alignment = Alignment.End),
verticalAlignment = Alignment.CenterVertically,
) {
- val start = min(state.pageIndex * state.pageSize + 1, state.count)
- val end = min(start + state.pageSize - 1, state.count)
- val pageCount = (state.count + state.pageSize - 1) / state.pageSize
+ val start = min(state.pageIndex * pageSize + 1, state.count)
+ val end = min(start + pageSize - 1, state.count)
+ val pageCount = (state.count + pageSize - 1) / pageSize
Text("$start-$end of ${state.count}")
IconButton(
onClick = { state.pageIndex = 0 },
diff --git a/datatable/src/commonMain/kotlin/com/seanproctor/datatable/paging/BasicPaginatedDataTable.kt b/datatable/src/commonMain/kotlin/com/seanproctor/datatable/paging/BasicPaginatedDataTable.kt
index b0946e2..66b6266 100644
--- a/datatable/src/commonMain/kotlin/com/seanproctor/datatable/paging/BasicPaginatedDataTable.kt
+++ b/datatable/src/commonMain/kotlin/com/seanproctor/datatable/paging/BasicPaginatedDataTable.kt
@@ -1,12 +1,25 @@
package com.seanproctor.datatable.paging
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.runtime.*
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import com.seanproctor.datatable.*
+import com.seanproctor.datatable.BasicDataTable
+import com.seanproctor.datatable.CellContentProvider
+import com.seanproctor.datatable.DataColumn
+import com.seanproctor.datatable.DataTableScope
+import com.seanproctor.datatable.DataTableState
+import com.seanproctor.datatable.DefaultCellContentProvider
@Composable
fun BasicPaginatedDataTable(
@@ -19,34 +32,56 @@ fun BasicPaginatedDataTable(
contentPadding: PaddingValues = PaddingValues(horizontal = 16.dp),
headerBackgroundColor: Color = Color.Unspecified,
footerBackgroundColor: Color = Color.Unspecified,
- footer: @Composable () -> Unit = { },
+ footer: @Composable (Int) -> Unit = { },
cellContentProvider: CellContentProvider = DefaultCellContentProvider,
sortColumnIndex: Int? = null,
sortAscending: Boolean = true,
logger: ((String) -> Unit)? = null,
content: DataTableScope.() -> Unit
) {
- BasicDataTable(
- columns = columns,
- modifier = modifier,
- state = remember(state.pageSize, state.pageIndex) { DataTableState() },
- separator = separator,
- headerHeight = headerHeight,
- rowHeight = rowHeight,
- contentPadding = contentPadding,
- headerBackgroundColor = headerBackgroundColor,
- footerBackgroundColor = footerBackgroundColor,
- footer = footer,
- cellContentProvider = cellContentProvider,
- sortColumnIndex = sortColumnIndex,
- sortAscending = sortAscending,
- logger = logger,
+ var pageSize by remember { mutableStateOf(state.pageSize) }
+ val density = LocalDensity.current
+
+ Box(
+ Modifier
+ .fillMaxSize()
+ .onGloballyPositioned { coords ->
+ /**
+ * The table size is calculated to fit the screen height.
+ * This is if pageSize is equal to 'PAGE_SIZE_FIXED_FLAG (-1)'
+ *
+ * Otherwise, the table has a fixed size
+ */
+ if (state.pageSize == PAGE_SIZE_FIXED_FLAG) {
+ val heightPx = coords.size.height.toFloat()
+ val rowHeightPx = with(density) { rowHeight.toPx() }
+ val rows = (heightPx / rowHeightPx).toInt()
+ pageSize = rows - 3
+ }
+ }
) {
- val start = state.pageIndex * state.pageSize
- val scope = PaginatedRowScope(start, start + state.pageSize, this)
- content(scope)
- if (state.count != scope.index) {
- state.count = scope.index
+ BasicDataTable(
+ columns = columns,
+ modifier = modifier,
+ state = remember(pageSize, state.pageIndex) { DataTableState() },
+ separator = separator,
+ headerHeight = headerHeight,
+ rowHeight = rowHeight,
+ contentPadding = contentPadding,
+ headerBackgroundColor = headerBackgroundColor,
+ footerBackgroundColor = footerBackgroundColor,
+ footer = { footer(pageSize) },
+ cellContentProvider = cellContentProvider,
+ sortColumnIndex = sortColumnIndex,
+ sortAscending = sortAscending,
+ logger = logger,
+ ) {
+ val start = state.pageIndex * pageSize
+ val scope = PaginatedRowScope(start, start + pageSize, this)
+ content(scope)
+ if (state.count != scope.index) {
+ state.count = scope.index
+ }
}
}
}
diff --git a/datatable/src/commonMain/kotlin/com/seanproctor/datatable/paging/PaginatedDataTableState.kt b/datatable/src/commonMain/kotlin/com/seanproctor/datatable/paging/PaginatedDataTableState.kt
index ad70c54..a037ff8 100644
--- a/datatable/src/commonMain/kotlin/com/seanproctor/datatable/paging/PaginatedDataTableState.kt
+++ b/datatable/src/commonMain/kotlin/com/seanproctor/datatable/paging/PaginatedDataTableState.kt
@@ -1,9 +1,20 @@
package com.seanproctor.datatable.paging
-import androidx.compose.runtime.*
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+
+
+/**
+ * PAGE_SIZE_FIXED_FLAG (-1) indicates dynamic page size.
+ * This is only used internally for automatic calculation.
+ */
+const val PAGE_SIZE_FIXED_FLAG = -1
interface PaginatedDataTableState {
var pageSize: Int
@@ -33,11 +44,18 @@ private class PaginatedDataTableStateImpl (
@Composable
fun rememberPaginatedDataTableState(
- initialPageSize: Int,
+ initialSize: PageSize,
initialPageIndex: Int = 0,
initialCount: Int = 0,
-): PaginatedDataTableState {
+ ): PaginatedDataTableState {
return rememberSaveable(saver = PaginatedDataTableStateImpl.Saver) {
- PaginatedDataTableStateImpl(initialPageSize, initialPageIndex, initialCount)
+ val pageSizeValue = if (initialSize is PageSize.FixedSize) initialSize.initialPageSize else PAGE_SIZE_FIXED_FLAG
+ PaginatedDataTableStateImpl(pageSizeValue, initialPageIndex, initialCount)
}
-}
\ No newline at end of file
+}
+
+sealed class PageSize {
+ data object FillMaxHeight : PageSize()
+ data class FixedSize(val initialPageSize: Int) : PageSize()
+}
+
diff --git a/demo-common/src/commonMain/kotlin/com/seanproctor/datatable/demo/App.kt b/demo-common/src/commonMain/kotlin/com/seanproctor/datatable/demo/App.kt
index 3d54cf7..6b09282 100644
--- a/demo-common/src/commonMain/kotlin/com/seanproctor/datatable/demo/App.kt
+++ b/demo-common/src/commonMain/kotlin/com/seanproctor/datatable/demo/App.kt
@@ -29,6 +29,7 @@ import com.seanproctor.datatable.TableColumnWidth
import com.seanproctor.datatable.material3.DataTable
import com.seanproctor.datatable.material3.LazyPaginatedDataTable
import com.seanproctor.datatable.material3.PaginatedDataTable
+import com.seanproctor.datatable.paging.PageSize
import com.seanproctor.datatable.paging.rememberPaginatedDataTableState
import io.github.oikvpqya.compose.fastscroller.HorizontalScrollbar
import io.github.oikvpqya.compose.fastscroller.VerticalScrollbar
@@ -135,7 +136,7 @@ fun App(onRowClick: (Int) -> Unit) {
1 -> {
PaginatedDataTable(
columns = columns,
- state = rememberPaginatedDataTableState(5),
+ state = rememberPaginatedDataTableState(initialSize = PageSize.FixedSize(2)),
sortColumnIndex = sortColumnIndex,
sortAscending = sortAscending,
modifier = Modifier.fillMaxWidth().padding(16.dp),
@@ -152,7 +153,7 @@ fun App(onRowClick: (Int) -> Unit) {
else -> {
LazyPaginatedDataTable(
columns = columns,
- state = rememberPaginatedDataTableState(initialPageSize = 5, initialCount = sortedData.size),
+ state = rememberPaginatedDataTableState(initialSize = PageSize.FillMaxHeight, initialCount = sortedData.size),
sortColumnIndex = sortColumnIndex,
sortAscending = sortAscending,
modifier = Modifier.fillMaxWidth().padding(16.dp),