Desktop shortcuts

pull/1/head
Koitharu 6 years ago
parent e528cc38ae
commit c60683eb42

@ -3,13 +3,15 @@ package org.koitharu.kotatsu.core.db
import androidx.room.* import androidx.room.*
import org.koitharu.kotatsu.core.db.entity.MangaEntity import org.koitharu.kotatsu.core.db.entity.MangaEntity
import org.koitharu.kotatsu.core.db.entity.MangaTagsEntity import org.koitharu.kotatsu.core.db.entity.MangaTagsEntity
import org.koitharu.kotatsu.core.db.entity.MangaWithTags
import org.koitharu.kotatsu.core.db.entity.TagEntity import org.koitharu.kotatsu.core.db.entity.TagEntity
@Dao @Dao
abstract class MangaDao { abstract class MangaDao {
@Query("SELECT * FROM manga") @Transaction
abstract suspend fun getAllManga(): List<MangaEntity> @Query("SELECT * FROM manga WHERE manga_id = :id")
abstract suspend fun find(id: Long): MangaWithTags?
@Insert(onConflict = OnConflictStrategy.IGNORE) @Insert(onConflict = OnConflictStrategy.IGNORE)
abstract suspend fun insert(manga: MangaEntity): Long abstract suspend fun insert(manga: MangaEntity): Long

@ -0,0 +1,20 @@
package org.koitharu.kotatsu.core.db.entity
import androidx.room.Embedded
import androidx.room.Junction
import androidx.room.Relation
data class MangaWithTags(
@Embedded val manga: MangaEntity,
@Relation(
parentColumn = "manga_id",
entityColumn = "tag_id",
associateBy = Junction(MangaTagsEntity::class)
)
val tags: List<TagEntity>
) {
fun toManga() = manga.toManga(tags.map {
it.toMangaTag()
}.toSet())
}

@ -0,0 +1,5 @@
package org.koitharu.kotatsu.core.exceptions
import java.lang.NullPointerException
class MangaNotFoundException(s: String? = null) : RuntimeException(s)

@ -3,14 +3,17 @@ package org.koitharu.kotatsu.domain
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
import org.koin.core.inject import org.koin.core.inject
import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.db.entity.MangaEntity
import org.koitharu.kotatsu.core.db.entity.MangaPrefsEntity import org.koitharu.kotatsu.core.db.entity.MangaPrefsEntity
import org.koitharu.kotatsu.core.db.entity.TagEntity
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.prefs.ReaderMode import org.koitharu.kotatsu.core.prefs.ReaderMode
class MangaPreferencesRepository : KoinComponent { class MangaDataRepository : KoinComponent {
private val db: MangaDatabase by inject() private val db: MangaDatabase by inject()
suspend fun saveData(mangaId: Long, mode: ReaderMode) { suspend fun savePreferences(mangaId: Long, mode: ReaderMode) {
db.preferencesDao().upsert( db.preferencesDao().upsert(
MangaPrefsEntity( MangaPrefsEntity(
mangaId = mangaId, mangaId = mangaId,
@ -22,4 +25,12 @@ class MangaPreferencesRepository : KoinComponent {
suspend fun getReaderMode(mangaId: Long): ReaderMode? { suspend fun getReaderMode(mangaId: Long): ReaderMode? {
return db.preferencesDao().find(mangaId)?.let { ReaderMode.valueOf(it.mode) } return db.preferencesDao().find(mangaId)?.let { ReaderMode.valueOf(it.mode) }
} }
suspend fun findMangaById(mangaId: Long): Manga? {
return db.mangaDao().find(mangaId)?.toManga()
}
suspend fun storeManga(manga: Manga) {
db.mangaDao().upsert(MangaEntity.from(manga), manga.tags.map(TagEntity.Companion::fromMangaTag))
}
} }

@ -40,12 +40,13 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
pager.adapter = MangaDetailsAdapter(resources, supportFragmentManager) pager.adapter = MangaDetailsAdapter(resources, supportFragmentManager)
tabs.setupWithViewPager(pager) tabs.setupWithViewPager(pager)
intent?.getParcelableExtra<Manga>(EXTRA_MANGA)?.let { if (savedInstanceState?.containsKey(MvpDelegate.MOXY_DELEGATE_TAGS_KEY) != true) {
presenter.loadDetails( intent?.getParcelableExtra<Manga>(EXTRA_MANGA)?.let {
manga = it, presenter.loadDetails(it, true)
force = savedInstanceState?.containsKey(MvpDelegate.MOXY_DELEGATE_TAGS_KEY) != true } ?: intent?.getLongExtra(EXTRA_MANGA_ID, 0)?.takeUnless { it == 0L }?.let {
) presenter.findMangaById(it)
} ?: finish() } ?: finish()
}
} }
override fun onMangaUpdated(manga: Manga) { override fun onMangaUpdated(manga: Manga) {
@ -69,7 +70,12 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
} }
override fun onError(e: Throwable) { override fun onError(e: Throwable) {
Snackbar.make(pager, e.getDisplayMessage(resources), Snackbar.LENGTH_LONG).show() if (manga == null) {
Toast.makeText(this, e.getDisplayMessage(resources), Toast.LENGTH_LONG).show()
finish()
} else {
Snackbar.make(pager, e.getDisplayMessage(resources), Snackbar.LENGTH_LONG).show()
}
} }
override fun onCreateOptionsMenu(menu: Menu?): Boolean { override fun onCreateOptionsMenu(menu: Menu?): Boolean {
@ -82,8 +88,8 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
manga?.source != null && manga?.source != MangaSource.LOCAL manga?.source != null && manga?.source != MangaSource.LOCAL
menu.findItem(R.id.action_delete).isVisible = menu.findItem(R.id.action_delete).isVisible =
manga?.source == MangaSource.LOCAL manga?.source == MangaSource.LOCAL
menu.findItem(R.id.action_shortcut).isVisible = BuildConfig.DEBUG && menu.findItem(R.id.action_shortcut).isVisible =
ShortcutManagerCompat.isRequestPinShortcutSupported(this) ShortcutManagerCompat.isRequestPinShortcutSupported(this)
return super.onPrepareOptionsMenu(menu) return super.onPrepareOptionsMenu(menu)
} }
@ -142,11 +148,16 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
companion object { companion object {
private const val EXTRA_MANGA = "manga" private const val EXTRA_MANGA = "manga"
private const val EXTRA_MANGA_ID = "manga_id"
const val ACTION_MANGA_VIEW = "${BuildConfig.APPLICATION_ID}.action.VIEW_MANGA" const val ACTION_MANGA_VIEW = "${BuildConfig.APPLICATION_ID}.action.VIEW_MANGA"
fun newIntent(context: Context, manga: Manga) = fun newIntent(context: Context, manga: Manga) =
Intent(context, MangaDetailsActivity::class.java) Intent(context, MangaDetailsActivity::class.java)
.putExtra(EXTRA_MANGA, manga) .putExtra(EXTRA_MANGA, manga)
fun newIntent(context: Context, mangaId: Long) =
Intent(context, MangaDetailsActivity::class.java)
.putExtra(EXTRA_MANGA_ID, mangaId)
} }
} }

@ -7,9 +7,11 @@ import kotlinx.coroutines.withContext
import moxy.InjectViewState import moxy.InjectViewState
import moxy.presenterScope import moxy.presenterScope
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.exceptions.MangaNotFoundException
import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.parser.LocalMangaRepository import org.koitharu.kotatsu.core.parser.LocalMangaRepository
import org.koitharu.kotatsu.domain.MangaDataRepository
import org.koitharu.kotatsu.domain.MangaProviderFactory import org.koitharu.kotatsu.domain.MangaProviderFactory
import org.koitharu.kotatsu.domain.favourites.FavouritesRepository import org.koitharu.kotatsu.domain.favourites.FavouritesRepository
import org.koitharu.kotatsu.domain.favourites.OnFavouritesChangeListener import org.koitharu.kotatsu.domain.favourites.OnFavouritesChangeListener
@ -37,6 +39,27 @@ class MangaDetailsPresenter private constructor() : BasePresenter<MangaDetailsVi
FavouritesRepository.subscribe(this) FavouritesRepository.subscribe(this)
} }
fun findMangaById(id: Long) {
presenterScope.launch {
viewState.onLoadingStateChanged(true)
try {
val manga = withContext(Dispatchers.IO) {
MangaDataRepository().findMangaById(id)
} ?: throw MangaNotFoundException("Cannot find manga by id")
viewState.onMangaUpdated(manga)
loadDetails(manga, true)
} catch (_: CancellationException){
} catch (e: Throwable) {
if (BuildConfig.DEBUG) {
e.printStackTrace()
}
viewState.onError(e)
} finally {
viewState.onLoadingStateChanged(false)
}
}
}
fun loadDetails(manga: Manga, force: Boolean = false) { fun loadDetails(manga: Manga, force: Boolean = false) {
if (!force && this.manga == manga) { if (!force && this.manga == manga) {
return return
@ -52,6 +75,7 @@ class MangaDetailsPresenter private constructor() : BasePresenter<MangaDetailsVi
} }
viewState.onMangaUpdated(data) viewState.onMangaUpdated(data)
this@MangaDetailsPresenter.manga = data this@MangaDetailsPresenter.manga = data
} catch (_: CancellationException){
} catch (e: Throwable) { } catch (e: Throwable) {
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
e.printStackTrace() e.printStackTrace()

@ -12,7 +12,7 @@ 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.MangaPage import org.koitharu.kotatsu.core.model.MangaPage
import org.koitharu.kotatsu.core.prefs.ReaderMode import org.koitharu.kotatsu.core.prefs.ReaderMode
import org.koitharu.kotatsu.domain.MangaPreferencesRepository import org.koitharu.kotatsu.domain.MangaDataRepository
import org.koitharu.kotatsu.domain.MangaProviderFactory import org.koitharu.kotatsu.domain.MangaProviderFactory
import org.koitharu.kotatsu.domain.MangaUtils import org.koitharu.kotatsu.domain.MangaUtils
import org.koitharu.kotatsu.domain.history.HistoryRepository import org.koitharu.kotatsu.domain.history.HistoryRepository
@ -43,12 +43,12 @@ class ReaderPresenter : BasePresenter<ReaderView>() {
?: throw RuntimeException("Chapter ${chapterId} not found") ?: throw RuntimeException("Chapter ${chapterId} not found")
val pages = repo.getPages(chapter) val pages = repo.getPages(chapter)
if (!isInitialized) { if (!isInitialized) {
val prefs = MangaPreferencesRepository() val prefs = MangaDataRepository()
var mode = prefs.getReaderMode(manga.id) var mode = prefs.getReaderMode(manga.id)
if (mode == null) { if (mode == null) {
mode = MangaUtils.determineReaderMode(pages) mode = MangaUtils.determineReaderMode(pages)
if (mode != null) { if (mode != null) {
prefs.saveData( prefs.savePreferences(
mangaId = manga.id, mangaId = manga.id,
mode = mode mode = mode
) )
@ -84,7 +84,7 @@ class ReaderPresenter : BasePresenter<ReaderView>() {
page = state.page page = state.page
) )
if (mode != null) { if (mode != null) {
MangaPreferencesRepository().saveData( MangaDataRepository().savePreferences(
mangaId = state.manga.id, mangaId = state.manga.id,
mode = mode mode = mode
) )

@ -12,6 +12,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
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.domain.MangaDataRepository
import org.koitharu.kotatsu.ui.details.MangaDetailsActivity import org.koitharu.kotatsu.ui.details.MangaDetailsActivity
import org.koitharu.kotatsu.utils.ext.safe import org.koitharu.kotatsu.utils.ext.safe
@ -27,6 +28,7 @@ object ShortcutUtils {
}.toBitmap() }.toBitmap()
} }
} }
MangaDataRepository().storeManga(manga)
return ShortcutInfoCompat.Builder(context, manga.id.toString()) return ShortcutInfoCompat.Builder(context, manga.id.toString())
.setShortLabel(manga.title) .setShortLabel(manga.title)
.setLongLabel(manga.title) .setLongLabel(manga.title)
@ -34,7 +36,7 @@ object ShortcutUtils {
IconCompat.createWithBitmap(it) IconCompat.createWithBitmap(it)
} ?: IconCompat.createWithResource(context, R.drawable.ic_launcher_foreground)) } ?: IconCompat.createWithResource(context, R.drawable.ic_launcher_foreground))
.setIntent( .setIntent(
MangaDetailsActivity.newIntent(context, manga.copy(chapters = null)) MangaDetailsActivity.newIntent(context, manga.id)
.setAction(MangaDetailsActivity.ACTION_MANGA_VIEW) .setAction(MangaDetailsActivity.ACTION_MANGA_VIEW)
) )
.build() .build()

Loading…
Cancel
Save