Improve reader
This commit is contained in:
@@ -8,11 +8,11 @@ import org.koitharu.kotatsu.core.db.entity.FavouriteManga
|
||||
abstract class FavouritesDao {
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM favourites ORDER BY :orderBy LIMIT :limit OFFSET :offset")
|
||||
@Query("SELECT * FROM favourites GROUP BY manga_id ORDER BY :orderBy LIMIT :limit OFFSET :offset")
|
||||
abstract suspend fun findAll(offset: Int, limit: Int, orderBy: String): List<FavouriteManga>
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM favourites WHERE manga_id = :id")
|
||||
@Query("SELECT * FROM favourites WHERE manga_id = :id GROUP BY manga_id")
|
||||
abstract suspend fun find(id: Long): FavouriteManga?
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
|
||||
@@ -13,10 +13,10 @@ abstract class HistoryDao {
|
||||
*/
|
||||
@Transaction
|
||||
@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 findAll(offset: Int, limit: Int, orderBy: String): List<HistoryWithManga>
|
||||
|
||||
@Query("SELECT * FROM history WHERE manga_id = :id")
|
||||
abstract suspend fun getOneOrNull(id: Long): HistoryEntity?
|
||||
abstract suspend fun find(id: Long): HistoryEntity?
|
||||
|
||||
@Query("DELETE FROM history")
|
||||
abstract suspend fun clear()
|
||||
|
||||
@@ -17,7 +17,7 @@ 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")
|
||||
val entities = db.historyDao().findAll(offset, 20, "updated_at")
|
||||
return entities.map { it.manga.toManga(it.tags.map(TagEntity::toMangaTag).toSet()) }
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class HistoryRepository : KoinComponent {
|
||||
}
|
||||
|
||||
suspend fun getOne(manga: Manga): MangaHistory? {
|
||||
return db.historyDao().getOneOrNull(manga.id)?.let {
|
||||
return db.historyDao().find(manga.id)?.let {
|
||||
MangaHistory(
|
||||
createdAt = Date(it.createdAt),
|
||||
updatedAt = Date(it.updatedAt),
|
||||
|
||||
@@ -1,15 +1,27 @@
|
||||
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)
|
||||
window.decorView.setOnSystemUiVisibilityChangeListener { visibility ->
|
||||
if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
|
||||
onSystemUiShown()
|
||||
} else {
|
||||
onSystemUiHidden()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
if (hasFocus) hideSystemUI()
|
||||
}
|
||||
|
||||
private fun hideSystemUI() {
|
||||
protected 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
|
||||
@@ -23,4 +35,8 @@ abstract class BaseFullscreenActivity : BaseActivity() {
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
|
||||
}
|
||||
|
||||
protected open fun onSystemUiShown() = Unit
|
||||
|
||||
protected open fun onSystemUiHidden() = Unit
|
||||
}
|
||||
@@ -12,12 +12,15 @@ import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import org.koitharu.kotatsu.ui.common.BaseActivity
|
||||
import org.koitharu.kotatsu.utils.ShareHelper
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
|
||||
class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
|
||||
|
||||
val presenter by moxyPresenter(factory = ::MangaDetailsPresenter)
|
||||
|
||||
private var manga: Manga? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_details)
|
||||
@@ -30,6 +33,7 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
|
||||
}
|
||||
|
||||
override fun onMangaUpdated(manga: Manga) {
|
||||
this.manga = manga
|
||||
title = manga.title
|
||||
}
|
||||
|
||||
@@ -47,7 +51,10 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
|
||||
R.id.action_favourite -> {
|
||||
R.id.action_share -> {
|
||||
manga?.let {
|
||||
ShareHelper.shareMangaLink(this, it)
|
||||
}
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.MotionEvent
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
@@ -16,9 +17,10 @@ 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.BaseFullscreenActivity
|
||||
import org.koitharu.kotatsu.utils.GridTouchHelper
|
||||
import org.koitharu.kotatsu.utils.ext.showDialog
|
||||
|
||||
class ReaderActivity : BaseFullscreenActivity(), ReaderView {
|
||||
class ReaderActivity : BaseFullscreenActivity(), ReaderView, GridTouchHelper.OnGridTouchListener {
|
||||
|
||||
private val presenter by moxyPresenter { ReaderPresenter() }
|
||||
|
||||
@@ -26,11 +28,13 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView {
|
||||
|
||||
private lateinit var loader: PageLoader
|
||||
private lateinit var adapter: PagesAdapter
|
||||
private lateinit var touchHelper: GridTouchHelper
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_reader)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
touchHelper = GridTouchHelper(this, this)
|
||||
toolbar_bottom.inflateMenu(R.menu.opt_reader_bottom)
|
||||
|
||||
state = savedInstanceState?.getParcelable(EXTRA_STATE)
|
||||
@@ -76,7 +80,11 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView {
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
|
||||
R.id.action_chapters -> {
|
||||
ChaptersDialog.show(supportFragmentManager, state.manga.chapters.orEmpty(), state.chapterId)
|
||||
ChaptersDialog.show(
|
||||
supportFragmentManager,
|
||||
state.manga.chapters.orEmpty(),
|
||||
state.chapterId
|
||||
)
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
@@ -99,17 +107,43 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView {
|
||||
}
|
||||
}
|
||||
|
||||
private fun onTapCenter() {
|
||||
if (appbar_top.isVisible) {
|
||||
appbar_top.isGone = false
|
||||
appbar_bottom.isGone = false
|
||||
} else {
|
||||
appbar_top.isGone = true
|
||||
appbar_bottom.isGone = true
|
||||
showSystemUI()
|
||||
override fun onSystemUiShown() {
|
||||
appbar_top.isGone = true
|
||||
appbar_bottom.isGone = true
|
||||
}
|
||||
|
||||
override fun onSystemUiHidden() {
|
||||
appbar_top.isGone = false
|
||||
appbar_bottom.isGone = false
|
||||
}
|
||||
|
||||
override fun onGridTouch(area: Int) {
|
||||
when (area) {
|
||||
GridTouchHelper.AREA_CENTER -> {
|
||||
if (appbar_top.isVisible) {
|
||||
appbar_top.isVisible = false
|
||||
appbar_bottom.isVisible = false
|
||||
} else {
|
||||
appbar_top.isVisible = true
|
||||
appbar_bottom.isVisible = true
|
||||
}
|
||||
}
|
||||
GridTouchHelper.AREA_TOP,
|
||||
GridTouchHelper.AREA_LEFT -> {
|
||||
pager.setCurrentItem(pager.currentItem - 1, true)
|
||||
}
|
||||
GridTouchHelper.AREA_BOTTOM,
|
||||
GridTouchHelper.AREA_RIGHT -> {
|
||||
pager.setCurrentItem(pager.currentItem + 1, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
|
||||
touchHelper.dispatchTouchEvent(ev)
|
||||
return super.dispatchTouchEvent(ev)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val EXTRA_STATE = "state"
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.koitharu.kotatsu.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.view.GestureDetector
|
||||
import android.view.MotionEvent
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class GridTouchHelper(context: Context, private val listener: OnGridTouchListener) :
|
||||
GestureDetector.SimpleOnGestureListener() {
|
||||
|
||||
private val detector = GestureDetector(context, this)
|
||||
private val width = context.resources.displayMetrics.widthPixels
|
||||
private val height = context.resources.displayMetrics.heightPixels
|
||||
|
||||
init {
|
||||
detector.setIsLongpressEnabled(false)
|
||||
detector.setOnDoubleTapListener(this)
|
||||
}
|
||||
|
||||
fun dispatchTouchEvent(event: MotionEvent) {
|
||||
detector.onTouchEvent(event)
|
||||
}
|
||||
|
||||
override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
|
||||
val xIndex = (event.rawX * 2f / width).roundToInt()
|
||||
val yIndex = (event.rawY * 2f / height).roundToInt()
|
||||
listener.onGridTouch(
|
||||
when (xIndex) {
|
||||
0 -> AREA_LEFT
|
||||
1 -> {
|
||||
when (yIndex) {
|
||||
0 -> AREA_TOP
|
||||
1 -> AREA_CENTER
|
||||
2 -> AREA_BOTTOM
|
||||
else -> return false
|
||||
}
|
||||
}
|
||||
2 -> AREA_RIGHT
|
||||
else -> return false
|
||||
}
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val AREA_CENTER = 1
|
||||
const val AREA_LEFT = 2
|
||||
const val AREA_RIGHT = 3
|
||||
const val AREA_TOP = 4
|
||||
const val AREA_BOTTOM = 5
|
||||
}
|
||||
|
||||
interface OnGridTouchListener {
|
||||
|
||||
fun onGridTouch(area: Int)
|
||||
}
|
||||
}
|
||||
22
app/src/main/java/org/koitharu/kotatsu/utils/ShareHelper.kt
Normal file
22
app/src/main/java/org/koitharu/kotatsu/utils/ShareHelper.kt
Normal file
@@ -0,0 +1,22 @@
|
||||
package org.koitharu.kotatsu.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
|
||||
object ShareHelper {
|
||||
|
||||
@JvmStatic
|
||||
fun shareMangaLink(context: Context, manga: Manga) {
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.type = "text/plain"
|
||||
intent.putExtra(Intent.EXTRA_TEXT, buildString {
|
||||
append(manga.title)
|
||||
append("\n \n")
|
||||
append(manga.url)
|
||||
})
|
||||
val shareIntent = Intent.createChooser(intent, context.getString(R.string.share_s, manga.title))
|
||||
context.startActivity(shareIntent)
|
||||
}
|
||||
}
|
||||
5
app/src/main/res/drawable/ic_share.xml
Normal file
5
app/src/main/res/drawable/ic_share.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
|
||||
</vector>
|
||||
@@ -2,6 +2,7 @@
|
||||
<com.google.android.material.circularreveal.CircularRevealFrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/rootLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_favourite"
|
||||
android:icon="@drawable/ic_favourites"
|
||||
android:title="@string/favourites"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/action_share"
|
||||
android:icon="@drawable/ic_share"
|
||||
android:title="@string/share"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_save"
|
||||
android:title="@string/save"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_shortcut"
|
||||
android:title="@string/create_shortcut"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
||||
@@ -30,4 +30,8 @@
|
||||
<string name="add_new_category">Add new category</string>
|
||||
<string name="add">Add</string>
|
||||
<string name="enter_category_name">Enter category name</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="share">Share</string>
|
||||
<string name="create_shortcut">Create shortcut…</string>
|
||||
<string name="share_s">Share %s</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user