FolderView.kt 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package eu.mjdev.desktop.components.file
  2. import androidx.compose.desktop.ui.tooling.preview.Preview
  3. import androidx.compose.foundation.layout.Box
  4. import androidx.compose.foundation.layout.padding
  5. import androidx.compose.runtime.Composable
  6. import androidx.compose.runtime.derivedStateOf
  7. import androidx.compose.runtime.getValue
  8. import androidx.compose.runtime.remember
  9. import androidx.compose.ui.Alignment
  10. import androidx.compose.ui.Modifier
  11. import androidx.compose.ui.unit.Dp
  12. import androidx.compose.ui.unit.DpSize
  13. import androidx.compose.ui.unit.dp
  14. import eu.mjdev.desktop.components.custom.MeasureUnconstrainedView
  15. import eu.mjdev.desktop.components.grid.GridPlaced
  16. import eu.mjdev.desktop.components.grid.base.GridPlacedCells
  17. import eu.mjdev.desktop.components.grid.base.GridPlacedPlacementPolicy
  18. import eu.mjdev.desktop.components.guide.GuideLines
  19. import eu.mjdev.desktop.components.sliding.base.VisibilityState
  20. import eu.mjdev.desktop.components.sliding.base.VisibilityState.Companion.rememberVisibilityState
  21. import eu.mjdev.desktop.data.DesktopFolderItem
  22. import eu.mjdev.desktop.extensions.ColorUtils.alpha
  23. import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
  24. import java.io.File
  25. import kotlin.math.max
  26. // DefaultShellFolder
  27. // ShellFolder
  28. // Clipboard
  29. // XBaseWindow
  30. // XWM
  31. // XWindow
  32. // XWrapperBase
  33. // ShellFolderManager
  34. // X11GraphicsEnvironment
  35. // todo orientation
  36. @Suppress("FunctionName")
  37. @Composable
  38. fun FolderView(
  39. modifier: Modifier = Modifier,
  40. showHidden: Boolean = false,
  41. directoryFirst: Boolean = true,
  42. showHomeFolder: Boolean = false,
  43. iconSpacing: Dp = 2.dp,
  44. iconSize: DpSize = DpSize(128.dp, 128.dp),
  45. path: File? = File("/"),
  46. // orientation: Orientation = Orientation.Vertical, // todo
  47. guideVisibleState: VisibilityState = rememberVisibilityState(false),
  48. ) = withDesktopScope {
  49. val files by rememberFiles(path, api.homeDir, showHidden, directoryFirst, showHomeFolder)
  50. MeasureUnconstrainedView(
  51. viewToMeasure = {
  52. FolderIcon(
  53. modifier = Modifier.padding(iconSpacing),
  54. iconSize = iconSize,
  55. )
  56. }
  57. ) { size ->
  58. val rows = max(1, ((api.containerSize.height / size.height).toInt()))
  59. val columns = max(1, (files.size.div(rows)))
  60. Box(
  61. modifier = modifier,
  62. contentAlignment = Alignment.TopStart
  63. ) {
  64. GridPlaced(
  65. cells = GridPlacedCells(
  66. rowCount = rows,
  67. columnCount = columns
  68. ),
  69. placementPolicy = GridPlacedPlacementPolicy(
  70. mainAxis = GridPlacedPlacementPolicy.MainAxis.VERTICAL,
  71. horizontalDirection = GridPlacedPlacementPolicy.HorizontalDirection.START_END,
  72. verticalDirection = GridPlacedPlacementPolicy.VerticalDirection.TOP_BOTTOM
  73. ),
  74. ) {
  75. files.forEach { file ->
  76. item {
  77. FolderIcon(
  78. modifier = Modifier.padding(iconSpacing),
  79. path = file.path,
  80. customName = file.customName,
  81. iconSize = iconSize,
  82. onDragStart = {
  83. guideVisibleState.show()
  84. },
  85. onDragEnd = {
  86. guideVisibleState.hide()
  87. }
  88. )
  89. }
  90. }
  91. }
  92. GuideLines(
  93. modifier = modifier,
  94. cellSize = size,
  95. color = iconsTintColor.alpha(0.5f),
  96. lineSize = 1.dp,
  97. visible = guideVisibleState.isVisible
  98. )
  99. }
  100. }
  101. }
  102. @Suppress("SimplifyBooleanWithConstants")
  103. @Composable
  104. private fun rememberFiles(
  105. path: File? = null,
  106. homeDir: File? = null,
  107. showHidden: Boolean = true,
  108. directoryFirst: Boolean = true,
  109. showHomeFolder: Boolean = true
  110. ) = remember(path, homeDir, showHidden, directoryFirst, showHomeFolder) {
  111. derivedStateOf {
  112. path?.listFiles()
  113. ?.sorted()
  114. ?.filter { f ->
  115. showHidden == true || (!f.name.startsWith("."))
  116. }
  117. ?.sortedByDescending {
  118. directoryFirst == false || it.extension.isEmpty() // todo isDirectory
  119. }
  120. ?.map { path ->
  121. DesktopFolderItem(path)
  122. }
  123. ?.toMutableList()
  124. ?.apply {
  125. if (showHomeFolder) add(
  126. DesktopFolderItem(
  127. path = homeDir ?: File("/"),
  128. customName = "Home",
  129. priority = 1
  130. )
  131. )
  132. }
  133. ?.sortedByDescending {
  134. it.priority
  135. } ?: emptyList()
  136. }
  137. }
  138. @Preview
  139. @Composable
  140. fun FolderViewPreview() = FolderView()