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")
|
@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>
|
||||||
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: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>
|
||||||
Reference in New Issue
Block a user