TrackInfoDialogSelector.kt 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. package eu.kanade.presentation.manga
  2. import androidx.compose.foundation.layout.Arrangement
  3. import androidx.compose.foundation.layout.Box
  4. import androidx.compose.foundation.layout.BoxScope
  5. import androidx.compose.foundation.layout.Row
  6. import androidx.compose.foundation.layout.RowScope
  7. import androidx.compose.foundation.layout.Spacer
  8. import androidx.compose.foundation.layout.WindowInsets
  9. import androidx.compose.foundation.layout.fillMaxWidth
  10. import androidx.compose.foundation.layout.padding
  11. import androidx.compose.foundation.layout.systemBars
  12. import androidx.compose.foundation.layout.windowInsetsPadding
  13. import androidx.compose.foundation.lazy.rememberLazyListState
  14. import androidx.compose.foundation.selection.selectable
  15. import androidx.compose.foundation.shape.RoundedCornerShape
  16. import androidx.compose.material3.MaterialTheme
  17. import androidx.compose.material3.RadioButton
  18. import androidx.compose.material3.Text
  19. import androidx.compose.material3.TextButton
  20. import androidx.compose.runtime.Composable
  21. import androidx.compose.runtime.getValue
  22. import androidx.compose.runtime.mutableStateOf
  23. import androidx.compose.runtime.remember
  24. import androidx.compose.runtime.setValue
  25. import androidx.compose.ui.Alignment
  26. import androidx.compose.ui.Modifier
  27. import androidx.compose.ui.draw.clip
  28. import androidx.compose.ui.res.stringResource
  29. import androidx.compose.ui.text.style.TextAlign
  30. import androidx.compose.ui.unit.dp
  31. import eu.kanade.presentation.components.ScrollbarLazyColumn
  32. import eu.kanade.presentation.components.WheelDatePicker
  33. import eu.kanade.presentation.components.WheelTextPicker
  34. import eu.kanade.presentation.util.isScrolledToEnd
  35. import eu.kanade.presentation.util.isScrolledToStart
  36. import eu.kanade.presentation.util.minimumTouchTargetSize
  37. import eu.kanade.presentation.util.padding
  38. import eu.kanade.tachiyomi.R
  39. import tachiyomi.presentation.core.components.material.AlertDialogContent
  40. import tachiyomi.presentation.core.components.material.Divider
  41. import java.time.LocalDate
  42. import java.time.format.TextStyle
  43. @Composable
  44. fun TrackStatusSelector(
  45. selection: Int,
  46. onSelectionChange: (Int) -> Unit,
  47. selections: Map<Int, String>,
  48. onConfirm: () -> Unit,
  49. onDismissRequest: () -> Unit,
  50. ) {
  51. BaseSelector(
  52. title = stringResource(R.string.status),
  53. content = {
  54. val state = rememberLazyListState()
  55. ScrollbarLazyColumn(state = state) {
  56. selections.forEach { (key, value) ->
  57. val isSelected = selection == key
  58. item {
  59. Row(
  60. verticalAlignment = Alignment.CenterVertically,
  61. modifier = Modifier
  62. .clip(RoundedCornerShape(8.dp))
  63. .selectable(
  64. selected = isSelected,
  65. onClick = { onSelectionChange(key) },
  66. )
  67. .fillMaxWidth()
  68. .minimumTouchTargetSize(),
  69. ) {
  70. RadioButton(
  71. selected = isSelected,
  72. onClick = null,
  73. )
  74. Text(
  75. text = value,
  76. style = MaterialTheme.typography.bodyLarge.merge(),
  77. modifier = Modifier.padding(start = 24.dp),
  78. )
  79. }
  80. }
  81. }
  82. }
  83. if (!state.isScrolledToStart()) Divider(modifier = Modifier.align(Alignment.TopCenter))
  84. if (!state.isScrolledToEnd()) Divider(modifier = Modifier.align(Alignment.BottomCenter))
  85. },
  86. onConfirm = onConfirm,
  87. onDismissRequest = onDismissRequest,
  88. )
  89. }
  90. @Composable
  91. fun TrackChapterSelector(
  92. selection: Int,
  93. onSelectionChange: (Int) -> Unit,
  94. range: Iterable<Int>,
  95. onConfirm: () -> Unit,
  96. onDismissRequest: () -> Unit,
  97. ) {
  98. BaseSelector(
  99. title = stringResource(R.string.chapters),
  100. content = {
  101. WheelTextPicker(
  102. modifier = Modifier.align(Alignment.Center),
  103. startIndex = selection,
  104. texts = range.map { "$it" },
  105. onSelectionChanged = { onSelectionChange(it) },
  106. )
  107. },
  108. onConfirm = onConfirm,
  109. onDismissRequest = onDismissRequest,
  110. )
  111. }
  112. @Composable
  113. fun TrackScoreSelector(
  114. selection: String,
  115. onSelectionChange: (String) -> Unit,
  116. selections: List<String>,
  117. onConfirm: () -> Unit,
  118. onDismissRequest: () -> Unit,
  119. ) {
  120. BaseSelector(
  121. title = stringResource(R.string.score),
  122. content = {
  123. WheelTextPicker(
  124. modifier = Modifier.align(Alignment.Center),
  125. startIndex = selections.indexOf(selection).coerceAtLeast(0),
  126. texts = selections,
  127. onSelectionChanged = { onSelectionChange(selections[it]) },
  128. )
  129. },
  130. onConfirm = onConfirm,
  131. onDismissRequest = onDismissRequest,
  132. )
  133. }
  134. @Composable
  135. fun TrackDateSelector(
  136. title: String,
  137. minDate: LocalDate?,
  138. maxDate: LocalDate?,
  139. selection: LocalDate,
  140. onSelectionChange: (LocalDate) -> Unit,
  141. onConfirm: () -> Unit,
  142. onRemove: (() -> Unit)?,
  143. onDismissRequest: () -> Unit,
  144. ) {
  145. BaseSelector(
  146. title = title,
  147. content = {
  148. Row(
  149. modifier = Modifier.align(Alignment.Center),
  150. verticalAlignment = Alignment.CenterVertically,
  151. ) {
  152. var internalSelection by remember { mutableStateOf(selection) }
  153. Text(
  154. modifier = Modifier
  155. .weight(1f)
  156. .padding(end = 16.dp),
  157. text = internalSelection.dayOfWeek
  158. .getDisplayName(TextStyle.SHORT, java.util.Locale.getDefault()),
  159. textAlign = TextAlign.Center,
  160. style = MaterialTheme.typography.titleMedium,
  161. )
  162. WheelDatePicker(
  163. startDate = selection,
  164. minDate = minDate,
  165. maxDate = maxDate,
  166. onSelectionChanged = {
  167. internalSelection = it
  168. onSelectionChange(it)
  169. },
  170. )
  171. }
  172. },
  173. thirdButton = if (onRemove != null) {
  174. {
  175. TextButton(onClick = onRemove) {
  176. Text(text = stringResource(R.string.action_remove))
  177. }
  178. }
  179. } else {
  180. null
  181. },
  182. onConfirm = onConfirm,
  183. onDismissRequest = onDismissRequest,
  184. )
  185. }
  186. @Composable
  187. private fun BaseSelector(
  188. title: String,
  189. content: @Composable BoxScope.() -> Unit,
  190. thirdButton: @Composable (RowScope.() -> Unit)? = null,
  191. onConfirm: () -> Unit,
  192. onDismissRequest: () -> Unit,
  193. ) {
  194. AlertDialogContent(
  195. modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars),
  196. title = { Text(text = title) },
  197. text = {
  198. Box(
  199. modifier = Modifier.fillMaxWidth(),
  200. content = content,
  201. )
  202. },
  203. buttons = {
  204. Row(
  205. modifier = Modifier.fillMaxWidth(),
  206. horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small, Alignment.End),
  207. ) {
  208. if (thirdButton != null) {
  209. thirdButton()
  210. Spacer(modifier = Modifier.weight(1f))
  211. }
  212. TextButton(onClick = onDismissRequest) {
  213. Text(text = stringResource(android.R.string.cancel))
  214. }
  215. TextButton(onClick = onConfirm) {
  216. Text(text = stringResource(android.R.string.ok))
  217. }
  218. }
  219. },
  220. )
  221. }