FolderView.kt 5.0 KB

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