Update details activity

pull/1/head
Admin 6 years ago
parent 6eea278b4d
commit ef32c49310

@ -16,6 +16,9 @@ abstract class HistoryDao {
@Query("SELECT * FROM history ORDER BY :orderBy LIMIT :limit OFFSET :offset") @Query("SELECT * FROM history ORDER BY :orderBy LIMIT :limit OFFSET :offset")
abstract suspend fun getAll(offset: Int, limit: Int, orderBy: String): List<HistoryWithManga> 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") @Query("DELETE FROM history")
abstract suspend fun clear() 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.db.entity.MangaEntity
import org.koitharu.kotatsu.core.model.* import org.koitharu.kotatsu.core.model.*
import java.io.Closeable import java.io.Closeable
import java.util.*
class HistoryRepository() : KoinComponent, MangaRepository, Closeable { 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() { suspend fun clear() {
db.historyDao().clear() db.historyDao().clear()
} }

@ -8,8 +8,9 @@ import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.fragment_chapters.* import kotlinx.android.synthetic.main.fragment_chapters.*
import moxy.ktx.moxyPresenter import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.R 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.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.BaseFragment
import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener import org.koitharu.kotatsu.ui.common.list.OnRecyclerItemClickListener
import org.koitharu.kotatsu.ui.reader.ReaderActivity import org.koitharu.kotatsu.ui.reader.ReaderActivity
@ -20,20 +21,25 @@ class ChaptersFragment : BaseFragment(R.layout.fragment_chapters), MangaDetailsV
@Suppress("unused") @Suppress("unused")
private val presenter by moxyPresenter { (activity as MangaDetailsActivity).presenter } 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 private lateinit var adapter: ChaptersAdapter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
adapter = ChaptersAdapter(this) adapter = ChaptersAdapter(this)
recyclerView_chapters.addItemDecoration(DividerItemDecoration(view.context, RecyclerView.VERTICAL)) recyclerView_chapters.addItemDecoration(
DividerItemDecoration(
view.context,
RecyclerView.VERTICAL
)
)
recyclerView_chapters.adapter = adapter recyclerView_chapters.adapter = adapter
} }
override fun onMangaUpdated(manga: Manga) { override fun onMangaUpdated(data: MangaInfo<MangaHistory?>) {
this.manga = manga this.data = data
adapter.replaceData(manga.chapters.orEmpty()) adapter.replaceData(data.manga.chapters.orEmpty())
} }
override fun onLoadingStateChanged(isLoading: Boolean) { 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) { override fun onItemClick(item: MangaChapter, position: Int, view: View) {
startActivity(ReaderActivity.newIntent( startActivity(
context ?: return, ReaderActivity.newIntent(
manga ?: return, context ?: return,
item.id data?.manga ?: return,
)) item.id
)
)
} }
} }

@ -8,6 +8,8 @@ import kotlinx.android.synthetic.main.activity_details.*
import moxy.ktx.moxyPresenter import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga 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.ui.common.BaseActivity
import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.getDisplayMessage
@ -26,8 +28,8 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
} ?: finish() } ?: finish()
} }
override fun onMangaUpdated(manga: Manga) { override fun onMangaUpdated(data: MangaInfo<MangaHistory?>) {
title = manga.title title = data.manga.title
} }
override fun onLoadingStateChanged(isLoading: Boolean) = Unit override fun onLoadingStateChanged(isLoading: Boolean) = Unit

@ -6,7 +6,10 @@ import kotlinx.android.synthetic.main.fragment_details.*
import moxy.ktx.moxyPresenter import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga 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.common.BaseFragment
import org.koitharu.kotatsu.ui.reader.ReaderActivity
import org.koitharu.kotatsu.utils.ext.setChips import org.koitharu.kotatsu.utils.ext.setChips
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -15,24 +18,46 @@ class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetai
@Suppress("unused") @Suppress("unused")
private val presenter by moxyPresenter { (activity as MangaDetailsActivity).presenter } private val presenter by moxyPresenter { (activity as MangaDetailsActivity).presenter }
override fun onMangaUpdated(manga: Manga) { override fun onMangaUpdated(data: MangaInfo<MangaHistory?>) {
imageView_cover.load(manga.largeCoverUrl ?: manga.coverUrl) imageView_cover.load(data.manga.largeCoverUrl ?: data.manga.coverUrl)
textView_title.text = manga.title textView_title.text = data.manga.title
textView_subtitle.text = manga.localizedTitle textView_subtitle.text = data.manga.localizedTitle
textView_description.text = manga.description textView_description.text = data.manga.description
if (manga.rating == Manga.NO_RATING) { if (data.manga.rating == Manga.NO_RATING) {
ratingBar.isVisible = false ratingBar.isVisible = false
} else { } else {
ratingBar.progress = (ratingBar.max * manga.rating).roundToInt() ratingBar.progress = (ratingBar.max * data.manga.rating).roundToInt()
ratingBar.isVisible = true ratingBar.isVisible = true
} }
chips_tags.setChips(manga.tags) { chips_tags.setChips(data.manga.tags) {
create( create(
text = it.title, text = it.title,
iconRes = R.drawable.ic_chip_tag, iconRes = R.drawable.ic_chip_tag,
tag = it 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) { override fun onLoadingStateChanged(isLoading: Boolean) {

@ -1,11 +1,14 @@
package org.koitharu.kotatsu.ui.details package org.koitharu.kotatsu.ui.details
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import moxy.InjectViewState import moxy.InjectViewState
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.model.Manga 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.domain.MangaProviderFactory
import org.koitharu.kotatsu.ui.common.BasePresenter import org.koitharu.kotatsu.ui.common.BasePresenter
@ -18,14 +21,20 @@ class MangaDetailsPresenter : BasePresenter<MangaDetailsView>() {
if (isLoaded) { if (isLoaded) {
return return
} }
viewState.onMangaUpdated(manga) viewState.onMangaUpdated(MangaInfo(manga, null))
launch { launch {
try { try {
viewState.onLoadingStateChanged(true) viewState.onLoadingStateChanged(true)
val details = withContext(Dispatchers.IO) { val data = withContext(Dispatchers.IO) {
MangaProviderFactory.create(manga.source).getDetails(manga) 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 isLoaded = true
} catch (e: Exception) { } catch (e: Exception) {
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {

@ -4,12 +4,13 @@ import moxy.MvpView
import moxy.viewstate.strategy.AddToEndSingleStrategy import moxy.viewstate.strategy.AddToEndSingleStrategy
import moxy.viewstate.strategy.OneExecutionStateStrategy import moxy.viewstate.strategy.OneExecutionStateStrategy
import moxy.viewstate.strategy.StateStrategyType 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 { interface MangaDetailsView : MvpView {
@StateStrategyType(AddToEndSingleStrategy::class) @StateStrategyType(AddToEndSingleStrategy::class)
fun onMangaUpdated(manga: Manga) fun onMangaUpdated(data: MangaInfo<MangaHistory?>)
@StateStrategyType(AddToEndSingleStrategy::class) @StateStrategyType(AddToEndSingleStrategy::class)
fun onLoadingStateChanged(isLoading: Boolean) fun onLoadingStateChanged(isLoading: Boolean)

@ -1,17 +1,20 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector
android:width="108dp" xmlns:android="http://schemas.android.com/apk/res/android"
android:height="108dp" android:width="108dp"
android:viewportWidth="108" android:height="108dp"
android:viewportHeight="108" android:tint="#0D47A1"
android:tint="#0D47A1"> android:viewportWidth="108"
<group android:scaleX="0.40188664" android:viewportHeight="108">
android:scaleY="0.40188664" <group
android:translateX="32.90095" android:scaleX="0.40188664"
android:translateY="18.7272"> android:scaleY="0.40188664"
<group android:translateY="139.39206"> android:translateX="32.90095"
<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:translateY="18.7272">
android:fillColor="#0D47A1"/> <group android:translateY="139.39206">
</group> <path
</group> 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> </vector>

@ -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>

@ -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:layout_marginTop="10dp"
android:isIndicator="true" android:isIndicator="true"
android:max="100" android:max="100"
tools:progress="70"
app:layout_constraintStart_toStartOf="@id/textView_title" 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 <androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_title" android:id="@+id/barrier_title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:barrierDirection="bottom" 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 <com.google.android.material.chip.ChipGroup
android:id="@+id/chips_tags" android:id="@+id/chips_tags"

@ -4,6 +4,13 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="92dp"> 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 <View
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="1dp" android:layout_height="1dp"

@ -22,4 +22,6 @@
<string name="clear_history">Clear history</string> <string name="clear_history">Clear history</string>
<string name="nothing_found">Nothing found</string> <string name="nothing_found">Nothing found</string>
<string name="history_is_empty">History is empty</string> <string name="history_is_empty">History is empty</string>
<string name="read">Read</string>
<string name="continue_">Continue</string>
</resources> </resources>
Loading…
Cancel
Save