Update details activity
This commit is contained in:
@@ -16,6 +16,9 @@ abstract class HistoryDao {
|
||||
@Query("SELECT * FROM history ORDER BY :orderBy LIMIT :limit OFFSET :offset")
|
||||
abstract suspend fun getAll(offset: Int, limit: Int, orderBy: String): List<HistoryWithManga>
|
||||
|
||||
@Query("SELECT * FROM history WHERE manga_id = :id")
|
||||
abstract suspend fun getOneOrNull(id: Long): HistoryEntity?
|
||||
|
||||
@Query("DELETE FROM history")
|
||||
abstract suspend fun clear()
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.koitharu.kotatsu.core.db.entity.HistoryWithManga
|
||||
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||
import org.koitharu.kotatsu.core.model.*
|
||||
import java.io.Closeable
|
||||
import java.util.*
|
||||
|
||||
class HistoryRepository() : KoinComponent, MangaRepository, Closeable {
|
||||
|
||||
@@ -61,6 +62,17 @@ class HistoryRepository() : KoinComponent, MangaRepository, Closeable {
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getHistory(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()
|
||||
}
|
||||
|
||||
@@ -8,8 +8,9 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.android.synthetic.main.fragment_chapters.*
|
||||
import moxy.ktx.moxyPresenter
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaChapter
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import org.koitharu.kotatsu.core.model.MangaInfo
|
||||
import org.koitharu.kotatsu.ui.common.BaseFragment
|
||||
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
|
||||
import org.koitharu.kotatsu.ui.reader.ReaderActivity
|
||||
@@ -20,20 +21,25 @@ class ChaptersFragment : BaseFragment(R.layout.fragment_chapters), MangaDetailsV
|
||||
@Suppress("unused")
|
||||
private val presenter by moxyPresenter { (activity as MangaDetailsActivity).presenter }
|
||||
|
||||
private var manga: Manga? = null
|
||||
private var data: MangaInfo<MangaHistory?>? = null
|
||||
|
||||
private lateinit var adapter: ChaptersAdapter
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
adapter = ChaptersAdapter(this)
|
||||
recyclerView_chapters.addItemDecoration(DividerItemDecoration(view.context, RecyclerView.VERTICAL))
|
||||
recyclerView_chapters.addItemDecoration(
|
||||
DividerItemDecoration(
|
||||
view.context,
|
||||
RecyclerView.VERTICAL
|
||||
)
|
||||
)
|
||||
recyclerView_chapters.adapter = adapter
|
||||
}
|
||||
|
||||
override fun onMangaUpdated(manga: Manga) {
|
||||
this.manga = manga
|
||||
adapter.replaceData(manga.chapters.orEmpty())
|
||||
override fun onMangaUpdated(data: MangaInfo<MangaHistory?>) {
|
||||
this.data = data
|
||||
adapter.replaceData(data.manga.chapters.orEmpty())
|
||||
}
|
||||
|
||||
override fun onLoadingStateChanged(isLoading: Boolean) {
|
||||
@@ -45,10 +51,12 @@ class ChaptersFragment : BaseFragment(R.layout.fragment_chapters), MangaDetailsV
|
||||
}
|
||||
|
||||
override fun onItemClick(item: MangaChapter, position: Int, view: View) {
|
||||
startActivity(ReaderActivity.newIntent(
|
||||
context ?: return,
|
||||
manga ?: return,
|
||||
item.id
|
||||
))
|
||||
startActivity(
|
||||
ReaderActivity.newIntent(
|
||||
context ?: return,
|
||||
data?.manga ?: return,
|
||||
item.id
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import kotlinx.android.synthetic.main.activity_details.*
|
||||
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.MangaInfo
|
||||
import org.koitharu.kotatsu.ui.common.BaseActivity
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
|
||||
@@ -26,8 +28,8 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
|
||||
} ?: finish()
|
||||
}
|
||||
|
||||
override fun onMangaUpdated(manga: Manga) {
|
||||
title = manga.title
|
||||
override fun onMangaUpdated(data: MangaInfo<MangaHistory?>) {
|
||||
title = data.manga.title
|
||||
}
|
||||
|
||||
override fun onLoadingStateChanged(isLoading: Boolean) = Unit
|
||||
|
||||
@@ -6,7 +6,10 @@ import kotlinx.android.synthetic.main.fragment_details.*
|
||||
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.MangaInfo
|
||||
import org.koitharu.kotatsu.ui.common.BaseFragment
|
||||
import org.koitharu.kotatsu.ui.reader.ReaderActivity
|
||||
import org.koitharu.kotatsu.utils.ext.setChips
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@@ -15,24 +18,46 @@ class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetai
|
||||
@Suppress("unused")
|
||||
private val presenter by moxyPresenter { (activity as MangaDetailsActivity).presenter }
|
||||
|
||||
override fun onMangaUpdated(manga: Manga) {
|
||||
imageView_cover.load(manga.largeCoverUrl ?: manga.coverUrl)
|
||||
textView_title.text = manga.title
|
||||
textView_subtitle.text = manga.localizedTitle
|
||||
textView_description.text = manga.description
|
||||
if (manga.rating == Manga.NO_RATING) {
|
||||
override fun onMangaUpdated(data: MangaInfo<MangaHistory?>) {
|
||||
imageView_cover.load(data.manga.largeCoverUrl ?: data.manga.coverUrl)
|
||||
textView_title.text = data.manga.title
|
||||
textView_subtitle.text = data.manga.localizedTitle
|
||||
textView_description.text = data.manga.description
|
||||
if (data.manga.rating == Manga.NO_RATING) {
|
||||
ratingBar.isVisible = false
|
||||
} else {
|
||||
ratingBar.progress = (ratingBar.max * manga.rating).roundToInt()
|
||||
ratingBar.progress = (ratingBar.max * data.manga.rating).roundToInt()
|
||||
ratingBar.isVisible = true
|
||||
}
|
||||
chips_tags.setChips(manga.tags) {
|
||||
chips_tags.setChips(data.manga.tags) {
|
||||
create(
|
||||
text = it.title,
|
||||
iconRes = R.drawable.ic_chip_tag,
|
||||
tag = it
|
||||
)
|
||||
}
|
||||
if (data.manga.chapters.isNullOrEmpty()) {
|
||||
button_read.isEnabled = false
|
||||
} else {
|
||||
button_read.isEnabled = true
|
||||
if (data.extra == null) {
|
||||
button_read.setText(R.string.read)
|
||||
button_read.setIconResource(R.drawable.ic_read)
|
||||
} else {
|
||||
button_read.setText(R.string.continue_)
|
||||
button_read.setIconResource(R.drawable.ic_play)
|
||||
}
|
||||
val chapterId = data.extra?.chapterId ?: data.manga.chapters.first().id
|
||||
button_read.setOnClickListener {
|
||||
startActivity(
|
||||
ReaderActivity.newIntent(
|
||||
context ?: return@setOnClickListener,
|
||||
data.manga,
|
||||
chapterId
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLoadingStateChanged(isLoading: Boolean) {
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package org.koitharu.kotatsu.ui.details
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import moxy.InjectViewState
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaInfo
|
||||
import org.koitharu.kotatsu.domain.HistoryRepository
|
||||
import org.koitharu.kotatsu.domain.MangaProviderFactory
|
||||
import org.koitharu.kotatsu.ui.common.BasePresenter
|
||||
|
||||
@@ -18,14 +21,20 @@ class MangaDetailsPresenter : BasePresenter<MangaDetailsView>() {
|
||||
if (isLoaded) {
|
||||
return
|
||||
}
|
||||
viewState.onMangaUpdated(manga)
|
||||
viewState.onMangaUpdated(MangaInfo(manga, null))
|
||||
launch {
|
||||
try {
|
||||
viewState.onLoadingStateChanged(true)
|
||||
val details = withContext(Dispatchers.IO) {
|
||||
MangaProviderFactory.create(manga.source).getDetails(manga)
|
||||
val data = withContext(Dispatchers.IO) {
|
||||
val details = async {
|
||||
MangaProviderFactory.create(manga.source).getDetails(manga)
|
||||
}
|
||||
val history = async {
|
||||
HistoryRepository().use { it.getHistory(manga) }
|
||||
}
|
||||
MangaInfo(details.await(), history.await())
|
||||
}
|
||||
viewState.onMangaUpdated(details)
|
||||
viewState.onMangaUpdated(data)
|
||||
isLoaded = true
|
||||
} catch (e: Exception) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
|
||||
@@ -4,12 +4,13 @@ import moxy.MvpView
|
||||
import moxy.viewstate.strategy.AddToEndSingleStrategy
|
||||
import moxy.viewstate.strategy.OneExecutionStateStrategy
|
||||
import moxy.viewstate.strategy.StateStrategyType
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import org.koitharu.kotatsu.core.model.MangaInfo
|
||||
|
||||
interface MangaDetailsView : MvpView {
|
||||
|
||||
@StateStrategyType(AddToEndSingleStrategy::class)
|
||||
fun onMangaUpdated(manga: Manga)
|
||||
fun onMangaUpdated(data: MangaInfo<MangaHistory?>)
|
||||
|
||||
@StateStrategyType(AddToEndSingleStrategy::class)
|
||||
fun onLoadingStateChanged(isLoading: Boolean)
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108"
|
||||
android:tint="#0D47A1">
|
||||
<group android:scaleX="0.40188664"
|
||||
android:scaleY="0.40188664"
|
||||
android:translateX="32.90095"
|
||||
android:translateY="18.7272">
|
||||
<group android:translateY="139.39206">
|
||||
<path android:pathData="M83.796875,-0L105.6875,-0L60.765625,-55.828125L103.09375,-101L82.078125,-101L32.25,-49.1875L32.25,-101L13.53125,-101L13.53125,-0L32.25,-0L32.25,-25.8125L48.234375,-42.265625L83.796875,-0Z"
|
||||
android:fillColor="#0D47A1"/>
|
||||
</group>
|
||||
</group>
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:tint="#0D47A1"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<group
|
||||
android:scaleX="0.40188664"
|
||||
android:scaleY="0.40188664"
|
||||
android:translateX="32.90095"
|
||||
android:translateY="18.7272">
|
||||
<group android:translateY="139.39206">
|
||||
<path
|
||||
android:fillColor="#0D47A1"
|
||||
android:pathData="M83.796875,-0L105.6875,-0L60.765625,-55.828125L103.09375,-101L82.078125,-101L32.25,-49.1875L32.25,-101L13.53125,-101L13.53125,-0L32.25,-0L32.25,-25.8125L48.234375,-42.265625L83.796875,-0Z" />
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
11
app/src/main/res/drawable/ic_play.xml
Normal file
11
app/src/main/res/drawable/ic_play.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?android:colorControlNormal"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M10,8.64L15.27,12 10,15.36V8.64M8,5v14l11,-7L8,5z" />
|
||||
</vector>
|
||||
11
app/src/main/res/drawable/ic_read.xml
Normal file
11
app/src/main/res/drawable/ic_read.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,9c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,3c1.1,0 2,0.9 2,2s-0.9,2 -2,2 -2,-0.9 -2,-2 0.9,-2 2,-2zM12,11.55C9.64,9.35 6.48,8 3,8v11c3.48,0 6.64,1.35 9,3.55 2.36,-2.19 5.52,-3.55 9,-3.55L21,8c-3.48,0 -6.64,1.35 -9,3.55zM19,17.13c-2.53,0.34 -4.93,1.3 -7,2.82 -2.06,-1.52 -4.47,-2.49 -7,-2.83v-6.95c2.1,0.38 4.05,1.35 5.64,2.83L12,14.28l1.36,-1.27c1.59,-1.48 3.54,-2.45 5.64,-2.83v6.95z" />
|
||||
</vector>
|
||||
@@ -55,16 +55,31 @@
|
||||
android:layout_marginTop="10dp"
|
||||
android:isIndicator="true"
|
||||
android:max="100"
|
||||
tools:progress="70"
|
||||
app:layout_constraintStart_toStartOf="@id/textView_title"
|
||||
app:layout_constraintTop_toBottomOf="@id/textView_subtitle" />
|
||||
app:layout_constraintTop_toBottomOf="@id/textView_subtitle"
|
||||
tools:progress="70" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_read"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/read"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
app:icon="@drawable/ic_read"
|
||||
app:iconPadding="12dp"
|
||||
android:enabled="false"
|
||||
android:layout_marginEnd="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/imageView_cover"
|
||||
app:layout_constraintEnd_toEndOf="@id/textView_title"
|
||||
app:layout_constraintTop_toBottomOf="@id/ratingBar"
|
||||
app:layout_constraintVertical_bias="1" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/barrier_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="imageView_cover, textView_subtitle, ratingBar" />
|
||||
app:constraint_referenced_ids="imageView_cover, button_read" />
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/chips_tags"
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="92dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_launcher_foreground"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
|
||||
@@ -22,4 +22,6 @@
|
||||
<string name="clear_history">Clear history</string>
|
||||
<string name="nothing_found">Nothing found</string>
|
||||
<string name="history_is_empty">History is empty</string>
|
||||
<string name="read">Read</string>
|
||||
<string name="continue_">Continue</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user