mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-19 22:39:18 +01:00
Add history date section headers
This commit is contained in:
parent
29eb87b7ef
commit
52434819c3
@ -19,7 +19,7 @@ import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
|||||||
import eu.kanade.tachiyomi.ui.main.ChangelogDialogController
|
import eu.kanade.tachiyomi.ui.main.ChangelogDialogController
|
||||||
import eu.kanade.tachiyomi.ui.setting.SettingsController
|
import eu.kanade.tachiyomi.ui.setting.SettingsController
|
||||||
import eu.kanade.tachiyomi.util.lang.launchNow
|
import eu.kanade.tachiyomi.util.lang.launchNow
|
||||||
import eu.kanade.tachiyomi.util.lang.toTimestampString
|
import eu.kanade.tachiyomi.util.lang.toDateTimestampString
|
||||||
import eu.kanade.tachiyomi.util.preference.defaultValue
|
import eu.kanade.tachiyomi.util.preference.defaultValue
|
||||||
import eu.kanade.tachiyomi.util.preference.onChange
|
import eu.kanade.tachiyomi.util.preference.onChange
|
||||||
import eu.kanade.tachiyomi.util.preference.onClick
|
import eu.kanade.tachiyomi.util.preference.onClick
|
||||||
@ -180,7 +180,7 @@ class AboutController : SettingsController() {
|
|||||||
DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault())
|
DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault())
|
||||||
outputDf.timeZone = TimeZone.getDefault()
|
outputDf.timeZone = TimeZone.getDefault()
|
||||||
|
|
||||||
return buildTime.toTimestampString(dateFormat)
|
return buildTime.toDateTimestampString(dateFormat)
|
||||||
} catch (e: ParseException) {
|
} catch (e: ParseException) {
|
||||||
return BuildConfig.BUILD_TIME
|
return BuildConfig.BUILD_TIME
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package eu.kanade.tachiyomi.ui.recent.updates
|
package eu.kanade.tachiyomi.ui.recent
|
||||||
|
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -11,10 +11,10 @@ import eu.davidea.viewholders.FlexibleViewHolder
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
class DateItem(val date: Date) : AbstractHeaderItem<DateItem.Holder>() {
|
class DateSectionItem(val date: Date) : AbstractHeaderItem<DateSectionItem.Holder>() {
|
||||||
|
|
||||||
override fun getLayoutRes(): Int {
|
override fun getLayoutRes(): Int {
|
||||||
return R.layout.updates_section_item
|
return R.layout.recent_section_item
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||||
@ -27,7 +27,7 @@ class DateItem(val date: Date) : AbstractHeaderItem<DateItem.Holder>() {
|
|||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other is DateItem) {
|
if (other is DateSectionItem) {
|
||||||
return date == other.date
|
return date == other.date
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -43,7 +43,7 @@ class DateItem(val date: Date) : AbstractHeaderItem<DateItem.Holder>() {
|
|||||||
|
|
||||||
val section_text: TextView = view.findViewById(R.id.section_text)
|
val section_text: TextView = view.findViewById(R.id.section_text)
|
||||||
|
|
||||||
fun bind(item: DateItem) {
|
fun bind(item: DateSectionItem) {
|
||||||
section_text.text = DateUtils.getRelativeTimeSpanString(item.date.time, now, DateUtils.DAY_IN_MILLIS)
|
section_text.text = DateUtils.getRelativeTimeSpanString(item.date.time, now, DateUtils.DAY_IN_MILLIS)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.ui.recent.history
|
package eu.kanade.tachiyomi.ui.recent.history
|
||||||
|
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import java.text.DateFormat
|
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import java.text.DecimalFormatSymbols
|
import java.text.DecimalFormatSymbols
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -34,9 +31,10 @@ class HistoryAdapter(controller: HistoryController) :
|
|||||||
val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols()
|
val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols()
|
||||||
.apply { decimalSeparator = '.' })
|
.apply { decimalSeparator = '.' })
|
||||||
|
|
||||||
private val preferences: PreferencesHelper by injectLazy()
|
init {
|
||||||
|
setDisplayHeadersAtStartUp(true)
|
||||||
val dateFormat: DateFormat = preferences.dateFormat().getOrDefault()
|
setStickyHeaders(true)
|
||||||
|
}
|
||||||
|
|
||||||
interface OnResumeClickListener {
|
interface OnResumeClickListener {
|
||||||
fun onResumeClick(position: Int)
|
fun onResumeClick(position: Int)
|
||||||
|
@ -61,7 +61,7 @@ class HistoryHolder(
|
|||||||
.format(adapter.sourceManager.getOrStub(manga.source).toString(), formattedNumber)
|
.format(adapter.sourceManager.getOrStub(manga.source).toString(), formattedNumber)
|
||||||
|
|
||||||
// Set last read timestamp title
|
// Set last read timestamp title
|
||||||
last_read.text = Date(history.last_read).toTimestampString(adapter.dateFormat)
|
last_read.text = Date(history.last_read).toTimestampString()
|
||||||
|
|
||||||
// Set cover
|
// Set cover
|
||||||
GlideApp.with(itemView.context).clear(cover)
|
GlideApp.with(itemView.context).clear(cover)
|
||||||
|
@ -3,12 +3,14 @@ package eu.kanade.tachiyomi.ui.recent.history
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractSectionableItem
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
|
import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
|
||||||
|
import eu.kanade.tachiyomi.ui.recent.DateSectionItem
|
||||||
|
|
||||||
class HistoryItem(val mch: MangaChapterHistory) : AbstractFlexibleItem<HistoryHolder>() {
|
class HistoryItem(val mch: MangaChapterHistory, header: DateSectionItem) :
|
||||||
|
AbstractSectionableItem<HistoryHolder, DateSectionItem>(header) {
|
||||||
|
|
||||||
override fun getLayoutRes(): Int {
|
override fun getLayoutRes(): Int {
|
||||||
return R.layout.history_item
|
return R.layout.history_item
|
||||||
@ -24,7 +26,6 @@ class HistoryItem(val mch: MangaChapterHistory) : AbstractFlexibleItem<HistoryHo
|
|||||||
position: Int,
|
position: Int,
|
||||||
payloads: List<Any?>?
|
payloads: List<Any?>?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
holder.bind(mch)
|
holder.bind(mch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,10 +5,14 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.History
|
import eu.kanade.tachiyomi.data.database.models.History
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
|
||||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||||
|
import eu.kanade.tachiyomi.ui.recent.DateSectionItem
|
||||||
|
import eu.kanade.tachiyomi.util.lang.toDateKey
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Comparator
|
import java.util.Comparator
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
import java.util.TreeMap
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -38,13 +42,21 @@ class HistoryPresenter : BasePresenter<HistoryController>() {
|
|||||||
* @return list of history
|
* @return list of history
|
||||||
*/
|
*/
|
||||||
fun getRecentMangaObservable(): Observable<List<HistoryItem>> {
|
fun getRecentMangaObservable(): Observable<List<HistoryItem>> {
|
||||||
// Set date for recent manga
|
// Set date limit for recent manga
|
||||||
val cal = Calendar.getInstance()
|
val cal = Calendar.getInstance()
|
||||||
cal.time = Date()
|
cal.time = Date()
|
||||||
cal.add(Calendar.MONTH, -1)
|
cal.add(Calendar.MONTH, -1)
|
||||||
|
|
||||||
return db.getRecentManga(cal.time).asRxObservable()
|
return db.getRecentManga(cal.time).asRxObservable()
|
||||||
.map { recents -> recents.map(::HistoryItem) }
|
.map { recents ->
|
||||||
|
val map = TreeMap<Date, MutableList<MangaChapterHistory>> { d1, d2 -> d2.compareTo(d1) }
|
||||||
|
val byDay = recents
|
||||||
|
.groupByTo(map, { it.history.last_read.toDateKey() })
|
||||||
|
byDay.flatMap {
|
||||||
|
val dateItem = DateSectionItem(it.key)
|
||||||
|
it.value.map { HistoryItem(it, dateItem) }
|
||||||
|
}
|
||||||
|
}
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,9 +9,10 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
|
import eu.kanade.tachiyomi.ui.recent.DateSectionItem
|
||||||
|
|
||||||
class UpdatesItem(val chapter: Chapter, val manga: Manga, header: DateItem) :
|
class UpdatesItem(val chapter: Chapter, val manga: Manga, header: DateSectionItem) :
|
||||||
AbstractSectionableItem<UpdatesHolder, DateItem>(header) {
|
AbstractSectionableItem<UpdatesHolder, DateSectionItem>(header) {
|
||||||
|
|
||||||
private var _status: Int = 0
|
private var _status: Int = 0
|
||||||
|
|
||||||
@ -41,7 +42,6 @@ class UpdatesItem(val chapter: Chapter, val manga: Manga, header: DateItem) :
|
|||||||
position: Int,
|
position: Int,
|
||||||
payloads: List<Any?>?
|
payloads: List<Any?>?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
holder.bind(this)
|
holder.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@ import eu.kanade.tachiyomi.data.download.model.Download
|
|||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||||
|
import eu.kanade.tachiyomi.ui.recent.DateSectionItem
|
||||||
|
import eu.kanade.tachiyomi.util.lang.toDateKey
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.TreeMap
|
import java.util.TreeMap
|
||||||
@ -60,9 +62,9 @@ class UpdatesPresenter(
|
|||||||
.map { mangaChapters ->
|
.map { mangaChapters ->
|
||||||
val map = TreeMap<Date, MutableList<MangaChapter>> { d1, d2 -> d2.compareTo(d1) }
|
val map = TreeMap<Date, MutableList<MangaChapter>> { d1, d2 -> d2.compareTo(d1) }
|
||||||
val byDay = mangaChapters
|
val byDay = mangaChapters
|
||||||
.groupByTo(map, { getMapKey(it.chapter.date_fetch) })
|
.groupByTo(map, { it.chapter.date_fetch.toDateKey() })
|
||||||
byDay.flatMap {
|
byDay.flatMap {
|
||||||
val dateItem = DateItem(it.key)
|
val dateItem = DateSectionItem(it.key)
|
||||||
it.value
|
it.value
|
||||||
.sortedWith(compareBy({ it.chapter.date_fetch }, { it.chapter.chapter_number })).asReversed()
|
.sortedWith(compareBy({ it.chapter.date_fetch }, { it.chapter.chapter_number })).asReversed()
|
||||||
.map { UpdatesItem(it.chapter, it.manga, dateItem) }
|
.map { UpdatesItem(it.chapter, it.manga, dateItem) }
|
||||||
@ -84,22 +86,6 @@ class UpdatesPresenter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns observable containing chapter status.
|
* Returns observable containing chapter status.
|
||||||
*
|
*
|
||||||
|
@ -1,10 +1,31 @@
|
|||||||
package eu.kanade.tachiyomi.util.lang
|
package eu.kanade.tachiyomi.util.lang
|
||||||
|
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
|
import java.util.Calendar
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
fun Date.toTimestampString(dateFormatter: DateFormat): String {
|
fun Date.toDateTimestampString(dateFormatter: DateFormat): String {
|
||||||
val date = dateFormatter.format(this)
|
val date = dateFormatter.format(this)
|
||||||
val time = DateFormat.getTimeInstance(DateFormat.SHORT).format(this)
|
val time = DateFormat.getTimeInstance(DateFormat.SHORT).format(this)
|
||||||
return "$date $time"
|
return "$date $time"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Date.toTimestampString(): String {
|
||||||
|
return DateFormat.getTimeInstance(DateFormat.SHORT).format(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get date as time key
|
||||||
|
*
|
||||||
|
* @param date desired date
|
||||||
|
* @return date as time key
|
||||||
|
*/
|
||||||
|
fun Long.toDateKey(): Date {
|
||||||
|
val cal = Calendar.getInstance()
|
||||||
|
cal.time = Date(this)
|
||||||
|
cal[Calendar.HOUR_OF_DAY] = 0
|
||||||
|
cal[Calendar.MINUTE] = 0
|
||||||
|
cal[Calendar.SECOND] = 0
|
||||||
|
cal[Calendar.MILLISECOND] = 0
|
||||||
|
return cal.time
|
||||||
|
}
|
||||||
|
@ -10,8 +10,6 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:paddingTop="4dp"
|
|
||||||
android:paddingBottom="4dp"
|
|
||||||
tools:listitem="@layout/history_item" />
|
tools:listitem="@layout/history_item" />
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.EmptyView
|
<eu.kanade.tachiyomi.widget.EmptyView
|
||||||
|
Loading…
Reference in New Issue
Block a user