diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterHolder.kt deleted file mode 100644 index 4ea8cb48c0..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterHolder.kt +++ /dev/null @@ -1,110 +0,0 @@ -package eu.kanade.tachiyomi.ui.recent_updates - -import android.app.Activity -import android.view.View -import androidx.core.content.ContextCompat -import coil.api.clear -import coil.transform.CircleCropTransformation -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.image.coil.loadLibraryManga -import eu.kanade.tachiyomi.databinding.RecentChaptersItemBinding -import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterHolder -import eu.kanade.tachiyomi.util.chapter.ChapterUtil -import eu.kanade.tachiyomi.util.system.getResourceColor - -/** - * Holder that contains chapter item - * Uses R.layout.item_recent_chapters. - * UI related actions should be called from here. - * - * @param view the inflated view for this holder. - * @param adapter the adapter handling this holder. - * @param listener a listener to react to single tap and long tap events. - * @constructor creates a new recent chapter holder. - */ -class RecentChapterHolder(private val view: View, private val adapter: RecentChaptersAdapter) : - BaseChapterHolder(view, adapter) { - - /** - * Color of read chapter - */ - private var readColor = view.context.getResourceColor(android.R.attr.textColorHint) - - /** - * Color of unread chapter - */ - private var unreadColor = view.context.getResourceColor(android.R.attr.textColorPrimary) - - /** - * Currently bound item. - */ - private var item: RecentChapterItem? = null - - private val binding = RecentChaptersItemBinding.bind(view) - init { - binding.mangaCover.setOnClickListener { - adapter.coverClickListener.onCoverClick(flexibleAdapterPosition) - } - } - - /** - * Set values of view - * - * @param item item containing chapter information - */ - fun bind(item: RecentChapterItem) { - this.item = item - - // Set chapter binding.title - binding.chapterTitle.text = item.chapter.name - - // Set manga binding.title - binding.title.text = item.manga.title - - if (binding.frontView.translationX == 0f) { - binding.read.setImageDrawable( - ContextCompat.getDrawable( - binding.root.context, - if (item.read) R.drawable.ic_eye_off_24dp - else R.drawable.ic_eye_24dp - ) - ) - } - - // Set cover - if ((view.context as? Activity)?.isDestroyed != true) { - binding.mangaCover.clear() - binding.mangaCover.loadLibraryManga(item.manga) { - transformations(CircleCropTransformation()) - } - } - - val chapterColor = ChapterUtil.chapterColor(itemView.context, item) - binding.chapterTitle.setTextColor(chapterColor) - binding.title.setTextColor(chapterColor) - - // Set chapter status - notifyStatus(item.status, item.progress) - resetFrontView() - } - - private fun resetFrontView() { - if (binding.frontView.translationX != 0f) itemView.post { adapter.notifyItemChanged(flexibleAdapterPosition) } - } - - override fun getFrontView(): View { - return binding.frontView - } - - override fun getRearRightView(): View { - return binding.rightView - } - - /** - * Updates chapter status in view. - * - * @param status download status - */ - fun notifyStatus(status: Int, progress: Int) = - binding.downloadButton.root.setDownloadStatus(status, progress) -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterItem.kt deleted file mode 100644 index 4f221d1ca7..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterItem.kt +++ /dev/null @@ -1,36 +0,0 @@ -package eu.kanade.tachiyomi.ui.recent_updates - -import android.view.View -import androidx.recyclerview.widget.RecyclerView -import eu.davidea.flexibleadapter.FlexibleAdapter -import eu.davidea.flexibleadapter.items.IFlexible -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.database.models.Chapter -import eu.kanade.tachiyomi.data.database.models.Manga -import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterItem - -class RecentChapterItem(chapter: Chapter, val manga: Manga, header: DateItem) : - BaseChapterItem(chapter, header) { - - override fun getLayoutRes(): Int { - return R.layout.recent_chapters_item - } - - override fun createViewHolder(view: View, adapter: FlexibleAdapter>): RecentChapterHolder { - return RecentChapterHolder(view, adapter as RecentChaptersAdapter) - } - - override fun bindViewHolder( - adapter: FlexibleAdapter>, - holder: RecentChapterHolder, - position: Int, - payloads: MutableList? - ) { - holder.bind(this) - } - - fun filter(text: String): Boolean { - return chapter.name.contains(text, false) || - manga.title.contains(text, false) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersAdapter.kt deleted file mode 100644 index 48b29ef4e3..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersAdapter.kt +++ /dev/null @@ -1,42 +0,0 @@ -package eu.kanade.tachiyomi.ui.recent_updates - -import androidx.recyclerview.widget.ItemTouchHelper -import eu.davidea.flexibleadapter.items.IFlexible -import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterAdapter - -class RecentChaptersAdapter(val controller: RecentChaptersController) : - BaseChapterAdapter>(controller) { - - val coverClickListener: OnCoverClickListener = controller - var recents = emptyList() - - init { - setDisplayHeadersAtStartUp(true) - // setStickyHeaders(true) - } - - fun setItems(recents: List) { - this.recents = recents - performFilter() - } - - fun performFilter() { - val s = getFilter(String::class.java) - if (s.isNullOrBlank()) { - updateDataSet(recents) - } else { - updateDataSet(recents.filter { it.filter(s) }) - } - } - - interface OnCoverClickListener { - fun onCoverClick(position: Int) - } - - override fun onItemSwiped(position: Int, direction: Int) { - super.onItemSwiped(position, direction) - when (direction) { - ItemTouchHelper.LEFT -> controller.toggleMarkAsRead(position) - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersController.kt deleted file mode 100644 index 62352c85c5..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersController.kt +++ /dev/null @@ -1,265 +0,0 @@ -package eu.kanade.tachiyomi.ui.recent_updates - -import android.app.Activity -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import androidx.recyclerview.widget.DividerItemDecoration -import androidx.recyclerview.widget.ItemTouchHelper -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.google.android.material.snackbar.BaseTransientBottomBar -import com.google.android.material.snackbar.Snackbar -import eu.davidea.flexibleadapter.FlexibleAdapter -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.download.DownloadService -import eu.kanade.tachiyomi.data.download.model.Download -import eu.kanade.tachiyomi.data.library.LibraryUpdateService -import eu.kanade.tachiyomi.data.notification.Notifications -import eu.kanade.tachiyomi.databinding.RecentChaptersControllerBinding -import eu.kanade.tachiyomi.ui.base.controller.BaseController -import eu.kanade.tachiyomi.ui.main.MainActivity -import eu.kanade.tachiyomi.ui.manga.MangaDetailsController -import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterAdapter -import eu.kanade.tachiyomi.ui.reader.ReaderActivity -import eu.kanade.tachiyomi.util.system.notificationManager -import eu.kanade.tachiyomi.util.view.scrollViewWith -import eu.kanade.tachiyomi.util.view.setStyle -import eu.kanade.tachiyomi.util.view.snack -import eu.kanade.tachiyomi.util.view.withFadeTransaction -import timber.log.Timber - -/** - * Fragment that shows recent chapters. - * Uses [R.layout.recent_chapters_controller]. - * UI related actions should be called from here. - */ -class RecentChaptersController(bundle: Bundle? = null) : - BaseController(bundle), - FlexibleAdapter.OnItemClickListener, - FlexibleAdapter.OnUpdateListener, - FlexibleAdapter.OnItemMoveListener, - RecentChaptersAdapter.OnCoverClickListener, - BaseChapterAdapter.DownloadInterface { - - /** - * Adapter containing the recent chapters. - */ - var adapter: RecentChaptersAdapter? = null - private set - - private var presenter = RecentChaptersPresenter(this) - private var snack: Snackbar? = null - private var lastChapterId: Long? = null - - override fun getTitle(): String? { - return resources?.getString(R.string.recent_updates) - } - - override fun createBinding(inflater: LayoutInflater) = RecentChaptersControllerBinding.inflate(inflater) - - /** - * Called when view is created - * @param view created view - */ - override fun onViewCreated(view: View) { - super.onViewCreated(view) - // view.applyWindowInsetsForController() - - view.context.notificationManager.cancel(Notifications.ID_NEW_CHAPTERS) - // Init RecyclerView and adapter - val layoutManager = LinearLayoutManager(view.context) - binding.recycler.layoutManager = layoutManager - binding.recycler.addItemDecoration(DividerItemDecoration(view.context, DividerItemDecoration.VERTICAL)) - binding.recycler.setHasFixedSize(true) - adapter = RecentChaptersAdapter(this@RecentChaptersController) - binding.recycler.adapter = adapter - - adapter?.isSwipeEnabled = true - adapter?.itemTouchHelperCallback?.setSwipeFlags( - ItemTouchHelper.LEFT - ) - if (presenter.chapters.isNotEmpty()) adapter?.updateDataSet(presenter.chapters.toList()) - binding.swipeRefresh.setStyle() - binding.swipeRefresh.setDistanceToTriggerSync((2 * 64 * view.resources.displayMetrics.density).toInt()) - binding.swipeRefresh.setOnRefreshListener { - if (!LibraryUpdateService.isRunning()) { - LibraryUpdateService.start(view.context) - snack = view.snack(R.string.updating_library) - } - // It can be a very long operation, so we disable swipe refresh and show a snackbar. - binding.swipeRefresh.isRefreshing = false - } - - scrollViewWith(binding.recycler, swipeRefreshLayout = binding.swipeRefresh, padBottom = true) - - presenter.onCreate() - } - - override fun onDestroy() { - super.onDestroy() - presenter.onDestroy() - } - - override fun onDestroyView(view: View) { - adapter = null - snack = null - super.onDestroyView(view) - } - - override fun onActivityResumed(activity: Activity) { - super.onActivityResumed(activity) - if (view != null) { - refresh() - } - } - - fun refresh() = presenter.getUpdates() - - /** - * Called when item in list is clicked - * @param position position of clicked item - */ - override fun onItemClick(view: View?, position: Int): Boolean { - val adapter = adapter ?: return false - - // Get item from position - val item = adapter.getItem(position) as? RecentChapterItem ?: return false - openChapter(item) - return false - } - - /** - * Open chapter in reader - * @param chapter selected chapter - */ - private fun openChapter(item: RecentChapterItem) { - val activity = activity ?: return - val intent = ReaderActivity.newIntent(activity, item.manga, item.chapter) - startActivity(intent) - } - - /** - * Populate adapter with chapters - * @param chapters list of [Any] - */ - fun onNextRecentChapters(chapters: List) { - adapter?.setItems(chapters) - } - - fun updateChapterDownload(download: Download) { - if (view == null) return - val id = download.chapter.id ?: return - val holder = binding.recycler.findViewHolderForItemId(id) as? RecentChapterHolder ?: return - holder.notifyStatus(download.status, download.progress) - } - - override fun onUpdateEmptyView(size: Int) { - if (size > 0) { - binding.emptyView.hide() - } else { - binding.emptyView.show(R.drawable.ic_update_24dp, R.string.no_recent_chapters) - } - } - - override fun onItemMove(fromPosition: Int, toPosition: Int) { } - override fun shouldMoveItem(fromPosition: Int, toPosition: Int) = true - - override fun onActionStateChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) { - binding.swipeRefresh.isEnabled = actionState != ItemTouchHelper.ACTION_STATE_SWIPE - } - - /** - * Update download status of chapter - * @param download [Download] object containing download progress. - */ - fun onChapterStatusChange(download: Download) { - getHolder(download)?.notifyStatus(download.status, download.progress) - } - - /** - * Returns holder belonging to chapter - * @param download [Download] object containing download progress. - */ - private fun getHolder(download: Download): RecentChapterHolder? { - return binding.recycler.findViewHolderForItemId(download.chapter.id!!) as? RecentChapterHolder - } - - /** - * Mark chapter as read - * @param position position of chapter item - */ - fun toggleMarkAsRead(position: Int) { - val item = adapter?.getItem(position) as? RecentChapterItem ?: return - val chapter = item.chapter - val lastRead = chapter.last_page_read - val pagesLeft = chapter.pages_left - val read = item.chapter.read - lastChapterId = chapter.id - presenter.markChapterRead(item, !read) - if (!read) { - snack = view?.snack(R.string.marked_as_read, Snackbar.LENGTH_INDEFINITE) { - var undoing = false - setAction(R.string.undo) { - presenter.markChapterRead(item, read, lastRead, pagesLeft) - undoing = true - } - addCallback( - object : BaseTransientBottomBar.BaseCallback() { - override fun onDismissed(transientBottomBar: Snackbar?, event: Int) { - super.onDismissed(transientBottomBar, event) - if (!undoing && presenter.preferences.removeAfterMarkedAsRead()) { - lastChapterId = chapter.id - presenter.deleteChapter(chapter, item.manga) - } - } - } - ) - } - (activity as? MainActivity)?.setUndoSnackBar(snack) - } - // presenter.markChapterRead(item, !item.chapter.read) - } - - override fun downloadChapter(position: Int) { - val view = view ?: return - val item = adapter?.getItem(position) as? RecentChapterItem ?: return - val chapter = item.chapter - val manga = item.manga - if (item.status != Download.NOT_DOWNLOADED && item.status != Download.ERROR) { - presenter.deleteChapter(chapter, manga) - } else { - if (item.status == Download.ERROR) DownloadService.start(view.context) - else presenter.downloadChapters(listOf(item)) - } - } - - override fun startDownloadNow(position: Int) { - val chapter = (adapter?.getItem(position) as? RecentChapterItem)?.chapter ?: return - presenter.startDownloadChapterNow(chapter) - } - - override fun onCoverClick(position: Int) { - val chapterClicked = adapter?.getItem(position) as? RecentChapterItem ?: return - openManga(chapterClicked) - } - - fun openManga(chapter: RecentChapterItem) { - router.pushController(MangaDetailsController(chapter.manga).withFadeTransaction()) - } - - /** - * Called when chapters are deleted - */ - fun onChaptersDeleted() { - adapter?.notifyDataSetChanged() - } - - /** - * Called when error while deleting - * @param error error message - */ - fun onChaptersDeletedError(error: Throwable) { - Timber.e(error) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersPresenter.kt deleted file mode 100644 index dd0eb8d782..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersPresenter.kt +++ /dev/null @@ -1,183 +0,0 @@ -package eu.kanade.tachiyomi.ui.recent_updates - -import eu.kanade.tachiyomi.data.database.DatabaseHelper -import eu.kanade.tachiyomi.data.database.models.Chapter -import eu.kanade.tachiyomi.data.database.models.Manga -import eu.kanade.tachiyomi.data.database.models.MangaChapter -import eu.kanade.tachiyomi.data.download.DownloadManager -import eu.kanade.tachiyomi.data.download.model.Download -import eu.kanade.tachiyomi.data.download.model.DownloadQueue -import eu.kanade.tachiyomi.data.library.LibraryServiceListener -import eu.kanade.tachiyomi.data.library.LibraryUpdateService -import eu.kanade.tachiyomi.data.preference.PreferencesHelper -import eu.kanade.tachiyomi.source.SourceManager -import eu.kanade.tachiyomi.util.system.executeOnIO -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.cancel -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import java.util.Calendar -import java.util.Date -import java.util.TreeMap - -class RecentChaptersPresenter( - private val controller: RecentChaptersController, - val preferences: PreferencesHelper = Injekt.get(), - private val db: DatabaseHelper = Injekt.get(), - private val downloadManager: DownloadManager = Injekt.get(), - private val sourceManager: SourceManager = Injekt.get() -) : DownloadQueue.DownloadListener, LibraryServiceListener { - - /** - * List containing chapter and manga information - */ - var chapters: List = emptyList() - - private var scope = CoroutineScope(Job() + Dispatchers.Default) - - fun onCreate() { - downloadManager.addListener(this) - LibraryUpdateService.setListener(this) - getUpdates() - } - - fun getUpdates() { - scope.launch { - val cal = Calendar.getInstance().apply { - time = Date() - add(Calendar.MONTH, -1) - } - val mangaChapters = db.getRecentChapters(cal.time).executeOnIO() - val map = TreeMap> { d1, d2 -> d2.compareTo(d1) } - val byDay = mangaChapters.groupByTo(map, { getMapKey(it.chapter.date_fetch) }) - val items = byDay.flatMap { - val dateItem = DateItem(it.key) - it.value.map { mc -> - RecentChapterItem(mc.chapter, mc.manga, dateItem) - } - } - setDownloadedChapters(items) - chapters = items - withContext(Dispatchers.Main) { controller.onNextRecentChapters(chapters) } - } - } - - fun onDestroy() { - downloadManager.removeListener(this) - LibraryUpdateService.removeListener(this) - } - - fun cancelScope() { - scope.cancel() - } - - override fun updateDownload(download: Download) { - chapters.find { it.chapter.id == download.chapter.id }?.download = download - scope.launch(Dispatchers.Main) { - controller.updateChapterDownload(download) - } - } - - override fun updateDownloads() { - scope.launch { - setDownloadedChapters(chapters) - withContext(Dispatchers.Main) { - controller.onNextRecentChapters(chapters) - } - } - } - - override fun onUpdateManga(manga: Manga?) { - getUpdates() - } - - /** - * Get date as time key - * - * @param date desired date - * @return date as time key - */ - private fun getMapKey(date: Long): Date { - val cal = Calendar.getInstance() - cal.time = Date(date) - cal[Calendar.HOUR_OF_DAY] = 0 - cal[Calendar.MINUTE] = 0 - cal[Calendar.SECOND] = 0 - cal[Calendar.MILLISECOND] = 0 - return cal.time - } - - /** - * Finds and assigns the list of downloaded chapters. - * - * @param chapters the list of chapter from the database. - */ - private fun setDownloadedChapters(chapters: List) { - for (item in chapters) { - if (downloadManager.isChapterDownloaded(item.chapter, item.manga)) { - item.status = Download.DOWNLOADED - } else if (downloadManager.hasQueue()) { - item.status = downloadManager.queue.find { it.chapter.id == item.chapter.id } - ?.status ?: 0 - } - } - } - - /** - * Mark selected chapter as read - * - * @param items list of selected chapters - * @param read read status - */ - fun markChapterRead( - item: RecentChapterItem, - read: Boolean, - lastRead: Int? = null, - pagesLeft: Int? = null - ) { - item.chapter.apply { - this.read = read - if (!read) { - last_page_read = lastRead ?: 0 - pages_left = pagesLeft ?: 0 - } - } - db.updateChapterProgress(item.chapter).executeAsBlocking() - controller.onNextRecentChapters(this.chapters) - } - - fun startDownloadChapterNow(chapter: Chapter) { - downloadManager.startDownloadNow(chapter) - } - - /** - * Deletes the given list of chapter. - * @param chapter the chapter to delete. - */ - fun deleteChapter(chapter: Chapter, manga: Manga, update: Boolean = true) { - val source = Injekt.get().getOrStub(manga.source) - downloadManager.deleteChapters(listOf(chapter), manga, source) - - if (update) { - val item = chapters.find { it.chapter.id == chapter.id } ?: return - item.apply { - status = Download.NOT_DOWNLOADED - download = null - } - - controller.onNextRecentChapters(chapters) - } - } - - /** - * Download selected chapters - * @param items list of recent chapters seleted. - */ - fun downloadChapters(items: List) { - items.forEach { downloadManager.downloadChapters(it.manga, listOf(it.chapter)) } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadAdapter.kt deleted file mode 100644 index 0b75f0d94e..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadAdapter.kt +++ /dev/null @@ -1,57 +0,0 @@ -package eu.kanade.tachiyomi.ui.recently_read - -import eu.davidea.flexibleadapter.FlexibleAdapter -import eu.davidea.flexibleadapter.items.IFlexible -import eu.kanade.tachiyomi.data.preference.PreferencesHelper -import eu.kanade.tachiyomi.source.SourceManager -import uy.kohesive.injekt.injectLazy -import java.text.DateFormat -import java.text.DecimalFormat -import java.text.DecimalFormatSymbols - -/** - * Adapter of RecentlyReadHolder. - * Connection between Fragment and Holder - * Holder updates should be called from here. - * - * @param controller a RecentlyReadController object - * @constructor creates an instance of the adapter. - */ -class RecentlyReadAdapter(controller: RecentlyReadController) : - FlexibleAdapter>(null, controller, true) { - - val sourceManager by injectLazy() - - val resumeClickListener: OnResumeClickListener = controller - - val removeClickListener: OnRemoveClickListener = controller - - val coverClickListener: OnCoverClickListener = controller - - /** - * DecimalFormat used to display correct chapter number - */ - val decimalFormat = DecimalFormat( - "#.###", - DecimalFormatSymbols() - .apply { decimalSeparator = '.' } - ) - - private val preferences: PreferencesHelper by injectLazy() - - val dateFormat: DateFormat by lazy { - preferences.dateFormat() - } - - interface OnResumeClickListener { - fun onResumeClick(position: Int) - } - - interface OnRemoveClickListener { - fun onRemoveClick(position: Int) - } - - interface OnCoverClickListener { - fun onCoverClick(position: Int) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadController.kt deleted file mode 100644 index 7a7c53bf84..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadController.kt +++ /dev/null @@ -1,244 +0,0 @@ -package eu.kanade.tachiyomi.ui.recently_read - -import android.app.Activity -import android.os.Bundle -import android.view.LayoutInflater -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import android.view.View -import androidx.appcompat.widget.SearchView -import androidx.recyclerview.widget.LinearLayoutManager -import eu.davidea.flexibleadapter.FlexibleAdapter -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.backup.BackupRestoreService -import eu.kanade.tachiyomi.data.database.models.History -import eu.kanade.tachiyomi.data.database.models.Manga -import eu.kanade.tachiyomi.databinding.RecentlyReadControllerBinding -import eu.kanade.tachiyomi.ui.base.controller.BaseController -import eu.kanade.tachiyomi.ui.manga.MangaDetailsController -import eu.kanade.tachiyomi.ui.reader.ReaderActivity -import eu.kanade.tachiyomi.ui.source.browse.ProgressItem -import eu.kanade.tachiyomi.util.system.launchUI -import eu.kanade.tachiyomi.util.system.toast -import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener -import eu.kanade.tachiyomi.util.view.scrollViewWith -import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener -import eu.kanade.tachiyomi.util.view.withFadeTransaction - -/** - * Fragment that shows recently read manga. - * Uses R.layout.fragment_recently_read. - * UI related actions should be called from here. - */ -class RecentlyReadController(bundle: Bundle? = null) : - BaseController(bundle), - FlexibleAdapter.OnUpdateListener, - FlexibleAdapter.EndlessScrollListener, - RecentlyReadAdapter.OnRemoveClickListener, - RecentlyReadAdapter.OnResumeClickListener, - RecentlyReadAdapter.OnCoverClickListener, - RemoveHistoryDialog.Listener { - - init { - setHasOptionsMenu(true) - } - - /** - * Adapter containing the recent manga. - */ - var adapter: RecentlyReadAdapter? = null - private set - - /** - * Endless loading item. - */ - private var progressItem: ProgressItem? = null - private var observeLater: Boolean = false - private var query = "" - - private var presenter = RecentlyReadPresenter(this) - private var recentItems: MutableList? = null - - override fun getTitle(): String? { - return resources?.getString(R.string.history) - } - - override fun createBinding(inflater: LayoutInflater) = RecentlyReadControllerBinding.inflate(inflater) - - /** - * Called when view is created - * - * @param view created view - */ - override fun onViewCreated(view: View) { - super.onViewCreated(view) - // view.applyWindowInsetsForController() - // Initialize adapter - adapter = RecentlyReadAdapter(this) - binding.recycler.adapter = adapter - binding.recycler.layoutManager = LinearLayoutManager(view.context) - binding.recycler.setHasFixedSize(true) - binding.recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener) - resetProgressItem() - scrollViewWith(binding.recycler, padBottom = true) - - if (recentItems != null) { - adapter?.updateDataSet(recentItems!!.toList()) - } - - launchUI { - val manga = presenter.refresh(query) - recentItems = manga.toMutableList() - adapter?.updateDataSet(manga) - } - } - - override fun onActivityResumed(activity: Activity) { - super.onActivityResumed(activity) - if (observeLater) { - launchUI { - val manga = presenter.refresh(query) - recentItems = manga.toMutableList() - adapter?.updateDataSet(manga) - } - observeLater = false - } - } - - /** - * Populate adapter with chapters - * - * @param mangaHistory list of manga history - */ - fun onNextManga(mangaHistory: List) { - val adapter = adapter ?: return - adapter.updateDataSet(mangaHistory) - adapter.onLoadMoreComplete(null) - if (recentItems == null) { - resetProgressItem() - } - recentItems = mangaHistory.toMutableList() - } - - fun onAddPageError() { - adapter?.onLoadMoreComplete(null) - adapter?.endlessTargetCount = 1 - } - - override fun onUpdateEmptyView(size: Int) { - if (size > 0) { - binding.emptyView.hide() - } else { - binding.emptyView.show( - R.drawable.ic_history_24dp, - R.string - .no_recently_read_manga - ) - } - } - - /** - * Sets a new progress item and reenables the scroll listener. - */ - private fun resetProgressItem() { - progressItem = ProgressItem() - adapter?.endlessTargetCount = 0 - adapter?.setEndlessScrollListener(this, progressItem!!) - } - - override fun onLoadMore(lastPosition: Int, currentPage: Int) { - val view = view ?: return - if (BackupRestoreService.isRunning(view.context.applicationContext)) { - onAddPageError() - return - } - presenter.requestNext(query) - } - - override fun noMoreLoad(newItemsSize: Int) { } - - override fun onResumeClick(position: Int) { - val activity = activity ?: return - observeLater = true - val (manga, chapter, _) = (adapter?.getItem(position) as? RecentlyReadItem)?.mch ?: return - - val nextChapter = presenter.getNextChapter(chapter, manga) - if (nextChapter != null) { - val intent = ReaderActivity.newIntent(activity, manga, nextChapter) - startActivity(intent) - } else { - activity.toast(R.string.next_chapter_not_found) - } - } - - override fun onRemoveClick(position: Int) { - val (manga, _, history) = (adapter?.getItem(position) as? RecentlyReadItem)?.mch ?: return - RemoveHistoryDialog(this, manga, history).showDialog(router) - } - - override fun onCoverClick(position: Int) { - val manga = (adapter?.getItem(position) as? RecentlyReadItem)?.mch?.manga ?: return - router.pushController(MangaDetailsController(manga).withFadeTransaction()) - } - - override fun removeHistory(manga: Manga, history: History, all: Boolean) { - presenter.lastCount = adapter?.itemCount ?: 25 - if (all) { - // Reset last read of chapter to 0L - presenter.removeAllFromHistory(manga.id!!) - } else { - // Remove all chapters belonging to manga from library - presenter.removeFromHistory(history) - } - } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.recently_read, menu) - val searchItem = menu.findItem(R.id.action_search) - val searchView = searchItem.actionView as SearchView - if (query.isNotEmpty()) { - searchItem.expandActionView() - searchView.setQuery(query, true) - searchView.clearFocus() - } - setOnQueryTextChangeListener(searchView) { - if (query != it) { - query = it ?: return@setOnQueryTextChangeListener false - launchUI { - resetProgressItem() - presenter.lastCount = 25 - val manga = presenter.refresh(query) - recentItems = manga.toMutableList() - adapter?.updateDataSet(manga) - } - } - true - } - - // Fixes problem with the overflow icon showing up in lieu of search - searchItem.setOnActionExpandListener( - object : MenuItem.OnActionExpandListener { - override fun onMenuItemActionExpand(item: MenuItem): Boolean { - return true - } - - override fun onMenuItemActionCollapse(item: MenuItem): Boolean { - activity?.invalidateOptionsMenu() - return true - } - } - ) - } - - /*override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - R.id.action_recents -> { - router.setRoot( - RecentChaptersController().withFadeTransaction().tag(R.id.nav_recents.toString())) - Injekt.get().showRecentUpdates().set(true) - (activity as? MainActivity)?.updateRecentsIcon() - } - } - return super.onOptionsItemSelected(item) - }*/ -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadHolder.kt deleted file mode 100644 index 6a80f83425..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadHolder.kt +++ /dev/null @@ -1,66 +0,0 @@ -package eu.kanade.tachiyomi.ui.recently_read - -import android.view.View -import coil.api.clear -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory -import eu.kanade.tachiyomi.data.image.coil.loadLibraryManga -import eu.kanade.tachiyomi.databinding.RecentlyReadItemBinding -import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder -import eu.kanade.tachiyomi.util.lang.toTimestampString -import java.util.Date - -/** - * Holder that contains recent manga item - * Uses R.layout.item_recently_read. - * UI related actions should be called from here. - * - * @param view the inflated view for this holder. - * @param adapter the adapter handling this holder. - * @constructor creates a new recent chapter holder. - */ -class RecentlyReadHolder( - view: View, - val adapter: RecentlyReadAdapter -) : BaseFlexibleViewHolder(view, adapter) { - - private val binding = RecentlyReadItemBinding.bind(view) - init { - binding.remove.setOnClickListener { - adapter.removeClickListener.onRemoveClick(flexibleAdapterPosition) - } - - binding.resume.setOnClickListener { - adapter.resumeClickListener.onResumeClick(flexibleAdapterPosition) - } - - binding.cover.setOnClickListener { - adapter.coverClickListener.onCoverClick(flexibleAdapterPosition) - } - } - - /** - * Set values of view - * - * @param item item containing history information - */ - fun bind(item: MangaChapterHistory) { - // Retrieve objects - val (manga, chapter, history) = item - - // Set manga title - binding.title.text = manga.title - - // Set source + chapter title - val formattedNumber = adapter.decimalFormat.format(chapter.chapter_number.toDouble()) - binding.mangaSource.text = itemView.context.getString(R.string.source_dash_chapter_) - .format(adapter.sourceManager.getOrStub(manga.source).toString(), formattedNumber) - - // Set last read timestamp title - binding.lastRead.text = Date(history.last_read).toTimestampString(adapter.dateFormat) - - // Set binding.cover - binding.cover.clear() - binding.cover.loadLibraryManga(manga) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadItem.kt deleted file mode 100644 index d08c40bf13..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadItem.kt +++ /dev/null @@ -1,40 +0,0 @@ -package eu.kanade.tachiyomi.ui.recently_read - -import android.view.View -import androidx.recyclerview.widget.RecyclerView -import eu.davidea.flexibleadapter.FlexibleAdapter -import eu.davidea.flexibleadapter.items.AbstractFlexibleItem -import eu.davidea.flexibleadapter.items.IFlexible -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory - -class RecentlyReadItem(val mch: MangaChapterHistory) : AbstractFlexibleItem() { - - override fun getLayoutRes(): Int { - return R.layout.recently_read_item - } - - override fun createViewHolder(view: View, adapter: FlexibleAdapter>): RecentlyReadHolder { - return RecentlyReadHolder(view, adapter as RecentlyReadAdapter) - } - - override fun bindViewHolder( - adapter: FlexibleAdapter>, - holder: RecentlyReadHolder, - position: Int, - payloads: MutableList? - ) { - holder.bind(mch) - } - - override fun equals(other: Any?): Boolean { - if (other is RecentlyReadItem) { - return mch.manga.id == other.mch.manga.id - } - return false - } - - override fun hashCode(): Int { - return mch.manga.id!!.hashCode() - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadPresenter.kt deleted file mode 100644 index d79b8442a6..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadPresenter.kt +++ /dev/null @@ -1,131 +0,0 @@ -package eu.kanade.tachiyomi.ui.recently_read - -import eu.kanade.tachiyomi.data.database.DatabaseHelper -import eu.kanade.tachiyomi.data.database.models.Chapter -import eu.kanade.tachiyomi.data.database.models.History -import eu.kanade.tachiyomi.data.database.models.Manga -import eu.kanade.tachiyomi.util.system.executeOnIO -import eu.kanade.tachiyomi.util.system.launchUI -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import uy.kohesive.injekt.injectLazy -import java.util.Calendar -import java.util.Comparator -import java.util.Date - -/** - * Presenter of RecentlyReadFragment. - * Contains information and data for fragment. - * Observable updates should be called from here. - */ -class RecentlyReadPresenter(private val view: RecentlyReadController) { - - /** - * Used to connect to database - */ - val db: DatabaseHelper by injectLazy() - var lastCount = 25 - var lastSearch = "" - - fun requestNext(search: String = "") { - lastCount += 25 - lastSearch = search - updateList(search) - } - - /** - * Get all recent manga up to a point - * @return list of history - */ - private suspend fun getRecentMangaLimit(search: String = ""): List { - // Set date for recent manga - val cal = Calendar.getInstance() - cal.time = Date() - cal.add(Calendar.YEAR, -50) - - return db.getRecentMangaLimit(cal.time, lastCount, search).executeOnIO() - .map(::RecentlyReadItem) - } - - /** - * Reset last read of chapter to 0L - * @param history history belonging to chapter - */ - fun removeFromHistory(history: History) { - history.last_read = 0L - db.updateHistoryLastRead(history).executeAsBlocking() - updateList() - } - - suspend fun refresh(search: String? = null): List { - val manga = getRecentMangaLimit(search ?: "") - checkIfNew(manga.size, search) - lastSearch = search ?: lastSearch - lastCount = manga.size - return manga - } - - private fun updateList(search: String? = null) { - launchUI { - val manga = withContext(Dispatchers.IO) { getRecentMangaLimit(search ?: "") } - checkIfNew(manga.size, search) - lastSearch = search ?: lastSearch - lastCount = manga.size - view.onNextManga(manga) - } - } - - private fun checkIfNew(newCount: Int, newSearch: String?) { - if (lastCount > newCount && newSearch == lastSearch) { - view.onAddPageError() - } - } - - /** - * Removes all chapters belonging to manga from history. - * @param mangaId id of manga - */ - fun removeAllFromHistory(mangaId: Long) { - val history = db.getHistoryByMangaId(mangaId).executeAsBlocking() - history.forEach { it.last_read = 0L } - db.updateHistoryLastRead(history).executeAsBlocking() - updateList() - } - - /** - * Retrieves the next chapter of the given one. - * - * @param chapter the chapter of the history object. - * @param manga the manga of the chapter. - */ - fun getNextChapter(chapter: Chapter, manga: Manga): Chapter? { - if (!chapter.read) { - return chapter - } - - val sortFunction: (Chapter, Chapter) -> Int = when (manga.sorting) { - Manga.SORTING_SOURCE -> { c1, c2 -> c2.source_order.compareTo(c1.source_order) } - Manga.SORTING_NUMBER -> { c1, c2 -> c1.chapter_number.compareTo(c2.chapter_number) } - else -> throw NotImplementedError("Unknown sorting method") - } - - val chapters = db.getChapters(manga).executeAsBlocking() - .sortedWith(Comparator { c1, c2 -> sortFunction(c1, c2) }) - - val currChapterIndex = chapters.indexOfFirst { chapter.id == it.id } - return when (manga.sorting) { - Manga.SORTING_SOURCE -> chapters.getOrNull(currChapterIndex + 1) - Manga.SORTING_NUMBER -> { - val chapterNumber = chapter.chapter_number - - ((currChapterIndex + 1) until chapters.size) - .map { chapters[it] } - .firstOrNull { - it.chapter_number > chapterNumber && - it.chapter_number <= chapterNumber + 1 - } - } - else -> throw NotImplementedError("Unknown sorting method") - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/DateItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/DateItem.kt similarity index 95% rename from app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/DateItem.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/recents/DateItem.kt index 81e8a2e317..82c974bf3c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/DateItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/DateItem.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.ui.recent_updates +package eu.kanade.tachiyomi.ui.recents import android.text.format.DateUtils import android.view.View @@ -11,8 +11,7 @@ import eu.davidea.viewholders.FlexibleViewHolder import eu.kanade.tachiyomi.R import java.util.Date -class DateItem(val date: Date, val addedString: Boolean = false) : AbstractHeaderItem() { +class DateItem(val date: Date, val addedString: Boolean = false) : AbstractHeaderItem() { override fun getLayoutRes(): Int { return R.layout.recent_chapters_section_item diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt index b15c6e459c..9d647fe077 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt @@ -33,7 +33,6 @@ import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.RootSearchInterface import eu.kanade.tachiyomi.ui.manga.MangaDetailsController import eu.kanade.tachiyomi.ui.reader.ReaderActivity -import eu.kanade.tachiyomi.ui.recently_read.RemoveHistoryDialog import eu.kanade.tachiyomi.ui.source.browse.ProgressItem import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.spToPx diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsPresenter.kt index 6d9dd77eb3..d8658d19ef 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsPresenter.kt @@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.data.library.LibraryServiceListener import eu.kanade.tachiyomi.data.library.LibraryUpdateService import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.source.SourceManager -import eu.kanade.tachiyomi.ui.recent_updates.DateItem import eu.kanade.tachiyomi.util.system.executeOnIO import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RemoveHistoryDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RemoveHistoryDialog.kt similarity index 97% rename from app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RemoveHistoryDialog.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/recents/RemoveHistoryDialog.kt index 141e5f80af..266c80f399 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RemoveHistoryDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RemoveHistoryDialog.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.ui.recently_read +package eu.kanade.tachiyomi.ui.recents import android.app.Dialog import android.os.Bundle