From 64b38c561cec51b36c478b3f3ada6f287adc390e Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 2 Feb 2020 18:17:25 +0200 Subject: [PATCH] Update history --- app/.gitignore | 3 +- app/build.gradle | 6 ++ .../koitharu/kotatsu/core/db/HistoryDao.kt | 11 +-- .../org/koitharu/kotatsu/core/db/MangaDao.kt | 40 ++++++++++ .../koitharu/kotatsu/core/db/MangaDatabase.kt | 5 +- .../org/koitharu/kotatsu/core/db/TagsDao.kt | 22 ++++-- .../core/db/entity/HistoryWithManga.kt | 9 ++- .../kotatsu/core/db/entity/MangaEntity.kt | 7 +- .../kotatsu/core/model/MangaSource.kt | 8 +- .../kotatsu/domain/HistoryRepository.kt | 53 ------------- .../domain/{ => history}/ChapterExtra.kt | 2 +- .../domain/history/HistoryRepository.kt | 74 +++++++++++++++++++ .../domain/history/OnHistoryChangeListener.kt | 6 ++ .../ui/common/BaseFullscreenActivity.kt | 33 +++++++++ .../ui/common/list/BaseRecyclerAdapter.kt | 10 ++- .../kotatsu/ui/details/ChapterHolder.kt | 2 +- .../kotatsu/ui/details/ChaptersAdapter.kt | 23 +++++- .../kotatsu/ui/details/ChaptersFragment.kt | 4 +- .../ui/details/MangaDetailsActivity.kt | 8 -- .../ui/details/MangaDetailsPresenter.kt | 24 ++++-- .../koitharu/kotatsu/ui/main/MainActivity.kt | 1 + .../kotatsu/ui/main/list/MangaListFragment.kt | 16 +++- .../main/list/history/HistoryListFragment.kt | 12 ++- .../main/list/history/HistoryListPresenter.kt | 2 +- .../ui/main/list/remote/RemoteListFragment.kt | 9 --- .../kotatsu/ui/reader/ReaderActivity.kt | 18 ++++- .../kotatsu/ui/reader/ReaderPresenter.kt | 2 +- app/src/main/res/drawable/ic_bookmark_add.xml | 12 +++ app/src/main/res/drawable/ic_tune.xml | 11 +++ app/src/main/res/layout/activity_reader.xml | 35 +++++++-- app/src/main/res/layout/fragment_details.xml | 3 +- app/src/main/res/layout/item_manga_list.xml | 4 +- .../res/layout/item_manga_list_details.xml | 4 +- app/src/main/res/menu/opt_reader_bottom.xml | 16 +++- app/src/main/res/values/strings.xml | 1 + 35 files changed, 359 insertions(+), 137 deletions(-) create mode 100644 app/src/main/java/org/koitharu/kotatsu/core/db/MangaDao.kt delete mode 100644 app/src/main/java/org/koitharu/kotatsu/domain/HistoryRepository.kt rename app/src/main/java/org/koitharu/kotatsu/domain/{ => history}/ChapterExtra.kt (55%) create mode 100644 app/src/main/java/org/koitharu/kotatsu/domain/history/HistoryRepository.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/domain/history/OnHistoryChangeListener.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/ui/common/BaseFullscreenActivity.kt create mode 100644 app/src/main/res/drawable/ic_bookmark_add.xml create mode 100644 app/src/main/res/drawable/ic_tune.xml diff --git a/app/.gitignore b/app/.gitignore index 42afabfd2..98f612bc2 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -1 +1,2 @@ -/build \ No newline at end of file +/build +/schemas/ diff --git a/app/build.gradle b/app/build.gradle index c9344047b..faf4830bc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,6 +17,12 @@ android { versionName "0.1" buildConfigField 'String', 'GIT_BRANCH', "\"${gitBranch}\"" + + kapt { + arguments { + arg("room.schemaLocation", "$projectDir/schemas".toString()) + } + } } archivesBaseName = "kotatsu_${gitCommits}" compileOptions { diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/HistoryDao.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/HistoryDao.kt index 611ac3d9e..83c3e2b78 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/db/HistoryDao.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/db/HistoryDao.kt @@ -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) } } diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/MangaDao.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/MangaDao.kt new file mode 100644 index 000000000..9a320b86d --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/core/db/MangaDao.kt @@ -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 + + @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? = null) { + if (update(manga) <= 0) { + insert(manga) + if (tags != null) { + clearTagRelation(manga.id) + tags.map { + MangaTagsEntity(manga.id, it.id) + }.forEach { + insertTagRelation(it) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/MangaDatabase.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/MangaDatabase.kt index 29cc9cfef..59852d620 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/db/MangaDatabase.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/db/MangaDatabase.kt @@ -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 } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/TagsDao.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/TagsDao.kt index 0cb75f74e..7e36d702d 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/db/TagsDao.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/db/TagsDao.kt @@ -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 + suspend fun getAllTags(): List + + @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) { + tags.forEach { tag -> + if (update(tag) <= 0) { + insert(tag) + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/entity/HistoryWithManga.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/entity/HistoryWithManga.kt index 3b6e4d34b..76d1edb6a 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/db/entity/HistoryWithManga.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/db/entity/HistoryWithManga.kt @@ -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 ) \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/core/db/entity/MangaEntity.kt b/app/src/main/java/org/koitharu/kotatsu/core/db/entity/MangaEntity.kt index b25baf73d..3820270bd 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/db/entity/MangaEntity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/db/entity/MangaEntity.kt @@ -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 = 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 { diff --git a/app/src/main/java/org/koitharu/kotatsu/core/model/MangaSource.kt b/app/src/main/java/org/koitharu/kotatsu/core/model/MangaSource.kt index d61423e4a..feb6b0b16 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/model/MangaSource.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/model/MangaSource.kt @@ -9,8 +9,8 @@ import org.koitharu.kotatsu.core.parser.site.SelfMangaRepository @Suppress("SpellCheckingInspection") @Parcelize -enum class MangaSource(val title: String, val cls: Class): 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): Parcelable { + READMANGA_RU("ReadManga", "ru", ReadmangaRepository::class.java), + MINTMANGA("MintManga", "ru", MintMangaRepository::class.java), + SELFMANGA("SelfManga", "ru", SelfMangaRepository::class.java) } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/domain/HistoryRepository.kt b/app/src/main/java/org/koitharu/kotatsu/domain/HistoryRepository.kt deleted file mode 100644 index f6f8e8ac0..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/domain/HistoryRepository.kt +++ /dev/null @@ -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 { - 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() - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/domain/ChapterExtra.kt b/app/src/main/java/org/koitharu/kotatsu/domain/history/ChapterExtra.kt similarity index 55% rename from app/src/main/java/org/koitharu/kotatsu/domain/ChapterExtra.kt rename to app/src/main/java/org/koitharu/kotatsu/domain/history/ChapterExtra.kt index bd0d15d15..a9f2d4341 100644 --- a/app/src/main/java/org/koitharu/kotatsu/domain/ChapterExtra.kt +++ b/app/src/main/java/org/koitharu/kotatsu/domain/history/ChapterExtra.kt @@ -1,4 +1,4 @@ -package org.koitharu.kotatsu.domain +package org.koitharu.kotatsu.domain.history enum class ChapterExtra { diff --git a/app/src/main/java/org/koitharu/kotatsu/domain/history/HistoryRepository.kt b/app/src/main/java/org/koitharu/kotatsu/domain/history/HistoryRepository.kt new file mode 100644 index 000000000..290bb1c3b --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/domain/history/HistoryRepository.kt @@ -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 { + 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() + + fun subscribe(listener: OnHistoryChangeListener) { + listeners += listener + } + + fun unsubscribe(listener: OnHistoryChangeListener) { + listeners += listener + } + + private suspend fun notifyHistoryChanged() { + withContext(Dispatchers.Main) { + listeners.forEach { x -> x.onHistoryChanged() } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/domain/history/OnHistoryChangeListener.kt b/app/src/main/java/org/koitharu/kotatsu/domain/history/OnHistoryChangeListener.kt new file mode 100644 index 000000000..8058cd8ac --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/domain/history/OnHistoryChangeListener.kt @@ -0,0 +1,6 @@ +package org.koitharu.kotatsu.domain.history + +interface OnHistoryChangeListener { + + fun onHistoryChanged() +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/common/BaseFullscreenActivity.kt b/app/src/main/java/org/koitharu/kotatsu/ui/common/BaseFullscreenActivity.kt new file mode 100644 index 000000000..b98f2782a --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/common/BaseFullscreenActivity.kt @@ -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) +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/common/list/BaseRecyclerAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/common/list/BaseRecyclerAdapter.kt index 7f1aebd18..ccb62092c 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/common/list/BaseRecyclerAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/common/list/BaseRecyclerAdapter.kt @@ -9,7 +9,7 @@ abstract class BaseRecyclerAdapter(private val onItemClickListener: OnRecy RecyclerView.Adapter>(), KoinComponent { - private val dataSet = ArrayList() + protected val dataSet = ArrayList() init { @Suppress("LeakingThis") @@ -34,21 +34,25 @@ abstract class BaseRecyclerAdapter(private val onItemClickListener: OnRecy val updater = AdapterUpdater(dataSet, newData, this::onGetItemId) dataSet.replaceWith(newData) updater(this) + onDataSetChanged() } fun appendData(newData: List) { 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(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(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) = Unit diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/details/ChapterHolder.kt b/app/src/main/java/org/koitharu/kotatsu/ui/details/ChapterHolder.kt index 7d766c8cd..7e91ff0e4 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/details/ChapterHolder.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/details/ChapterHolder.kt @@ -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 diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/details/ChaptersAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/details/ChaptersAdapter.kt index 35a29a1ac..513501f1e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/details/ChaptersAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/details/ChaptersAdapter.kt @@ -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) : BaseRecyclerAdapter(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 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() + } + } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/details/ChaptersFragment.kt b/app/src/main/java/org/koitharu/kotatsu/ui/details/ChaptersFragment.kt index 7adc3a0bb..bce5f29b0 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/details/ChaptersFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/details/ChaptersFragment.kt @@ -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) { diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/details/MangaDetailsActivity.kt b/app/src/main/java/org/koitharu/kotatsu/ui/details/MangaDetailsActivity.kt index ca5a56a05..2ab2db4f6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/details/MangaDetailsActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/details/MangaDetailsActivity.kt @@ -24,17 +24,9 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView { tabs.setupWithViewPager(pager) intent?.getParcelableExtra(EXTRA_MANGA)?.let { presenter.loadDetails(it) - presenter.loadHistory(it) } ?: finish() } - override fun onResume() { - super.onResume() - intent?.getParcelableExtra(EXTRA_MANGA)?.let { - presenter.loadHistory(it) - } - } - override fun onMangaUpdated(manga: Manga) { title = manga.title } diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/details/MangaDetailsPresenter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/details/MangaDetailsPresenter.kt index 7c043f519..cbcbe9388 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/details/MangaDetailsPresenter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/details/MangaDetailsPresenter.kt @@ -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() { +class MangaDetailsPresenter : BasePresenter(), 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() { 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() { } } - fun loadHistory(manga: Manga) { + private fun loadHistory(manga: Manga) { launch { try { val history = withContext(Dispatchers.IO) { @@ -60,4 +63,13 @@ class MangaDetailsPresenter : BasePresenter() { } } } + + override fun onHistoryChanged() { + loadHistory(manga ?: return) + } + + override fun onDestroy() { + HistoryRepository.unsubscribe(this) + super.onDestroy() + } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/MainActivity.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/MainActivity.kt index da07b373e..0934d480b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/main/MainActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/MainActivity.kt @@ -31,6 +31,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList if (!supportFragmentManager.isStateSaved) { navigationView.setCheckedItem(R.id.nav_history) + setPrimaryFragment(HistoryListFragment.newInstance()) } } diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt index a6e7c4c37..eb8a7d1c6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt @@ -79,7 +79,12 @@ abstract class MangaListFragment : BaseFragment(R.layout.fragment_list), Man override fun onListChanged(list: List) { 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) { @@ -89,6 +94,10 @@ abstract class MangaListFragment : 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 : 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 diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/history/HistoryListFragment.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/history/HistoryListFragment.kt index 138886624..6b1b03b97 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/history/HistoryListFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/history/HistoryListFragment.kt @@ -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(), MangaListView(), MangaListView() { private val source by arg(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) } diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderActivity.kt b/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderActivity.kt index 5c5d98932..c95046071 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderActivity.kt @@ -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(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" diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderPresenter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderPresenter.kt index 81cf6aef5..ff2d08785 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderPresenter.kt @@ -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 diff --git a/app/src/main/res/drawable/ic_bookmark_add.xml b/app/src/main/res/drawable/ic_bookmark_add.xml new file mode 100644 index 000000000..81ac20eb6 --- /dev/null +++ b/app/src/main/res/drawable/ic_bookmark_add.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_tune.xml b/app/src/main/res/drawable/ic_tune.xml new file mode 100644 index 000000000..810bd9420 --- /dev/null +++ b/app/src/main/res/drawable/ic_tune.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/layout/activity_reader.xml b/app/src/main/res/layout/activity_reader.xml index 7246537dd..5ca58e527 100644 --- a/app/src/main/res/layout/activity_reader.xml +++ b/app/src/main/res/layout/activity_reader.xml @@ -1,5 +1,6 @@ - @@ -9,23 +10,43 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - + app:elevation="0dp"> - + + + + + app:elevation="0dp"> + + + + + app:layout_constraintTop_toBottomOf="@id/barrier_title" /> diff --git a/app/src/main/res/layout/item_manga_list_details.xml b/app/src/main/res/layout/item_manga_list_details.xml index 8f8deb4f8..fff8f5da2 100644 --- a/app/src/main/res/layout/item_manga_list_details.xml +++ b/app/src/main/res/layout/item_manga_list_details.xml @@ -27,7 +27,7 @@ android:layout_marginEnd="6dp" android:layout_toEndOf="@id/imageView_cover" android:ellipsize="end" - android:lines="2" + android:maxLines="2" android:textAppearance="@style/TextAppearance.MaterialComponents.Body1" tools:text="@tools:sample/lorem[6]" /> @@ -43,7 +43,7 @@ android:layout_marginBottom="6dp" android:layout_toEndOf="@id/imageView_cover" android:ellipsize="end" - android:lines="1" + android:maxLines="1" android:textAppearance="@style/TextAppearance.MaterialComponents.Body2" android:textColor="?android:textColorSecondary" tools:text="@tools:sample/lorem[6]" /> diff --git a/app/src/main/res/menu/opt_reader_bottom.xml b/app/src/main/res/menu/opt_reader_bottom.xml index 7e83279b3..ed8abf64a 100644 --- a/app/src/main/res/menu/opt_reader_bottom.xml +++ b/app/src/main/res/menu/opt_reader_bottom.xml @@ -1,8 +1,18 @@ - + - + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3a900ba96..3d065462a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -24,4 +24,5 @@ History is empty Read Continue + Add bookmark \ No newline at end of file