LibrarySettingsDialog.kt 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. package eu.kanade.presentation.library
  2. import android.content.res.Configuration
  3. import androidx.compose.foundation.layout.Column
  4. import androidx.compose.foundation.layout.ColumnScope
  5. import androidx.compose.foundation.layout.padding
  6. import androidx.compose.foundation.rememberScrollState
  7. import androidx.compose.foundation.verticalScroll
  8. import androidx.compose.material3.Text
  9. import androidx.compose.runtime.Composable
  10. import androidx.compose.runtime.getValue
  11. import androidx.compose.runtime.remember
  12. import androidx.compose.ui.Modifier
  13. import androidx.compose.ui.platform.LocalConfiguration
  14. import androidx.compose.ui.res.stringResource
  15. import eu.kanade.presentation.components.TabbedDialog
  16. import eu.kanade.presentation.components.TabbedDialogPaddings
  17. import eu.kanade.presentation.util.collectAsState
  18. import eu.kanade.tachiyomi.R
  19. import eu.kanade.tachiyomi.ui.library.LibrarySettingsScreenModel
  20. import tachiyomi.core.preference.TriState
  21. import tachiyomi.domain.category.model.Category
  22. import tachiyomi.domain.library.model.LibraryDisplayMode
  23. import tachiyomi.domain.library.model.LibrarySort
  24. import tachiyomi.domain.library.model.sort
  25. import tachiyomi.domain.library.service.LibraryPreferences
  26. import tachiyomi.presentation.core.components.CheckboxItem
  27. import tachiyomi.presentation.core.components.HeadingItem
  28. import tachiyomi.presentation.core.components.SettingsFlowRow
  29. import tachiyomi.presentation.core.components.SliderItem
  30. import tachiyomi.presentation.core.components.SortItem
  31. import tachiyomi.presentation.core.components.TriStateItem
  32. import tachiyomi.presentation.core.components.material.ChoiceChip
  33. @Composable
  34. fun LibrarySettingsDialog(
  35. onDismissRequest: () -> Unit,
  36. screenModel: LibrarySettingsScreenModel,
  37. category: Category?,
  38. ) {
  39. TabbedDialog(
  40. onDismissRequest = onDismissRequest,
  41. tabTitles = listOf(
  42. stringResource(R.string.action_filter),
  43. stringResource(R.string.action_sort),
  44. stringResource(R.string.action_display),
  45. ),
  46. ) { page ->
  47. Column(
  48. modifier = Modifier
  49. .padding(vertical = TabbedDialogPaddings.Vertical)
  50. .verticalScroll(rememberScrollState()),
  51. ) {
  52. when (page) {
  53. 0 -> FilterPage(
  54. screenModel = screenModel,
  55. )
  56. 1 -> SortPage(
  57. category = category,
  58. screenModel = screenModel,
  59. )
  60. 2 -> DisplayPage(
  61. screenModel = screenModel,
  62. )
  63. }
  64. }
  65. }
  66. }
  67. @Composable
  68. private fun ColumnScope.FilterPage(
  69. screenModel: LibrarySettingsScreenModel,
  70. ) {
  71. val filterDownloaded by screenModel.libraryPreferences.filterDownloaded().collectAsState()
  72. val downloadedOnly by screenModel.preferences.downloadedOnly().collectAsState()
  73. TriStateItem(
  74. label = stringResource(R.string.label_downloaded),
  75. state = if (downloadedOnly) {
  76. TriState.ENABLED_IS
  77. } else {
  78. filterDownloaded
  79. },
  80. enabled = !downloadedOnly,
  81. onClick = { screenModel.toggleFilter(LibraryPreferences::filterDownloaded) },
  82. )
  83. val filterUnread by screenModel.libraryPreferences.filterUnread().collectAsState()
  84. TriStateItem(
  85. label = stringResource(R.string.action_filter_unread),
  86. state = filterUnread,
  87. onClick = { screenModel.toggleFilter(LibraryPreferences::filterUnread) },
  88. )
  89. val filterStarted by screenModel.libraryPreferences.filterStarted().collectAsState()
  90. TriStateItem(
  91. label = stringResource(R.string.label_started),
  92. state = filterStarted,
  93. onClick = { screenModel.toggleFilter(LibraryPreferences::filterStarted) },
  94. )
  95. val filterBookmarked by screenModel.libraryPreferences.filterBookmarked().collectAsState()
  96. TriStateItem(
  97. label = stringResource(R.string.action_filter_bookmarked),
  98. state = filterBookmarked,
  99. onClick = { screenModel.toggleFilter(LibraryPreferences::filterBookmarked) },
  100. )
  101. val filterCompleted by screenModel.libraryPreferences.filterCompleted().collectAsState()
  102. TriStateItem(
  103. label = stringResource(R.string.completed),
  104. state = filterCompleted,
  105. onClick = { screenModel.toggleFilter(LibraryPreferences::filterCompleted) },
  106. )
  107. val trackServices = remember { screenModel.trackServices }
  108. when (trackServices.size) {
  109. 0 -> {
  110. // No trackers
  111. }
  112. 1 -> {
  113. val service = trackServices[0]
  114. val filterTracker by screenModel.libraryPreferences.filterTracking(service.id.toInt()).collectAsState()
  115. TriStateItem(
  116. label = stringResource(R.string.action_filter_tracked),
  117. state = filterTracker,
  118. onClick = { screenModel.toggleTracker(service.id.toInt()) },
  119. )
  120. }
  121. else -> {
  122. HeadingItem(R.string.action_filter_tracked)
  123. trackServices.map { service ->
  124. val filterTracker by screenModel.libraryPreferences.filterTracking(service.id.toInt()).collectAsState()
  125. TriStateItem(
  126. label = stringResource(service.nameRes()),
  127. state = filterTracker,
  128. onClick = { screenModel.toggleTracker(service.id.toInt()) },
  129. )
  130. }
  131. }
  132. }
  133. }
  134. @Composable
  135. private fun ColumnScope.SortPage(
  136. category: Category?,
  137. screenModel: LibrarySettingsScreenModel,
  138. ) {
  139. val sortingMode = category.sort.type
  140. val sortDescending = !category.sort.isAscending
  141. listOf(
  142. R.string.action_sort_alpha to LibrarySort.Type.Alphabetical,
  143. R.string.action_sort_total to LibrarySort.Type.TotalChapters,
  144. R.string.action_sort_last_read to LibrarySort.Type.LastRead,
  145. R.string.action_sort_last_manga_update to LibrarySort.Type.LastUpdate,
  146. R.string.action_sort_unread_count to LibrarySort.Type.UnreadCount,
  147. R.string.action_sort_latest_chapter to LibrarySort.Type.LatestChapter,
  148. R.string.action_sort_chapter_fetch_date to LibrarySort.Type.ChapterFetchDate,
  149. R.string.action_sort_date_added to LibrarySort.Type.DateAdded,
  150. ).map { (titleRes, mode) ->
  151. SortItem(
  152. label = stringResource(titleRes),
  153. sortDescending = sortDescending.takeIf { sortingMode == mode },
  154. onClick = {
  155. val isTogglingDirection = sortingMode == mode
  156. val direction = when {
  157. isTogglingDirection -> if (sortDescending) LibrarySort.Direction.Ascending else LibrarySort.Direction.Descending
  158. else -> if (sortDescending) LibrarySort.Direction.Descending else LibrarySort.Direction.Ascending
  159. }
  160. screenModel.setSort(category, mode, direction)
  161. },
  162. )
  163. }
  164. }
  165. private val displayModes = listOf(
  166. R.string.action_display_grid to LibraryDisplayMode.CompactGrid,
  167. R.string.action_display_comfortable_grid to LibraryDisplayMode.ComfortableGrid,
  168. R.string.action_display_cover_only_grid to LibraryDisplayMode.CoverOnlyGrid,
  169. R.string.action_display_list to LibraryDisplayMode.List,
  170. )
  171. @Composable
  172. private fun ColumnScope.DisplayPage(
  173. screenModel: LibrarySettingsScreenModel,
  174. ) {
  175. val displayMode by screenModel.libraryPreferences.libraryDisplayMode().collectAsState()
  176. SettingsFlowRow(R.string.action_display_mode) {
  177. displayModes.map { (titleRes, mode) ->
  178. ChoiceChip(
  179. isSelected = displayMode == mode,
  180. onClick = { screenModel.setDisplayMode(mode) },
  181. content = { Text(stringResource(titleRes)) },
  182. )
  183. }
  184. }
  185. if (displayMode != LibraryDisplayMode.List) {
  186. val configuration = LocalConfiguration.current
  187. val columnPreference = remember {
  188. if (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
  189. screenModel.libraryPreferences.landscapeColumns()
  190. } else {
  191. screenModel.libraryPreferences.portraitColumns()
  192. }
  193. }
  194. val columns by columnPreference.collectAsState()
  195. SliderItem(
  196. label = stringResource(R.string.pref_library_columns),
  197. max = 10,
  198. value = columns,
  199. valueText = if (columns > 0) {
  200. stringResource(R.string.pref_library_columns_per_row, columns)
  201. } else {
  202. stringResource(R.string.label_default)
  203. },
  204. onChange = { columnPreference.set(it) },
  205. )
  206. }
  207. HeadingItem(R.string.overlay_header)
  208. val downloadBadge by screenModel.libraryPreferences.downloadBadge().collectAsState()
  209. CheckboxItem(
  210. label = stringResource(R.string.action_display_download_badge),
  211. checked = downloadBadge,
  212. onClick = {
  213. screenModel.togglePreference(LibraryPreferences::downloadBadge)
  214. },
  215. )
  216. val localBadge by screenModel.libraryPreferences.localBadge().collectAsState()
  217. CheckboxItem(
  218. label = stringResource(R.string.action_display_local_badge),
  219. checked = localBadge,
  220. onClick = {
  221. screenModel.togglePreference(LibraryPreferences::localBadge)
  222. },
  223. )
  224. val languageBadge by screenModel.libraryPreferences.languageBadge().collectAsState()
  225. CheckboxItem(
  226. label = stringResource(R.string.action_display_language_badge),
  227. checked = languageBadge,
  228. onClick = {
  229. screenModel.togglePreference(LibraryPreferences::languageBadge)
  230. },
  231. )
  232. val showContinueReadingButton by screenModel.libraryPreferences.showContinueReadingButton().collectAsState()
  233. CheckboxItem(
  234. label = stringResource(R.string.action_display_show_continue_reading_button),
  235. checked = showContinueReadingButton,
  236. onClick = {
  237. screenModel.togglePreference(LibraryPreferences::showContinueReadingButton)
  238. },
  239. )
  240. HeadingItem(R.string.tabs_header)
  241. val categoryTabs by screenModel.libraryPreferences.categoryTabs().collectAsState()
  242. CheckboxItem(
  243. label = stringResource(R.string.action_display_show_tabs),
  244. checked = categoryTabs,
  245. onClick = {
  246. screenModel.togglePreference(LibraryPreferences::categoryTabs)
  247. },
  248. )
  249. val categoryNumberOfItems by screenModel.libraryPreferences.categoryNumberOfItems().collectAsState()
  250. CheckboxItem(
  251. label = stringResource(R.string.action_display_show_number_of_items),
  252. checked = categoryNumberOfItems,
  253. onClick = {
  254. screenModel.togglePreference(LibraryPreferences::categoryNumberOfItems)
  255. },
  256. )
  257. }