Manga.kt 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. package eu.kanade.domain.manga.model
  2. import eu.kanade.domain.base.BasePreferences
  3. import eu.kanade.tachiyomi.data.cache.CoverCache
  4. import eu.kanade.tachiyomi.source.LocalSource
  5. import eu.kanade.tachiyomi.source.model.SManga
  6. import eu.kanade.tachiyomi.source.model.UpdateStrategy
  7. import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
  8. import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
  9. import eu.kanade.tachiyomi.widget.ExtendedNavigationView
  10. import tachiyomi.domain.manga.model.MangaUpdate
  11. import uy.kohesive.injekt.Injekt
  12. import uy.kohesive.injekt.api.get
  13. import java.io.Serializable
  14. data class Manga(
  15. val id: Long,
  16. val source: Long,
  17. val favorite: Boolean,
  18. val lastUpdate: Long,
  19. val dateAdded: Long,
  20. val viewerFlags: Long,
  21. val chapterFlags: Long,
  22. val coverLastModified: Long,
  23. val url: String,
  24. val title: String,
  25. val artist: String?,
  26. val author: String?,
  27. val description: String?,
  28. val genre: List<String>?,
  29. val status: Long,
  30. val thumbnailUrl: String?,
  31. val updateStrategy: UpdateStrategy,
  32. val initialized: Boolean,
  33. ) : Serializable {
  34. val sorting: Long
  35. get() = chapterFlags and CHAPTER_SORTING_MASK
  36. val displayMode: Long
  37. get() = chapterFlags and CHAPTER_DISPLAY_MASK
  38. val unreadFilterRaw: Long
  39. get() = chapterFlags and CHAPTER_UNREAD_MASK
  40. val downloadedFilterRaw: Long
  41. get() = chapterFlags and CHAPTER_DOWNLOADED_MASK
  42. val bookmarkedFilterRaw: Long
  43. get() = chapterFlags and CHAPTER_BOOKMARKED_MASK
  44. val readingModeType: Long
  45. get() = viewerFlags and ReadingModeType.MASK.toLong()
  46. val orientationType: Long
  47. get() = viewerFlags and OrientationType.MASK.toLong()
  48. val unreadFilter: TriStateFilter
  49. get() = when (unreadFilterRaw) {
  50. CHAPTER_SHOW_UNREAD -> TriStateFilter.ENABLED_IS
  51. CHAPTER_SHOW_READ -> TriStateFilter.ENABLED_NOT
  52. else -> TriStateFilter.DISABLED
  53. }
  54. val downloadedFilter: TriStateFilter
  55. get() {
  56. if (forceDownloaded()) return TriStateFilter.ENABLED_IS
  57. return when (downloadedFilterRaw) {
  58. CHAPTER_SHOW_DOWNLOADED -> TriStateFilter.ENABLED_IS
  59. CHAPTER_SHOW_NOT_DOWNLOADED -> TriStateFilter.ENABLED_NOT
  60. else -> TriStateFilter.DISABLED
  61. }
  62. }
  63. val bookmarkedFilter: TriStateFilter
  64. get() = when (bookmarkedFilterRaw) {
  65. CHAPTER_SHOW_BOOKMARKED -> TriStateFilter.ENABLED_IS
  66. CHAPTER_SHOW_NOT_BOOKMARKED -> TriStateFilter.ENABLED_NOT
  67. else -> TriStateFilter.DISABLED
  68. }
  69. fun chaptersFiltered(): Boolean {
  70. return unreadFilter != TriStateFilter.DISABLED ||
  71. downloadedFilter != TriStateFilter.DISABLED ||
  72. bookmarkedFilter != TriStateFilter.DISABLED
  73. }
  74. fun forceDownloaded(): Boolean {
  75. return favorite && Injekt.get<BasePreferences>().downloadedOnly().get()
  76. }
  77. fun sortDescending(): Boolean {
  78. return chapterFlags and CHAPTER_SORT_DIR_MASK == CHAPTER_SORT_DESC
  79. }
  80. fun toSManga(): SManga = SManga.create().also {
  81. it.url = url
  82. it.title = title
  83. it.artist = artist
  84. it.author = author
  85. it.description = description
  86. it.genre = genre.orEmpty().joinToString()
  87. it.status = status.toInt()
  88. it.thumbnail_url = thumbnailUrl
  89. it.initialized = initialized
  90. }
  91. fun copyFrom(other: SManga): Manga {
  92. val author = other.author ?: author
  93. val artist = other.artist ?: artist
  94. val description = other.description ?: description
  95. val genres = if (other.genre != null) {
  96. other.getGenres()
  97. } else {
  98. genre
  99. }
  100. val thumbnailUrl = other.thumbnail_url ?: thumbnailUrl
  101. return this.copy(
  102. author = author,
  103. artist = artist,
  104. description = description,
  105. genre = genres,
  106. thumbnailUrl = thumbnailUrl,
  107. status = other.status.toLong(),
  108. updateStrategy = other.update_strategy,
  109. initialized = other.initialized && initialized,
  110. )
  111. }
  112. companion object {
  113. // Generic filter that does not filter anything
  114. const val SHOW_ALL = 0x00000000L
  115. const val CHAPTER_SORT_DESC = 0x00000000L
  116. const val CHAPTER_SORT_ASC = 0x00000001L
  117. const val CHAPTER_SORT_DIR_MASK = 0x00000001L
  118. const val CHAPTER_SHOW_UNREAD = 0x00000002L
  119. const val CHAPTER_SHOW_READ = 0x00000004L
  120. const val CHAPTER_UNREAD_MASK = 0x00000006L
  121. const val CHAPTER_SHOW_DOWNLOADED = 0x00000008L
  122. const val CHAPTER_SHOW_NOT_DOWNLOADED = 0x00000010L
  123. const val CHAPTER_DOWNLOADED_MASK = 0x00000018L
  124. const val CHAPTER_SHOW_BOOKMARKED = 0x00000020L
  125. const val CHAPTER_SHOW_NOT_BOOKMARKED = 0x00000040L
  126. const val CHAPTER_BOOKMARKED_MASK = 0x00000060L
  127. const val CHAPTER_SORTING_SOURCE = 0x00000000L
  128. const val CHAPTER_SORTING_NUMBER = 0x00000100L
  129. const val CHAPTER_SORTING_UPLOAD_DATE = 0x00000200L
  130. const val CHAPTER_SORTING_MASK = 0x00000300L
  131. const val CHAPTER_DISPLAY_NAME = 0x00000000L
  132. const val CHAPTER_DISPLAY_NUMBER = 0x00100000L
  133. const val CHAPTER_DISPLAY_MASK = 0x00100000L
  134. fun create() = Manga(
  135. id = -1L,
  136. url = "",
  137. title = "",
  138. source = -1L,
  139. favorite = false,
  140. lastUpdate = 0L,
  141. dateAdded = 0L,
  142. viewerFlags = 0L,
  143. chapterFlags = 0L,
  144. coverLastModified = 0L,
  145. artist = null,
  146. author = null,
  147. description = null,
  148. genre = null,
  149. status = 0L,
  150. thumbnailUrl = null,
  151. updateStrategy = UpdateStrategy.ALWAYS_UPDATE,
  152. initialized = false,
  153. )
  154. }
  155. }
  156. enum class TriStateFilter {
  157. DISABLED, // Disable filter
  158. ENABLED_IS, // Enabled with "is" filter
  159. ENABLED_NOT, // Enabled with "not" filter
  160. }
  161. fun TriStateFilter.toTriStateGroupState(): ExtendedNavigationView.Item.TriStateGroup.State {
  162. return when (this) {
  163. TriStateFilter.DISABLED -> ExtendedNavigationView.Item.TriStateGroup.State.IGNORE
  164. TriStateFilter.ENABLED_IS -> ExtendedNavigationView.Item.TriStateGroup.State.INCLUDE
  165. TriStateFilter.ENABLED_NOT -> ExtendedNavigationView.Item.TriStateGroup.State.EXCLUDE
  166. }
  167. }
  168. fun Manga.toMangaUpdate(): MangaUpdate {
  169. return MangaUpdate(
  170. id = id,
  171. source = source,
  172. favorite = favorite,
  173. lastUpdate = lastUpdate,
  174. dateAdded = dateAdded,
  175. viewerFlags = viewerFlags,
  176. chapterFlags = chapterFlags,
  177. coverLastModified = coverLastModified,
  178. url = url,
  179. title = title,
  180. artist = artist,
  181. author = author,
  182. description = description,
  183. genre = genre,
  184. status = status,
  185. thumbnailUrl = thumbnailUrl,
  186. updateStrategy = updateStrategy,
  187. initialized = initialized,
  188. )
  189. }
  190. fun SManga.toDomainManga(sourceId: Long): Manga {
  191. return Manga.create().copy(
  192. url = url,
  193. title = title,
  194. artist = artist,
  195. author = author,
  196. description = description,
  197. genre = getGenres(),
  198. status = status.toLong(),
  199. thumbnailUrl = thumbnail_url,
  200. updateStrategy = update_strategy,
  201. initialized = initialized,
  202. source = sourceId,
  203. )
  204. }
  205. fun Manga.isLocal(): Boolean = source == LocalSource.ID
  206. fun Manga.hasCustomCover(coverCache: CoverCache = Injekt.get()): Boolean {
  207. return coverCache.getCustomCoverFile(id).exists()
  208. }