Update history
This commit is contained in:
@@ -3,7 +3,6 @@ package org.koitharu.kotatsu.core.db
|
||||
import androidx.room.*
|
||||
import org.koitharu.kotatsu.core.db.entity.HistoryEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.HistoryWithManga
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
|
||||
|
||||
@Dao
|
||||
@@ -25,19 +24,15 @@ abstract class HistoryDao {
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
abstract suspend fun insert(entity: HistoryEntity): Long
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
abstract suspend fun insertManga(manga: MangaEntity): Long
|
||||
|
||||
@Query("UPDATE history SET page = :page, chapter_id = :chapterId, updated_at = :updatedAt WHERE manga_id = :mangaId")
|
||||
abstract suspend fun update(mangaId: Long, page: Int, chapterId: Long, updatedAt: Long): Int
|
||||
|
||||
suspend fun update(entity: HistoryWithManga) = update(entity.manga.id, entity.history.page, entity.history.chapterId, entity.history.updatedAt)
|
||||
suspend fun update(entity: HistoryEntity) = update(entity.mangaId, entity.page, entity.chapterId, entity.updatedAt)
|
||||
|
||||
@Transaction
|
||||
open suspend fun upsert(entity: HistoryWithManga) {
|
||||
open suspend fun upsert(entity: HistoryEntity) {
|
||||
if (update(entity) == 0) {
|
||||
insertManga(entity.manga)
|
||||
insert(entity.history)
|
||||
insert(entity)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
40
app/src/main/java/org/koitharu/kotatsu/core/db/MangaDao.kt
Normal file
40
app/src/main/java/org/koitharu/kotatsu/core/db/MangaDao.kt
Normal file
@@ -0,0 +1,40 @@
|
||||
package org.koitharu.kotatsu.core.db
|
||||
|
||||
import androidx.room.*
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaTagsEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||
|
||||
@Dao
|
||||
abstract class MangaDao {
|
||||
|
||||
@Query("SELECT * FROM manga")
|
||||
abstract suspend fun getAllManga(): List<MangaEntity>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
abstract suspend fun insert(manga: MangaEntity): Long
|
||||
|
||||
@Update(onConflict = OnConflictStrategy.IGNORE)
|
||||
abstract suspend fun update(manga: MangaEntity): Int
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
abstract suspend fun insertTagRelation(tag: MangaTagsEntity): Long
|
||||
|
||||
@Query("DELETE FROM manga_tags WHERE manga_id = :mangaId")
|
||||
abstract suspend fun clearTagRelation(mangaId: Long)
|
||||
|
||||
@Transaction
|
||||
open suspend fun upsert(manga: MangaEntity, tags: Iterable<TagEntity>? = null) {
|
||||
if (update(manga) <= 0) {
|
||||
insert(manga)
|
||||
if (tags != null) {
|
||||
clearTagRelation(manga.id)
|
||||
tags.map {
|
||||
MangaTagsEntity(manga.id, it.id)
|
||||
}.forEach {
|
||||
insertTagRelation(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,15 @@ import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import org.koitharu.kotatsu.core.db.entity.HistoryEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaTagsEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||
|
||||
@Database(entities = [MangaEntity::class, TagEntity::class, HistoryEntity::class], version = 1)
|
||||
@Database(entities = [MangaEntity::class, TagEntity::class, HistoryEntity::class, MangaTagsEntity::class], version = 1)
|
||||
abstract class MangaDatabase : RoomDatabase() {
|
||||
|
||||
abstract fun historyDao(): HistoryDao
|
||||
|
||||
abstract fun tagsDao(): TagsDao
|
||||
|
||||
abstract fun mangaDao(): MangaDao
|
||||
}
|
||||
@@ -1,14 +1,26 @@
|
||||
package org.koitharu.kotatsu.core.db
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.*
|
||||
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||
|
||||
@Dao
|
||||
interface TagsDao {
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM tags")
|
||||
fun getAllTags(): List<TagEntity>
|
||||
suspend fun getAllTags(): List<TagEntity>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
suspend fun insert(tag: TagEntity): Long
|
||||
|
||||
@Update(onConflict = OnConflictStrategy.IGNORE)
|
||||
suspend fun update(tag: TagEntity): Int
|
||||
|
||||
@Transaction
|
||||
suspend fun upsert(tags: Iterable<TagEntity>) {
|
||||
tags.forEach { tag ->
|
||||
if (update(tag) <= 0) {
|
||||
insert(tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.koitharu.kotatsu.core.db.entity
|
||||
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Junction
|
||||
import androidx.room.Relation
|
||||
|
||||
data class HistoryWithManga(
|
||||
@@ -9,5 +10,11 @@ data class HistoryWithManga(
|
||||
parentColumn = "manga_id",
|
||||
entityColumn = "manga_id"
|
||||
)
|
||||
val manga: MangaEntity
|
||||
val manga: MangaEntity,
|
||||
@Relation(
|
||||
parentColumn = "manga_id",
|
||||
entityColumn = "tag_id",
|
||||
associateBy = Junction(MangaTagsEntity::class)
|
||||
)
|
||||
val tags: List<TagEntity>
|
||||
)
|
||||
@@ -6,6 +6,7 @@ import androidx.room.PrimaryKey
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.model.MangaState
|
||||
import org.koitharu.kotatsu.core.model.MangaTag
|
||||
|
||||
@Entity(tableName = "manga")
|
||||
data class MangaEntity(
|
||||
@@ -22,7 +23,7 @@ data class MangaEntity(
|
||||
@ColumnInfo(name = "source") val source: String
|
||||
) {
|
||||
|
||||
fun toManga() = Manga(
|
||||
fun toManga(tags: Set<MangaTag> = emptySet()) = Manga(
|
||||
id = this.id,
|
||||
title = this.title,
|
||||
localizedTitle = this.localizedTitle,
|
||||
@@ -32,8 +33,8 @@ data class MangaEntity(
|
||||
url = this.url,
|
||||
coverUrl = this.coverUrl,
|
||||
largeCoverUrl = this.largeCoverUrl,
|
||||
source = MangaSource.valueOf(this.source)
|
||||
// tags = this.tags.map(TagEntity::toMangaTag).toSet()
|
||||
source = MangaSource.valueOf(this.source),
|
||||
tags = tags
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -9,8 +9,8 @@ import org.koitharu.kotatsu.core.parser.site.SelfMangaRepository
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
@Parcelize
|
||||
enum class MangaSource(val title: String, val cls: Class<out MangaRepository>): Parcelable {
|
||||
READMANGA_RU("ReadManga", ReadmangaRepository::class.java),
|
||||
MINTMANGA("MintManga", MintMangaRepository::class.java),
|
||||
SELFMANGA("SelfManga", SelfMangaRepository::class.java)
|
||||
enum class MangaSource(val title: String, val locale: String, val cls: Class<out MangaRepository>): Parcelable {
|
||||
READMANGA_RU("ReadManga", "ru", ReadmangaRepository::class.java),
|
||||
MINTMANGA("MintManga", "ru", MintMangaRepository::class.java),
|
||||
SELFMANGA("SelfManga", "ru", SelfMangaRepository::class.java)
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package org.koitharu.kotatsu.domain
|
||||
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.inject
|
||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||
import org.koitharu.kotatsu.core.db.entity.HistoryEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.HistoryWithManga
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import java.util.*
|
||||
|
||||
class HistoryRepository : KoinComponent {
|
||||
|
||||
private val db: MangaDatabase by inject()
|
||||
|
||||
suspend fun getList(offset: Int) : List<Manga> {
|
||||
val entities = db.historyDao().getAll(offset, 20, "updated_by")
|
||||
return entities.map { it.manga.toManga() }
|
||||
}
|
||||
|
||||
suspend fun addOrUpdate(manga: Manga, chapterId: Long, page: Int) {
|
||||
val dao = db.historyDao()
|
||||
val entity = HistoryEntity(
|
||||
mangaId = manga.id,
|
||||
createdAt = System.currentTimeMillis(),
|
||||
updatedAt = System.currentTimeMillis(),
|
||||
chapterId = chapterId,
|
||||
page = page
|
||||
)
|
||||
dao.upsert(
|
||||
HistoryWithManga(
|
||||
history = entity,
|
||||
manga = MangaEntity.from(manga)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getOne(manga: Manga): MangaHistory? {
|
||||
return db.historyDao().getOneOrNull(manga.id)?.let {
|
||||
MangaHistory(
|
||||
createdAt = Date(it.createdAt),
|
||||
updatedAt = Date(it.updatedAt),
|
||||
chapterId = it.chapterId,
|
||||
page = it.page
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun clear() {
|
||||
db.historyDao().clear()
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.domain
|
||||
package org.koitharu.kotatsu.domain.history
|
||||
|
||||
enum class ChapterExtra {
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package org.koitharu.kotatsu.domain.history
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.inject
|
||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||
import org.koitharu.kotatsu.core.db.entity.HistoryEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import java.util.*
|
||||
|
||||
class HistoryRepository : KoinComponent {
|
||||
|
||||
private val db: MangaDatabase by inject()
|
||||
|
||||
suspend fun getList(offset: Int): List<Manga> {
|
||||
val entities = db.historyDao().getAll(offset, 20, "updated_at")
|
||||
return entities.map { it.manga.toManga(it.tags.map(TagEntity::toMangaTag).toSet()) }
|
||||
}
|
||||
|
||||
suspend fun addOrUpdate(manga: Manga, chapterId: Long, page: Int) {
|
||||
val tags = manga.tags.map(TagEntity.Companion::fromMangaTag)
|
||||
db.tagsDao().upsert(tags)
|
||||
db.mangaDao().upsert(MangaEntity.from(manga), tags)
|
||||
db.historyDao().upsert(
|
||||
HistoryEntity(
|
||||
mangaId = manga.id,
|
||||
createdAt = System.currentTimeMillis(),
|
||||
updatedAt = System.currentTimeMillis(),
|
||||
chapterId = chapterId,
|
||||
page = page
|
||||
)
|
||||
)
|
||||
notifyHistoryChanged()
|
||||
}
|
||||
|
||||
suspend fun getOne(manga: Manga): MangaHistory? {
|
||||
return db.historyDao().getOneOrNull(manga.id)?.let {
|
||||
MangaHistory(
|
||||
createdAt = Date(it.createdAt),
|
||||
updatedAt = Date(it.updatedAt),
|
||||
chapterId = it.chapterId,
|
||||
page = it.page
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun clear() {
|
||||
db.historyDao().clear()
|
||||
notifyHistoryChanged()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val listeners = HashSet<OnHistoryChangeListener>()
|
||||
|
||||
fun subscribe(listener: OnHistoryChangeListener) {
|
||||
listeners += listener
|
||||
}
|
||||
|
||||
fun unsubscribe(listener: OnHistoryChangeListener) {
|
||||
listeners += listener
|
||||
}
|
||||
|
||||
private suspend fun notifyHistoryChanged() {
|
||||
withContext(Dispatchers.Main) {
|
||||
listeners.forEach { x -> x.onHistoryChanged() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.koitharu.kotatsu.domain.history
|
||||
|
||||
interface OnHistoryChangeListener {
|
||||
|
||||
fun onHistoryChanged()
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.koitharu.kotatsu.ui.common
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
|
||||
abstract class BaseFullscreenActivity : BaseActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
if (hasFocus) hideSystemUI()
|
||||
}
|
||||
|
||||
private fun hideSystemUI() {
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_FULLSCREEN)
|
||||
}
|
||||
|
||||
protected fun showSystemUI() {
|
||||
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
|
||||
}
|
||||
|
||||
abstract fun onFullscreenModeChanged(isFullscreen: Boolean)
|
||||
}
|
||||
@@ -9,7 +9,7 @@ abstract class BaseRecyclerAdapter<T, E>(private val onItemClickListener: OnRecy
|
||||
RecyclerView.Adapter<BaseViewHolder<T, E>>(),
|
||||
KoinComponent {
|
||||
|
||||
private val dataSet = ArrayList<T>()
|
||||
protected val dataSet = ArrayList<T>()
|
||||
|
||||
init {
|
||||
@Suppress("LeakingThis")
|
||||
@@ -34,21 +34,25 @@ abstract class BaseRecyclerAdapter<T, E>(private val onItemClickListener: OnRecy
|
||||
val updater = AdapterUpdater(dataSet, newData, this::onGetItemId)
|
||||
dataSet.replaceWith(newData)
|
||||
updater(this)
|
||||
onDataSetChanged()
|
||||
}
|
||||
|
||||
fun appendData(newData: List<T>) {
|
||||
val pos = dataSet.size
|
||||
dataSet.addAll(newData)
|
||||
notifyItemRangeInserted(pos, newData.size)
|
||||
onDataSetChanged()
|
||||
}
|
||||
|
||||
fun appendItem(newItem: T) {
|
||||
dataSet.add(newItem)
|
||||
notifyItemInserted(dataSet.lastIndex)
|
||||
onDataSetChanged()
|
||||
}
|
||||
|
||||
fun removeItem(item: T) {
|
||||
removeItemAt(dataSet.indexOf(item))
|
||||
onDataSetChanged()
|
||||
}
|
||||
|
||||
fun removeItemAt(position: Int) {
|
||||
@@ -56,11 +60,13 @@ abstract class BaseRecyclerAdapter<T, E>(private val onItemClickListener: OnRecy
|
||||
dataSet.removeAt(position)
|
||||
notifyItemRemoved(position)
|
||||
}
|
||||
onDataSetChanged()
|
||||
}
|
||||
|
||||
fun clearData() {
|
||||
dataSet.clear()
|
||||
notifyDataSetChanged()
|
||||
onDataSetChanged()
|
||||
}
|
||||
|
||||
final override fun getItemCount() = dataSet.size
|
||||
@@ -70,6 +76,8 @@ abstract class BaseRecyclerAdapter<T, E>(private val onItemClickListener: OnRecy
|
||||
.also(this::onViewHolderCreated)
|
||||
}
|
||||
|
||||
protected open fun onDataSetChanged() = Unit
|
||||
|
||||
protected abstract fun getExtra(item: T, position: Int): E
|
||||
|
||||
protected open fun onViewHolderCreated(holder: BaseViewHolder<T, E>) = Unit
|
||||
|
||||
@@ -4,7 +4,7 @@ import android.view.ViewGroup
|
||||
import kotlinx.android.synthetic.main.item_chapter.*
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.domain.ChapterExtra
|
||||
import org.koitharu.kotatsu.domain.history.ChapterExtra
|
||||
import org.koitharu.kotatsu.ui.common.list.BaseViewHolder
|
||||
import org.koitharu.kotatsu.utils.ext.getThemeColor
|
||||
|
||||
|
||||
@@ -3,19 +3,21 @@ package org.koitharu.kotatsu.ui.details
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.domain.ChapterExtra
|
||||
import org.koitharu.kotatsu.domain.history.ChapterExtra
|
||||
import org.koitharu.kotatsu.ui.common.list.BaseRecyclerAdapter
|
||||
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
|
||||
|
||||
class ChaptersAdapter(onItemClickListener: OnRecyclerItemClickListener<MangaChapter>) :
|
||||
BaseRecyclerAdapter<MangaChapter, ChapterExtra>(onItemClickListener) {
|
||||
|
||||
var currentChapterPosition = RecyclerView.NO_POSITION
|
||||
var currentChapterId: Long? = null
|
||||
set(value) {
|
||||
field = value
|
||||
notifyDataSetChanged()
|
||||
updateCurrentPosition()
|
||||
}
|
||||
|
||||
private var currentChapterPosition = RecyclerView.NO_POSITION
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup) = ChapterHolder(parent)
|
||||
|
||||
override fun onGetItemId(item: MangaChapter) = item.id
|
||||
@@ -27,4 +29,19 @@ class ChaptersAdapter(onItemClickListener: OnRecyclerItemClickListener<MangaChap
|
||||
currentChapterPosition > position -> ChapterExtra.READ
|
||||
else -> ChapterExtra.UNREAD
|
||||
}
|
||||
|
||||
override fun onDataSetChanged() {
|
||||
super.onDataSetChanged()
|
||||
updateCurrentPosition()
|
||||
}
|
||||
|
||||
private fun updateCurrentPosition() {
|
||||
val pos = currentChapterId?.let {
|
||||
dataSet.indexOfFirst { x -> x.id == it }
|
||||
} ?: RecyclerView.NO_POSITION
|
||||
if (pos != currentChapterPosition) {
|
||||
currentChapterPosition = pos
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,9 +51,7 @@ class ChaptersFragment : BaseFragment(R.layout.fragment_chapters), MangaDetailsV
|
||||
}
|
||||
|
||||
override fun onHistoryChanged(history: MangaHistory?) {
|
||||
adapter.currentChapterPosition = history?.let {
|
||||
manga?.chapters?.indexOfFirst { x -> x.id == it.chapterId }
|
||||
} ?: RecyclerView.NO_POSITION
|
||||
adapter.currentChapterId = history?.chapterId
|
||||
}
|
||||
|
||||
override fun onItemClick(item: MangaChapter, position: Int, view: View) {
|
||||
|
||||
@@ -24,17 +24,9 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
|
||||
tabs.setupWithViewPager(pager)
|
||||
intent?.getParcelableExtra<Manga>(EXTRA_MANGA)?.let {
|
||||
presenter.loadDetails(it)
|
||||
presenter.loadHistory(it)
|
||||
} ?: finish()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
intent?.getParcelableExtra<Manga>(EXTRA_MANGA)?.let {
|
||||
presenter.loadHistory(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMangaUpdated(manga: Manga) {
|
||||
title = manga.title
|
||||
}
|
||||
|
||||
@@ -6,26 +6,29 @@ import kotlinx.coroutines.withContext
|
||||
import moxy.InjectViewState
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.domain.HistoryRepository
|
||||
import org.koitharu.kotatsu.domain.MangaProviderFactory
|
||||
import org.koitharu.kotatsu.domain.history.HistoryRepository
|
||||
import org.koitharu.kotatsu.domain.history.OnHistoryChangeListener
|
||||
import org.koitharu.kotatsu.ui.common.BasePresenter
|
||||
|
||||
@InjectViewState
|
||||
class MangaDetailsPresenter : BasePresenter<MangaDetailsView>() {
|
||||
class MangaDetailsPresenter : BasePresenter<MangaDetailsView>(), OnHistoryChangeListener {
|
||||
|
||||
private lateinit var historyRepository: HistoryRepository
|
||||
|
||||
private var isLoaded = false
|
||||
private var manga: Manga? = null
|
||||
|
||||
override fun onFirstViewAttach() {
|
||||
historyRepository = HistoryRepository()
|
||||
super.onFirstViewAttach()
|
||||
HistoryRepository.subscribe(this)
|
||||
}
|
||||
|
||||
fun loadDetails(manga: Manga, force: Boolean = false) {
|
||||
if (!force && isLoaded) {
|
||||
if (!force && this.manga == manga) {
|
||||
return
|
||||
}
|
||||
loadHistory(manga)
|
||||
viewState.onMangaUpdated(manga)
|
||||
launch {
|
||||
try {
|
||||
@@ -34,7 +37,7 @@ class MangaDetailsPresenter : BasePresenter<MangaDetailsView>() {
|
||||
MangaProviderFactory.create(manga.source).getDetails(manga)
|
||||
}
|
||||
viewState.onMangaUpdated(data)
|
||||
isLoaded = true
|
||||
this@MangaDetailsPresenter.manga = data
|
||||
} catch (e: Exception) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
e.printStackTrace()
|
||||
@@ -46,7 +49,7 @@ class MangaDetailsPresenter : BasePresenter<MangaDetailsView>() {
|
||||
}
|
||||
}
|
||||
|
||||
fun loadHistory(manga: Manga) {
|
||||
private fun loadHistory(manga: Manga) {
|
||||
launch {
|
||||
try {
|
||||
val history = withContext(Dispatchers.IO) {
|
||||
@@ -60,4 +63,13 @@ class MangaDetailsPresenter : BasePresenter<MangaDetailsView>() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHistoryChanged() {
|
||||
loadHistory(manga ?: return)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
HistoryRepository.unsubscribe(this)
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
|
||||
if (!supportFragmentManager.isStateSaved) {
|
||||
navigationView.setCheckedItem(R.id.nav_history)
|
||||
setPrimaryFragment(HistoryListFragment.newInstance())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,12 @@ abstract class MangaListFragment <E> : BaseFragment(R.layout.fragment_list), Man
|
||||
|
||||
override fun onListChanged(list: List<Manga>) {
|
||||
adapter.replaceData(list)
|
||||
layout_holder.isVisible = list.isEmpty()
|
||||
if (list.isEmpty()) {
|
||||
setUpEmptyListHolder()
|
||||
layout_holder.isVisible = true
|
||||
} else {
|
||||
layout_holder.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onListAppended(list: List<Manga>) {
|
||||
@@ -89,6 +94,10 @@ abstract class MangaListFragment <E> : BaseFragment(R.layout.fragment_list), Man
|
||||
override fun onError(e: Exception) {
|
||||
if (recyclerView.hasItems) {
|
||||
Snackbar.make(recyclerView, e.getDisplayMessage(resources), Snackbar.LENGTH_SHORT).show()
|
||||
} else {
|
||||
textView_holder.text = e.getDisplayMessage(resources)
|
||||
textView_holder.setCompoundDrawablesRelativeWithIntrinsicBounds(0, R.drawable.ic_error_large, 0, 0)
|
||||
layout_holder.isVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +117,11 @@ abstract class MangaListFragment <E> : BaseFragment(R.layout.fragment_list), Man
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun setUpEmptyListHolder() {
|
||||
textView_holder.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, null, null)
|
||||
textView_holder.setText(R.string.nothing_found)
|
||||
}
|
||||
|
||||
private fun initListMode(mode: ListMode) {
|
||||
val ctx = context ?: return
|
||||
val position = recyclerView.firstItem
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package org.koitharu.kotatsu.ui.main.list.history
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import kotlinx.android.synthetic.main.fragment_list.*
|
||||
import moxy.ktx.moxyPresenter
|
||||
import org.koitharu.kotatsu.R
|
||||
@@ -16,11 +14,6 @@ class HistoryListFragment : MangaListFragment<MangaHistory>(), MangaListView<Man
|
||||
|
||||
private val presenter by moxyPresenter(factory = ::HistoryListPresenter)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
textView_holder.setText(R.string.history_is_empty)
|
||||
}
|
||||
|
||||
override fun onRequestMoreItems(offset: Int) {
|
||||
presenter.loadList(offset)
|
||||
}
|
||||
@@ -42,6 +35,11 @@ class HistoryListFragment : MangaListFragment<MangaHistory>(), MangaListView<Man
|
||||
return getString(R.string.history)
|
||||
}
|
||||
|
||||
override fun setUpEmptyListHolder() {
|
||||
textView_holder.setText(R.string.history_is_empty)
|
||||
textView_holder.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance() = HistoryListFragment()
|
||||
|
||||
@@ -6,7 +6,7 @@ import kotlinx.coroutines.withContext
|
||||
import moxy.InjectViewState
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import org.koitharu.kotatsu.domain.HistoryRepository
|
||||
import org.koitharu.kotatsu.domain.history.HistoryRepository
|
||||
import org.koitharu.kotatsu.ui.common.BasePresenter
|
||||
import org.koitharu.kotatsu.ui.main.list.MangaListView
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
package org.koitharu.kotatsu.ui.main.list.remote
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import kotlinx.android.synthetic.main.fragment_list.*
|
||||
import moxy.ktx.moxyPresenter
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.ui.main.list.MangaListFragment
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
@@ -15,11 +11,6 @@ class RemoteListFragment : MangaListFragment<Unit>() {
|
||||
|
||||
private val source by arg<MangaSource>(ARG_SOURCE)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
textView_holder.setText(R.string.nothing_found)
|
||||
}
|
||||
|
||||
override fun onRequestMoreItems(offset: Int) {
|
||||
presenter.loadList(source, offset)
|
||||
}
|
||||
|
||||
@@ -6,17 +6,19 @@ import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updatePadding
|
||||
import kotlinx.android.synthetic.main.activity_reader.*
|
||||
import moxy.ktx.moxyPresenter
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import org.koitharu.kotatsu.core.model.MangaPage
|
||||
import org.koitharu.kotatsu.ui.common.BaseActivity
|
||||
import org.koitharu.kotatsu.ui.common.BaseFullscreenActivity
|
||||
import org.koitharu.kotatsu.utils.ext.showDialog
|
||||
|
||||
class ReaderActivity : BaseActivity(), ReaderView {
|
||||
class ReaderActivity : BaseFullscreenActivity(), ReaderView {
|
||||
|
||||
private val presenter by moxyPresenter { ReaderPresenter() }
|
||||
|
||||
@@ -29,7 +31,7 @@ class ReaderActivity : BaseActivity(), ReaderView {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_reader)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
bottomBar.inflateMenu(R.menu.opt_reader_bottom)
|
||||
toolbar_bottom.inflateMenu(R.menu.opt_reader_bottom)
|
||||
|
||||
state = savedInstanceState?.getParcelable(EXTRA_STATE)
|
||||
?: intent.getParcelableExtra<ReaderState>(EXTRA_STATE)
|
||||
@@ -45,6 +47,11 @@ class ReaderActivity : BaseActivity(), ReaderView {
|
||||
getString(R.string.chapter_d_of_d, state.chapter?.number ?: 0, size)
|
||||
}
|
||||
|
||||
appbar_bottom.setOnApplyWindowInsetsListener { view, insets ->
|
||||
view.updatePadding(bottom = insets.systemWindowInsetBottom)
|
||||
insets
|
||||
}
|
||||
|
||||
loader = PageLoader(this)
|
||||
adapter = PagesAdapter(loader)
|
||||
pager.adapter = adapter
|
||||
@@ -92,6 +99,11 @@ class ReaderActivity : BaseActivity(), ReaderView {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFullscreenModeChanged(isFullscreen: Boolean) {
|
||||
appbar_top.isGone = isFullscreen
|
||||
appbar_bottom.isGone = isFullscreen
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val EXTRA_STATE = "state"
|
||||
|
||||
@@ -5,7 +5,7 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import moxy.InjectViewState
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.domain.HistoryRepository
|
||||
import org.koitharu.kotatsu.domain.history.HistoryRepository
|
||||
import org.koitharu.kotatsu.domain.MangaProviderFactory
|
||||
import org.koitharu.kotatsu.ui.common.BasePresenter
|
||||
|
||||
|
||||
Reference in New Issue
Block a user