mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-01 22:58:57 +01:00
Added recently read tab (#316)
This commit is contained in:
@@ -13,7 +13,8 @@ import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
|
||||
import eu.kanade.tachiyomi.ui.catalogue.CatalogueFragment
|
||||
import eu.kanade.tachiyomi.ui.download.DownloadFragment
|
||||
import eu.kanade.tachiyomi.ui.library.LibraryFragment
|
||||
import eu.kanade.tachiyomi.ui.recent.RecentChaptersFragment
|
||||
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersFragment
|
||||
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadFragment
|
||||
import eu.kanade.tachiyomi.ui.setting.SettingsActivity
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.toolbar.*
|
||||
@@ -50,6 +51,7 @@ class MainActivity : BaseActivity() {
|
||||
when (item.itemId) {
|
||||
R.id.nav_drawer_library -> setFragment(LibraryFragment.newInstance())
|
||||
R.id.nav_drawer_recent_updates -> setFragment(RecentChaptersFragment.newInstance())
|
||||
R.id.nav_drawer_recent_manga -> setFragment(RecentlyReadFragment.newInstance())
|
||||
R.id.nav_drawer_catalogues -> setFragment(CatalogueFragment.newInstance())
|
||||
R.id.nav_drawer_downloads -> setFragment(DownloadFragment.newInstance())
|
||||
R.id.nav_drawer_settings -> startActivity(Intent(this, SettingsActivity::class.java))
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.os.Bundle
|
||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||
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.data.database.models.MangaSync
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
@@ -24,6 +25,7 @@ import rx.schedulers.Schedulers
|
||||
import rx.subjects.PublishSubject
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class ReaderPresenter : BasePresenter<ReaderActivity>() {
|
||||
@@ -289,6 +291,7 @@ class ReaderPresenter : BasePresenter<ReaderActivity>() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check whether the given chapter is downloaded
|
||||
fun isChapterDownloaded(chapter: Chapter): Boolean {
|
||||
return downloadManager.isChapterDownloaded(source, manga, chapter)
|
||||
@@ -340,6 +343,12 @@ class ReaderPresenter : BasePresenter<ReaderActivity>() {
|
||||
}
|
||||
}
|
||||
db.updateChapterProgress(chapter).asRxObservable().subscribe()
|
||||
// Update last read data
|
||||
db.updateHistoryLastRead(History.create(chapter)
|
||||
.apply { last_read = Date().time })
|
||||
.asRxObservable()
|
||||
.doOnError { Timber.e(it.message) }
|
||||
.subscribe()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.kanade.tachiyomi.ui.recent
|
||||
package eu.kanade.tachiyomi.ui.recent_updates
|
||||
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.view.View
|
||||
@@ -72,7 +72,7 @@ class RecentChaptersAdapter(val fragment: RecentChaptersFragment) : FlexibleAdap
|
||||
// Check which view type and set correct values.
|
||||
when (viewType) {
|
||||
VIEW_TYPE_CHAPTER -> {
|
||||
view = parent.inflate(R.layout.item_recent_chapter)
|
||||
view = parent.inflate(R.layout.item_recent_chapters)
|
||||
return RecentChaptersHolder(view, this, fragment)
|
||||
}
|
||||
VIEW_TYPE_SECTION -> {
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.kanade.tachiyomi.ui.recent
|
||||
package eu.kanade.tachiyomi.ui.recent_updates
|
||||
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.DialogFragment
|
||||
@@ -213,7 +213,7 @@ class RecentChaptersFragment : BaseRxFragment<RecentChaptersPresenter>(), Action
|
||||
*/
|
||||
fun onNextMangaChapters(chapters: List<Any>) {
|
||||
(activity as MainActivity).updateEmptyView(chapters.isEmpty(),
|
||||
R.string.information_no_recent, R.drawable.ic_history_black_128dp)
|
||||
R.string.information_no_recent, R.drawable.ic_update_black_128dp)
|
||||
|
||||
destroyActionModeIfNeeded()
|
||||
adapter.setItems(chapters)
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.kanade.tachiyomi.ui.recent
|
||||
package eu.kanade.tachiyomi.ui.recent_updates
|
||||
|
||||
import android.view.View
|
||||
import android.widget.PopupMenu
|
||||
@@ -7,11 +7,11 @@ import eu.kanade.tachiyomi.data.database.models.MangaChapter
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.util.getResourceColor
|
||||
import kotlinx.android.synthetic.main.item_recent_chapter.view.*
|
||||
import kotlinx.android.synthetic.main.item_recent_chapters.view.*
|
||||
|
||||
/**
|
||||
* Holder that contains chapter item
|
||||
* Uses R.layout.item_recent_chapter.
|
||||
* Uses R.layout.item_recent_chapters.
|
||||
* UI related actions should be called from here.
|
||||
*
|
||||
* @param view the inflated view for this holder.
|
||||
@@ -19,7 +19,7 @@ import kotlinx.android.synthetic.main.item_recent_chapter.view.*
|
||||
* @param listener a listener to react to single tap and long tap events.
|
||||
* @constructor creates a new recent chapter holder.
|
||||
*/
|
||||
class RecentChaptersHolder(view: View, private val adapter: RecentChaptersAdapter, listener: FlexibleViewHolder.OnListItemClickListener) :
|
||||
class RecentChaptersHolder(view: View, private val adapter: RecentChaptersAdapter, listener: OnListItemClickListener) :
|
||||
FlexibleViewHolder(view, adapter, listener) {
|
||||
/**
|
||||
* Color of read chapter
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.kanade.tachiyomi.ui.recent
|
||||
package eu.kanade.tachiyomi.ui.recent_updates
|
||||
|
||||
import android.os.Bundle
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.kanade.tachiyomi.ui.recent
|
||||
package eu.kanade.tachiyomi.ui.recent_updates
|
||||
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.text.format.DateUtils
|
||||
@@ -0,0 +1,52 @@
|
||||
package eu.kanade.tachiyomi.ui.recently_read
|
||||
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.view.ViewGroup
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
|
||||
import eu.kanade.tachiyomi.util.inflate
|
||||
|
||||
/**
|
||||
* Adapter of RecentlyReadHolder.
|
||||
* Connection between Fragment and Holder
|
||||
* Holder updates should be called from here.
|
||||
*
|
||||
* @param fragment a RecentlyReadFragment object
|
||||
* @constructor creates an instance of the adapter.
|
||||
*/
|
||||
class RecentlyReadAdapter(val fragment: RecentlyReadFragment) : FlexibleAdapter<RecyclerView.ViewHolder, Any>() {
|
||||
/**
|
||||
* Called when ViewHolder is created
|
||||
* @param parent parent View
|
||||
* @param viewType int containing viewType
|
||||
*/
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder? {
|
||||
val view = parent.inflate(R.layout.item_recent_manga)
|
||||
return RecentlyReadHolder(view, this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when ViewHolder is bind
|
||||
* @param holder bind holder
|
||||
* @param position position of holder
|
||||
*/
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {
|
||||
val item = getItem(position) as MangaChapterHistory
|
||||
(holder as RecentlyReadHolder).onSetValues(item)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update items
|
||||
* @param items items
|
||||
*/
|
||||
fun setItems(items: List<MangaChapterHistory>) {
|
||||
mItems = items
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun updateDataSet(param: String?) {
|
||||
// Empty function
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package eu.kanade.tachiyomi.ui.recently_read
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import eu.kanade.tachiyomi.R
|
||||
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.data.database.models.MangaChapterHistory
|
||||
import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaActivity
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.widget.NpaLinearLayoutManager
|
||||
import kotlinx.android.synthetic.main.fragment_recent_manga.*
|
||||
import nucleus.factory.RequiresPresenter
|
||||
|
||||
/**
|
||||
* Fragment that shows recently read manga.
|
||||
* Uses R.layout.fragment_recent_manga.
|
||||
* UI related actions should be called from here.
|
||||
*/
|
||||
@RequiresPresenter(RecentlyReadPresenter::class)
|
||||
class RecentlyReadFragment : BaseRxFragment<RecentlyReadPresenter>() {
|
||||
companion object {
|
||||
/**
|
||||
* Create new RecentChaptersFragment.
|
||||
*
|
||||
*/
|
||||
@JvmStatic
|
||||
fun newInstance(): RecentlyReadFragment {
|
||||
return RecentlyReadFragment()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter containing the recent manga.
|
||||
*/
|
||||
lateinit var adapter: RecentlyReadAdapter
|
||||
private set
|
||||
|
||||
/**
|
||||
* Called when view gets created
|
||||
*
|
||||
* @param inflater layout inflater
|
||||
* @param container view group
|
||||
* @param savedState status of saved state
|
||||
*/
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_recent_manga, container, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when view is created
|
||||
*
|
||||
* @param view created view
|
||||
* @param savedInstanceState status of saved sate
|
||||
*/
|
||||
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
|
||||
// Initialize adapter
|
||||
recycler.layoutManager = NpaLinearLayoutManager(activity)
|
||||
adapter = RecentlyReadAdapter(this)
|
||||
recycler.setHasFixedSize(true)
|
||||
recycler.adapter = adapter
|
||||
|
||||
// Update toolbar text
|
||||
setToolbarTitle(R.string.label_recent_manga)
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate adapter with chapters
|
||||
*
|
||||
* @param mangaHistory list of manga history
|
||||
*/
|
||||
fun onNextManga(mangaHistory: List<MangaChapterHistory>) {
|
||||
(activity as MainActivity).updateEmptyView(mangaHistory.isEmpty(),
|
||||
R.string.information_no_recent_manga, R.drawable.ic_glasses_black_128dp)
|
||||
|
||||
adapter.setItems(mangaHistory)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset last read of chapter to 0L
|
||||
* @param history history belonging to chapter
|
||||
*/
|
||||
fun removeFromHistory(history: History) {
|
||||
presenter.removeFromHistory(history)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all chapters belonging to manga from library
|
||||
* @param mangaId id of manga
|
||||
*/
|
||||
fun removeAllFromHistory(mangaId: Long) {
|
||||
presenter.removeAllFromHistory(mangaId)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
/**
|
||||
* Open chapter to continue reading
|
||||
* @param chapter chapter that is opened
|
||||
* @param manga manga belonging to chapter
|
||||
*/
|
||||
fun openChapter(chapter: Chapter, manga: Manga) {
|
||||
val intent = ReaderActivity.newIntent(activity, manga, chapter)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Open manga info page
|
||||
* @param manga manga belonging to info page
|
||||
*/
|
||||
fun openMangaInfo(manga: Manga) {
|
||||
val intent = MangaActivity.newIntent(activity, manga, true)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp of last read
|
||||
* @param history history containing time of last read
|
||||
*/
|
||||
fun getLastRead(history: History): String? {
|
||||
return presenter.getLastRead(history)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package eu.kanade.tachiyomi.ui.recently_read
|
||||
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.view.View
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
|
||||
import eu.kanade.tachiyomi.data.source.SourceManager
|
||||
import kotlinx.android.synthetic.main.dialog_remove_recently.view.*
|
||||
import kotlinx.android.synthetic.main.item_recent_manga.view.*
|
||||
import java.text.DecimalFormat
|
||||
import java.text.DecimalFormatSymbols
|
||||
|
||||
/**
|
||||
* Holder that contains recent manga item
|
||||
* Uses R.layout.item_recent_manga.
|
||||
* 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, private val adapter: RecentlyReadAdapter) :
|
||||
RecyclerView.ViewHolder(view) {
|
||||
|
||||
/**
|
||||
* DecimalFormat used to display correct chapter number
|
||||
*/
|
||||
private val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols().apply { decimalSeparator = '.' })
|
||||
|
||||
/**
|
||||
* Set values of view
|
||||
*
|
||||
* @param item item containing history information
|
||||
*/
|
||||
fun onSetValues(item: MangaChapterHistory) {
|
||||
// Retrieve objects
|
||||
val manga = item.mangaChapter.manga
|
||||
val chapter = item.mangaChapter.chapter
|
||||
val history = item.history
|
||||
|
||||
// Set manga title
|
||||
itemView.manga_title.text = manga.title
|
||||
|
||||
// Set source + chapter title
|
||||
val formattedNumber = decimalFormat.format(chapter.chapter_number.toDouble())
|
||||
itemView.manga_source.text = itemView.context.getString(R.string.recent_manga_source)
|
||||
.format(SourceManager(adapter.fragment.context).get(manga.source)?.name, formattedNumber)
|
||||
|
||||
// Set last read timestamp title
|
||||
itemView.last_read.text = adapter.fragment.getLastRead(history)
|
||||
|
||||
// Set cover
|
||||
if (!manga.thumbnail_url.isNullOrEmpty()) {
|
||||
Glide.with(itemView.context)
|
||||
.load(manga)
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESULT)
|
||||
.centerCrop()
|
||||
.into(itemView.cover)
|
||||
}
|
||||
|
||||
// Set remove clickListener
|
||||
itemView.remove.setOnClickListener {
|
||||
MaterialDialog.Builder(itemView.context)
|
||||
.title(R.string.action_remove)
|
||||
.customView(R.layout.dialog_remove_recently, true)
|
||||
.positiveText(R.string.action_remove)
|
||||
.negativeText(android.R.string.cancel)
|
||||
.onPositive { materialDialog, dialogAction ->
|
||||
// Check if user wants all chapters reset
|
||||
if (materialDialog.customView?.removeAll?.isChecked as Boolean) {
|
||||
adapter.fragment.removeAllFromHistory(manga.id)
|
||||
} else {
|
||||
adapter.fragment.removeFromHistory(history)
|
||||
}
|
||||
}
|
||||
.onNegative { materialDialog, dialogAction ->
|
||||
materialDialog.dismiss()
|
||||
}
|
||||
.show();
|
||||
}
|
||||
|
||||
// Set continue reading clickListener
|
||||
itemView.resume.setOnClickListener {
|
||||
adapter.fragment.openChapter(chapter, manga)
|
||||
}
|
||||
|
||||
// Set open manga info clickListener
|
||||
itemView.cover.setOnClickListener {
|
||||
adapter.fragment.openMangaInfo(manga)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package eu.kanade.tachiyomi.ui.recently_read
|
||||
|
||||
import android.os.Bundle
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.History
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import timber.log.Timber
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* The id of the restartable.
|
||||
*/
|
||||
const private val GET_RECENT_MANGA = 1
|
||||
|
||||
/**
|
||||
* Presenter of RecentlyReadFragment.
|
||||
* Contains information and data for fragment.
|
||||
* Observable updates should be called from here.
|
||||
*/
|
||||
class RecentlyReadPresenter : BasePresenter<RecentlyReadFragment>() {
|
||||
/**
|
||||
* Used to connect to database
|
||||
*/
|
||||
@Inject lateinit var db: DatabaseHelper
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
// Used to get recent manga
|
||||
restartableLatestCache(GET_RECENT_MANGA,
|
||||
{ getRecentMangaObservable() },
|
||||
{ recentMangaFragment, manga ->
|
||||
// Update adapter to show recent manga's
|
||||
recentMangaFragment.onNextManga(manga)
|
||||
}
|
||||
)
|
||||
|
||||
if (savedState == null) {
|
||||
// Start fetching recent manga
|
||||
start(GET_RECENT_MANGA)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get recent manga observable
|
||||
* @return list of history
|
||||
*/
|
||||
fun getRecentMangaObservable(): Observable<MutableList<MangaChapterHistory>> {
|
||||
// Set date for recent manga
|
||||
val cal = Calendar.getInstance()
|
||||
cal.time = Date()
|
||||
cal.add(Calendar.MONTH, -1)
|
||||
|
||||
return db.getRecentManga(cal.time).asRxObservable()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset last read of chapter to 0L
|
||||
* @param history history belonging to chapter
|
||||
*/
|
||||
fun removeFromHistory(history: History) {
|
||||
history.last_read = 0L
|
||||
db.updateHistoryLastRead(history).asRxObservable()
|
||||
.doOnError { Timber.e(it.message) }.subscribe()
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all chapters belonging to manga from library
|
||||
* @param mangaId id of manga
|
||||
*/
|
||||
fun removeAllFromHistory(mangaId: Long) {
|
||||
db.getHistoryByMangaId(mangaId).asRxObservable()
|
||||
.take(1)
|
||||
.flatMapIterable { it }
|
||||
.doOnError { Timber.e(it.message) }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ result -> removeFromHistory(result) })
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp of last read
|
||||
* @param history history containing time of last read
|
||||
*/
|
||||
fun getLastRead(history: History): String? {
|
||||
return SimpleDateFormat("dd-MM-yyyy HH:mm",
|
||||
Locale.getDefault()).format(Date(history.last_read))
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user