Wrap stuff in manga details with an online check to improve user experience (#344)
* wrap details stuff in network checks so app doesn't reach out when it knows it cant * wrap some more clean up a little * remove online check for chapter click/resume in mangadetail * code review fixes
This commit is contained in:
parent
7043687142
commit
149ecaa592
@ -97,6 +97,7 @@ import eu.kanade.tachiyomi.util.system.ThemeUtil
|
|||||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
import eu.kanade.tachiyomi.util.system.isInNightMode
|
import eu.kanade.tachiyomi.util.system.isInNightMode
|
||||||
|
import eu.kanade.tachiyomi.util.system.isOnline
|
||||||
import eu.kanade.tachiyomi.util.system.launchUI
|
import eu.kanade.tachiyomi.util.system.launchUI
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import eu.kanade.tachiyomi.util.view.getText
|
import eu.kanade.tachiyomi.util.view.getText
|
||||||
@ -515,6 +516,14 @@ class MangaDetailsController : BaseController,
|
|||||||
}
|
}
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
fun isNotOnline(showSnackbar: Boolean = true): Boolean {
|
||||||
|
if (activity == null || !activity!!.isOnline()) {
|
||||||
|
if (showSnackbar) view?.snack(R.string.no_network_connection)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
fun showError(message: String) {
|
fun showError(message: String) {
|
||||||
swipe_refresh?.isRefreshing = presenter.isLoading
|
swipe_refresh?.isRefreshing = presenter.isLoading
|
||||||
view?.snack(message)
|
view?.snack(message)
|
||||||
@ -599,7 +608,8 @@ class MangaDetailsController : BaseController,
|
|||||||
fun refreshAdapter() = adapter?.notifyDataSetChanged()
|
fun refreshAdapter() = adapter?.notifyDataSetChanged()
|
||||||
|
|
||||||
override fun onItemClick(view: View?, position: Int): Boolean {
|
override fun onItemClick(view: View?, position: Int): Boolean {
|
||||||
val chapter = (adapter?.getItem(position) as? ChapterItem)?.chapter ?: return false
|
val chapterItem = (adapter?.getItem(position) as? ChapterItem) ?: return false
|
||||||
|
val chapter = chapterItem.chapter
|
||||||
if (actionMode != null) {
|
if (actionMode != null) {
|
||||||
if (startingDLChapterPos == null) {
|
if (startingDLChapterPos == null) {
|
||||||
adapter?.addSelection(position)
|
adapter?.addSelection(position)
|
||||||
@ -629,6 +639,7 @@ class MangaDetailsController : BaseController,
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
openChapter(chapter)
|
openChapter(chapter)
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -828,13 +839,15 @@ class MangaDetailsController : BaseController,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
R.id.action_open_in_web_view -> openInWebView()
|
R.id.action_open_in_web_view -> openInWebView()
|
||||||
R.id.action_refresh_tracking -> presenter.refreshTrackers()
|
R.id.action_refresh_tracking -> presenter.refreshTrackers(true)
|
||||||
R.id.action_migrate ->
|
R.id.action_migrate ->
|
||||||
PreMigrationController.navigateToMigration(
|
if (!isNotOnline()) {
|
||||||
presenter.preferences.skipPreMigration().getOrDefault(),
|
PreMigrationController.navigateToMigration(
|
||||||
router,
|
presenter.preferences.skipPreMigration().getOrDefault(),
|
||||||
listOf(manga!!.id!!)
|
router,
|
||||||
)
|
listOf(manga!!.id!!)
|
||||||
|
)
|
||||||
|
}
|
||||||
R.id.action_mark_all_as_read -> {
|
R.id.action_mark_all_as_read -> {
|
||||||
MaterialDialog(view!!.context).message(R.string.mark_all_chapters_as_read)
|
MaterialDialog(view!!.context).message(R.string.mark_all_chapters_as_read)
|
||||||
.positiveButton(R.string.mark_as_read) {
|
.positiveButton(R.string.mark_as_read) {
|
||||||
@ -892,8 +905,8 @@ class MangaDetailsController : BaseController,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun openInWebView() {
|
override fun openInWebView() {
|
||||||
|
if (isNotOnline()) return
|
||||||
val source = presenter.source as? HttpSource ?: return
|
val source = presenter.source as? HttpSource ?: return
|
||||||
|
|
||||||
val url = try {
|
val url = try {
|
||||||
source.mangaDetailsRequest(presenter.manga).url.toString()
|
source.mangaDetailsRequest(presenter.manga).url.toString()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@ -1053,6 +1066,7 @@ class MangaDetailsController : BaseController,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun globalSearch(text: String) {
|
override fun globalSearch(text: String) {
|
||||||
|
if (isNotOnline()) return
|
||||||
router.pushController(SourceSearchController(text).withFadeTransaction())
|
router.pushController(SourceSearchController(text).withFadeTransaction())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ class MangaDetailsPresenter(
|
|||||||
controller.updateChapters(this.chapters)
|
controller.updateChapters(this.chapters)
|
||||||
}
|
}
|
||||||
fetchTrackings()
|
fetchTrackings()
|
||||||
refreshTrackers()
|
refreshTrackers(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onDestroy() {
|
fun onDestroy() {
|
||||||
@ -372,6 +372,7 @@ class MangaDetailsPresenter(
|
|||||||
|
|
||||||
/** Refresh Manga Info and Chapter List (not tracking) */
|
/** Refresh Manga Info and Chapter List (not tracking) */
|
||||||
fun refreshAll() {
|
fun refreshAll() {
|
||||||
|
if (controller.isNotOnline()) return
|
||||||
scope.launch {
|
scope.launch {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
var mangaError: java.lang.Exception? = null
|
var mangaError: java.lang.Exception? = null
|
||||||
@ -763,36 +764,40 @@ class MangaDetailsPresenter(
|
|||||||
withContext(Dispatchers.Main) { controller.refreshTracking(trackList) }
|
withContext(Dispatchers.Main) { controller.refreshTracking(trackList) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refreshTrackers() {
|
fun refreshTrackers(showOfflineSnack: Boolean = false) {
|
||||||
scope.launch {
|
if (controller.isNotOnline(showOfflineSnack)) {
|
||||||
trackList.filter { it.track != null }.map { item ->
|
scope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
trackList.filter { it.track != null }.map { item ->
|
||||||
val trackItem = try {
|
withContext(Dispatchers.IO) {
|
||||||
item.service.refresh(item.track!!)
|
val trackItem = try {
|
||||||
} catch (e: Exception) {
|
item.service.refresh(item.track!!)
|
||||||
trackError(e)
|
} catch (e: Exception) {
|
||||||
null
|
trackError(e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
if (trackItem != null) {
|
||||||
|
db.insertTrack(trackItem).executeAsBlocking()
|
||||||
|
trackItem
|
||||||
|
} else item.track
|
||||||
}
|
}
|
||||||
if (trackItem != null) {
|
|
||||||
db.insertTrack(trackItem).executeAsBlocking()
|
|
||||||
trackItem
|
|
||||||
} else item.track
|
|
||||||
}
|
}
|
||||||
|
refreshTracking()
|
||||||
}
|
}
|
||||||
refreshTracking()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun trackSearch(query: String, service: TrackService) {
|
fun trackSearch(query: String, service: TrackService) {
|
||||||
scope.launch(Dispatchers.IO) {
|
if (controller.isNotOnline()) {
|
||||||
val results = try {
|
scope.launch(Dispatchers.IO) {
|
||||||
service.search(query)
|
val results = try {
|
||||||
} catch (e: Exception) {
|
service.search(query)
|
||||||
withContext(Dispatchers.Main) { controller.trackSearchError(e) }
|
} catch (e: Exception) {
|
||||||
null
|
withContext(Dispatchers.Main) { controller.trackSearchError(e) }
|
||||||
}
|
null
|
||||||
if (!results.isNullOrEmpty()) {
|
}
|
||||||
withContext(Dispatchers.Main) { controller.onTrackSearchResults(results) }
|
if (!results.isNullOrEmpty()) {
|
||||||
|
withContext(Dispatchers.Main) { controller.onTrackSearchResults(results) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
|
|||||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
|
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
|
||||||
|
import eu.kanade.tachiyomi.util.view.hide
|
||||||
import eu.kanade.tachiyomi.util.view.setEdgeToEdge
|
import eu.kanade.tachiyomi.util.view.setEdgeToEdge
|
||||||
import kotlinx.android.synthetic.main.tracking_bottom_sheet.*
|
import kotlinx.android.synthetic.main.tracking_bottom_sheet.*
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -106,8 +107,12 @@ class TrackingBottomSheet(private val controller: MangaDetailsController) : Bott
|
|||||||
activity.toast(error.message)
|
activity.toast(error.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLogoClick(position: Int) {
|
override fun onLogoClick(position: Int) {
|
||||||
val track = adapter?.getItem(position)?.track ?: return
|
val track = adapter?.getItem(position)?.track ?: return
|
||||||
|
if (controller.isNotOnline()) {
|
||||||
|
sheetBehavior.hide()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (track.tracking_url.isBlank()) {
|
if (track.tracking_url.isBlank()) {
|
||||||
activity.toast(R.string.url_not_set_click_again)
|
activity.toast(R.string.url_not_set_click_again)
|
||||||
@ -119,6 +124,11 @@ class TrackingBottomSheet(private val controller: MangaDetailsController) : Bott
|
|||||||
|
|
||||||
override fun onSetClick(position: Int) {
|
override fun onSetClick(position: Int) {
|
||||||
val item = adapter?.getItem(position) ?: return
|
val item = adapter?.getItem(position) ?: return
|
||||||
|
if (controller.isNotOnline()) {
|
||||||
|
sheetBehavior.hide()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
TrackSearchDialog(this, item.service, item.track != null).showDialog(
|
TrackSearchDialog(this, item.service, item.track != null).showDialog(
|
||||||
controller.router,
|
controller.router,
|
||||||
TAG_SEARCH_CONTROLLER
|
TAG_SEARCH_CONTROLLER
|
||||||
@ -128,6 +138,10 @@ class TrackingBottomSheet(private val controller: MangaDetailsController) : Bott
|
|||||||
override fun onStatusClick(position: Int) {
|
override fun onStatusClick(position: Int) {
|
||||||
val item = adapter?.getItem(position) ?: return
|
val item = adapter?.getItem(position) ?: return
|
||||||
if (item.track == null) return
|
if (item.track == null) return
|
||||||
|
if (controller.isNotOnline()) {
|
||||||
|
dismiss()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
SetTrackStatusDialog(this, item).showDialog(controller.router)
|
SetTrackStatusDialog(this, item).showDialog(controller.router)
|
||||||
}
|
}
|
||||||
@ -135,13 +149,20 @@ class TrackingBottomSheet(private val controller: MangaDetailsController) : Bott
|
|||||||
override fun onChaptersClick(position: Int) {
|
override fun onChaptersClick(position: Int) {
|
||||||
val item = adapter?.getItem(position) ?: return
|
val item = adapter?.getItem(position) ?: return
|
||||||
if (item.track == null) return
|
if (item.track == null) return
|
||||||
|
if (controller.isNotOnline()) {
|
||||||
|
dismiss()
|
||||||
|
return
|
||||||
|
}
|
||||||
SetTrackChaptersDialog(this, item).showDialog(controller.router)
|
SetTrackChaptersDialog(this, item).showDialog(controller.router)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onScoreClick(position: Int) {
|
override fun onScoreClick(position: Int) {
|
||||||
val item = adapter?.getItem(position) ?: return
|
val item = adapter?.getItem(position) ?: return
|
||||||
if (item.track == null) return
|
if (item.track == null) return
|
||||||
|
if (controller.isNotOnline()) {
|
||||||
|
dismiss()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
SetTrackScoreDialog(this, item).showDialog(controller.router)
|
SetTrackScoreDialog(this, item).showDialog(controller.router)
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import android.content.res.Configuration
|
|||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -219,3 +220,22 @@ fun Context.isInNightMode(): Boolean {
|
|||||||
val currentNightMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
val currentNightMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
||||||
return currentNightMode == Configuration.UI_MODE_NIGHT_YES
|
return currentNightMode == Configuration.UI_MODE_NIGHT_YES
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Context.isOnline(): Boolean {
|
||||||
|
val connectivityManager = this
|
||||||
|
.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
|
||||||
|
var result = false
|
||||||
|
connectivityManager?.let {
|
||||||
|
val networkCapabilities = connectivityManager.activeNetwork ?: return false
|
||||||
|
val actNw =
|
||||||
|
connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
|
||||||
|
result = when {
|
||||||
|
actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
|
||||||
|
actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
|
||||||
|
actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user