Resolve some warinings

pull/311/head
Koitharu 3 years ago
parent efc4bbacb5
commit f38ff55aea
No known key found for this signature in database
GPG Key ID: 8E861F8CE6E7CE27

@ -2,7 +2,6 @@ package org.koitharu.kotatsu.base.ui
import android.app.Dialog import android.app.Dialog
import android.os.Bundle import android.os.Bundle
import android.util.DisplayMetrics
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -15,7 +14,8 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.dialog.AppBottomSheetDialog import org.koitharu.kotatsu.base.ui.dialog.AppBottomSheetDialog
import org.koitharu.kotatsu.utils.ext.displayCompat import org.koitharu.kotatsu.utils.ext.findActivity
import org.koitharu.kotatsu.utils.ext.getDisplaySize
import com.google.android.material.R as materialR import com.google.android.material.R as materialR
abstract class BaseBottomSheet<B : ViewBinding> : BottomSheetDialogFragment() { abstract class BaseBottomSheet<B : ViewBinding> : BottomSheetDialogFragment() {
@ -41,21 +41,20 @@ abstract class BaseBottomSheet<B : ViewBinding> : BottomSheetDialogFragment() {
): View { ): View {
val binding = onInflateView(inflater, container) val binding = onInflateView(inflater, container)
viewBinding = binding viewBinding = binding
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Enforce max width for tablets // Enforce max width for tablets
val width = resources.getDimensionPixelSize(R.dimen.bottom_sheet_width) val width = resources.getDimensionPixelSize(R.dimen.bottom_sheet_width)
if (width > 0) { if (width > 0) {
behavior?.maxWidth = width behavior?.maxWidth = width
} }
// Set peek height to 40% display height
// Set peek height to 50% display height binding.root.context.findActivity()?.getDisplaySize()?.let {
requireContext().displayCompat?.let { behavior?.peekHeight = (it.height() * 0.4).toInt()
val metrics = DisplayMetrics()
it.getRealMetrics(metrics)
behavior?.peekHeight = (metrics.heightPixels * 0.4).toInt()
} }
return binding.root
} }
override fun onDestroyView() { override fun onDestroyView() {

@ -12,13 +12,13 @@ class ReversibleActionObserver(
private val snackbarHost: View, private val snackbarHost: View,
) : Observer<ReversibleAction?> { ) : Observer<ReversibleAction?> {
override fun onChanged(action: ReversibleAction?) { override fun onChanged(value: ReversibleAction?) {
if (action == null) { if (value == null) {
return return
} }
val handle = action.handle val handle = value.handle
val length = if (handle == null) Snackbar.LENGTH_SHORT else Snackbar.LENGTH_LONG val length = if (handle == null) Snackbar.LENGTH_SHORT else Snackbar.LENGTH_LONG
val snackbar = Snackbar.make(snackbarHost, action.stringResId, length) val snackbar = Snackbar.make(snackbarHost, value.stringResId, length)
if (handle != null) { if (handle != null) {
snackbar.setAction(R.string.undo) { handle.reverseAsync() } snackbar.setAction(R.string.undo) { handle.reverseAsync() }
} }

@ -20,14 +20,13 @@ import org.koitharu.kotatsu.core.network.CommonHeaders
import org.koitharu.kotatsu.core.network.CommonHeadersInterceptor import org.koitharu.kotatsu.core.network.CommonHeadersInterceptor
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
import org.koitharu.kotatsu.databinding.FragmentCloudflareBinding import org.koitharu.kotatsu.databinding.FragmentCloudflareBinding
import org.koitharu.kotatsu.utils.ext.stringArgument
import org.koitharu.kotatsu.utils.ext.withArgs import org.koitharu.kotatsu.utils.ext.withArgs
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), CloudFlareCallback { class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), CloudFlareCallback {
private val url by stringArgument(ARG_URL) private lateinit var url: String
private val pendingResult = Bundle(1) private val pendingResult = Bundle(1)
@Inject @Inject
@ -35,6 +34,11 @@ class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), Cloud
private var onBackPressedCallback: WebViewBackPressedCallback? = null private var onBackPressedCallback: WebViewBackPressedCallback? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
url = requireArguments().getString(ARG_URL).orEmpty()
}
override fun onInflateView( override fun onInflateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@ -50,12 +54,12 @@ class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), Cloud
databaseEnabled = true databaseEnabled = true
userAgentString = arguments?.getString(ARG_UA) ?: CommonHeadersInterceptor.userAgentChrome userAgentString = arguments?.getString(ARG_UA) ?: CommonHeadersInterceptor.userAgentChrome
} }
binding.webView.webViewClient = CloudFlareClient(cookieJar, this, url.orEmpty()) binding.webView.webViewClient = CloudFlareClient(cookieJar, this, url)
CookieManager.getInstance().setAcceptThirdPartyCookies(binding.webView, true) CookieManager.getInstance().setAcceptThirdPartyCookies(binding.webView, true)
if (url.isNullOrEmpty()) { if (url.isEmpty()) {
dismissAllowingStateLoss() dismissAllowingStateLoss()
} else { } else {
binding.webView.loadUrl(url.orEmpty()) binding.webView.loadUrl(url)
} }
} }

@ -22,22 +22,22 @@ class DialogErrorObserver(
fragment: Fragment?, fragment: Fragment?,
) : this(host, fragment, null, null) ) : this(host, fragment, null, null)
override fun onChanged(error: Throwable?) { override fun onChanged(value: Throwable?) {
if (error == null) { if (value == null) {
return return
} }
val listener = DialogListener(error) val listener = DialogListener(value)
val dialogBuilder = MaterialAlertDialogBuilder(activity ?: host.context) val dialogBuilder = MaterialAlertDialogBuilder(activity ?: host.context)
.setMessage(error.getDisplayMessage(host.context.resources)) .setMessage(value.getDisplayMessage(host.context.resources))
.setNegativeButton(R.string.close, listener) .setNegativeButton(R.string.close, listener)
.setOnCancelListener(listener) .setOnCancelListener(listener)
if (canResolve(error)) { if (canResolve(value)) {
dialogBuilder.setPositiveButton(ExceptionResolver.getResolveStringId(error), listener) dialogBuilder.setPositiveButton(ExceptionResolver.getResolveStringId(value), listener)
} else if (error is ParseException) { } else if (value is ParseException) {
val fm = fragmentManager val fm = fragmentManager
if (fm != null) { if (fm != null) {
dialogBuilder.setPositiveButton(R.string.details) { _, _ -> dialogBuilder.setPositiveButton(R.string.details) { _, _ ->
ErrorDetailsDialog.show(fm, error, error.url) ErrorDetailsDialog.show(fm, value, value.url)
} }
} }
} }

@ -22,23 +22,23 @@ class SnackbarErrorObserver(
fragment: Fragment?, fragment: Fragment?,
) : this(host, fragment, null, null) ) : this(host, fragment, null, null)
override fun onChanged(error: Throwable?) { override fun onChanged(value: Throwable?) {
if (error == null) { if (value == null) {
return return
} }
val snackbar = Snackbar.make(host, error.getDisplayMessage(host.context.resources), Snackbar.LENGTH_SHORT) val snackbar = Snackbar.make(host, value.getDisplayMessage(host.context.resources), Snackbar.LENGTH_SHORT)
if (activity is BottomNavOwner) { if (activity is BottomNavOwner) {
snackbar.anchorView = activity.bottomNav snackbar.anchorView = activity.bottomNav
} }
if (canResolve(error)) { if (canResolve(value)) {
snackbar.setAction(ExceptionResolver.getResolveStringId(error)) { snackbar.setAction(ExceptionResolver.getResolveStringId(value)) {
resolve(error) resolve(value)
} }
} else if (error is ParseException) { } else if (value is ParseException) {
val fm = fragmentManager val fm = fragmentManager
if (fm != null) { if (fm != null) {
snackbar.setAction(R.string.details) { snackbar.setAction(R.string.details) {
ErrorDetailsDialog.show(fm, error, error.url) ErrorDetailsDialog.show(fm, value, value.url)
} }
} }
} }

@ -47,6 +47,7 @@ class ErrorDetailsDialog : AlertDialogFragment<DialogErrorDetailsBinding>() {
} }
} }
@Suppress("NAME_SHADOWING")
override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder { override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder {
val builder = super.onBuildDialog(builder) val builder = super.onBuildDialog(builder)
.setCancelable(true) .setCancelable(true)

@ -309,13 +309,13 @@ class DetailsActivity :
private var isCalled = false private var isCalled = false
override fun onChanged(t: List<ChapterListItem>?) { override fun onChanged(value: List<ChapterListItem>?) {
if (t.isNullOrEmpty()) { if (value.isNullOrEmpty()) {
return return
} }
if (!isCalled) { if (!isCalled) {
isCalled = true isCalled = true
val item = t.find { it.hasFlag(ChapterListItem.FLAG_CURRENT) } ?: t.first() val item = value.find { it.hasFlag(ChapterListItem.FLAG_CURRENT) } ?: value.first()
MangaPrefetchService.prefetchPages(context, item.chapter) MangaPrefetchService.prefetchPages(context, item.chapter)
} }
} }

@ -21,6 +21,7 @@ import org.koitharu.kotatsu.base.ui.BaseActivity
import org.koitharu.kotatsu.databinding.ActivityImageBinding import org.koitharu.kotatsu.databinding.ActivityImageBinding
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.utils.ext.enqueueWith import org.koitharu.kotatsu.utils.ext.enqueueWith
import org.koitharu.kotatsu.utils.ext.getSerializableExtraCompat
import org.koitharu.kotatsu.utils.ext.indicator import org.koitharu.kotatsu.utils.ext.indicator
import javax.inject.Inject import javax.inject.Inject
@ -57,7 +58,7 @@ class ImageActivity : BaseActivity<ActivityImageBinding>() {
.data(url) .data(url)
.memoryCachePolicy(CachePolicy.DISABLED) .memoryCachePolicy(CachePolicy.DISABLED)
.lifecycle(this) .lifecycle(this)
.tag(intent.getSerializableExtra(EXTRA_SOURCE) as? MangaSource) .tag(intent.getSerializableExtraCompat<MangaSource>(EXTRA_SOURCE))
.target(SsivTarget(binding.ssiv)) .target(SsivTarget(binding.ssiv))
.indicator(binding.progressBar) .indicator(binding.progressBar)
.enqueueWith(coil) .enqueueWith(coil)

@ -26,7 +26,7 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.commit import androidx.fragment.app.commit
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.whenResumed import androidx.lifecycle.withResumed
import androidx.transition.TransitionManager import androidx.transition.TransitionManager
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS import com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS
@ -310,11 +310,11 @@ class MainActivity :
private fun onFirstStart() { private fun onFirstStart() {
lifecycleScope.launch(Dispatchers.Main) { // not a default `Main.immediate` dispatcher lifecycleScope.launch(Dispatchers.Main) { // not a default `Main.immediate` dispatcher
when { when {
!settings.isSourcesSelected -> whenResumed { !settings.isSourcesSelected -> withResumed {
OnboardDialogFragment.showWelcome(supportFragmentManager) OnboardDialogFragment.showWelcome(supportFragmentManager)
} }
settings.newSources.isNotEmpty() -> whenResumed { settings.newSources.isNotEmpty() -> withResumed {
NewSourcesDialogFragment.show(supportFragmentManager) NewSourcesDialogFragment.show(supportFragmentManager)
} }
} }
@ -322,7 +322,7 @@ class MainActivity :
TrackWorker.setup(applicationContext) TrackWorker.setup(applicationContext)
SuggestionsWorker.setup(applicationContext) SuggestionsWorker.setup(applicationContext)
} }
whenResumed { withResumed {
MangaPrefetchService.prefetchLast(this@MainActivity) MangaPrefetchService.prefetchLast(this@MainActivity)
requestNotificationsPermission() requestNotificationsPermission()
} }

@ -103,7 +103,7 @@ class PageHolderDelegate(
} }
} }
override fun onChanged(t: ReaderSettings) { override fun onChanged(value: ReaderSettings) {
if (state == State.SHOWN) { if (state == State.SHOWN) {
callback.onImageShowing(readerSettings) callback.onImageShowing(readerSettings)
} }

@ -8,6 +8,7 @@ import android.view.ViewGroup
import androidx.core.view.children import androidx.core.view.children
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.os.NetworkState
import org.koitharu.kotatsu.databinding.FragmentReaderStandardBinding import org.koitharu.kotatsu.databinding.FragmentReaderStandardBinding
import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.domain.PageLoader
@ -86,7 +87,7 @@ class ReversedReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
override fun onPagesChanged(pages: List<ReaderPage>, pendingState: ReaderState?) { override fun onPagesChanged(pages: List<ReaderPage>, pendingState: ReaderState?) {
val reversedPages = pages.asReversed() val reversedPages = pages.asReversed()
viewLifecycleScope.launchWhenCreated { viewLifecycleScope.launch {
val items = async { val items = async {
pagerAdapter?.setItems(reversedPages) pagerAdapter?.setItems(reversedPages)
} }
@ -94,7 +95,7 @@ class ReversedReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
val position = reversedPages.indexOfLast { val position = reversedPages.indexOfLast {
it.chapterId == pendingState.chapterId && it.index == pendingState.page it.chapterId == pendingState.chapterId && it.index == pendingState.page
} }
items.await() ?: return@launchWhenCreated items.await() ?: return@launch
if (position != -1) { if (position != -1) {
binding.pager.setCurrentItem(position, false) binding.pager.setCurrentItem(position, false)
notifyPageChanged(position) notifyPageChanged(position)

@ -8,6 +8,7 @@ import android.view.ViewGroup
import androidx.core.view.children import androidx.core.view.children
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.os.NetworkState
import org.koitharu.kotatsu.databinding.FragmentReaderStandardBinding import org.koitharu.kotatsu.databinding.FragmentReaderStandardBinding
import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.domain.PageLoader
@ -71,7 +72,7 @@ class PagerReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
} }
override fun onPagesChanged(pages: List<ReaderPage>, pendingState: ReaderState?) { override fun onPagesChanged(pages: List<ReaderPage>, pendingState: ReaderState?) {
viewLifecycleScope.launchWhenCreated { viewLifecycleScope.launch {
val items = async { val items = async {
pagesAdapter?.setItems(pages) pagesAdapter?.setItems(pages)
} }
@ -79,7 +80,7 @@ class PagerReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
val position = pages.indexOfFirst { val position = pages.indexOfFirst {
it.chapterId == pendingState.chapterId && it.index == pendingState.page it.chapterId == pendingState.chapterId && it.index == pendingState.page
} }
items.await() ?: return@launchWhenCreated items.await() ?: return@launch
if (position != -1) { if (position != -1) {
binding.pager.setCurrentItem(position, false) binding.pager.setCurrentItem(position, false)
notifyPageChanged(position) notifyPageChanged(position)

@ -7,6 +7,7 @@ import android.view.ViewGroup
import android.view.animation.AccelerateDecelerateInterpolator import android.view.animation.AccelerateDecelerateInterpolator
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.os.NetworkState
import org.koitharu.kotatsu.databinding.FragmentReaderWebtoonBinding import org.koitharu.kotatsu.databinding.FragmentReaderWebtoonBinding
import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.domain.PageLoader
@ -62,13 +63,13 @@ class WebtoonReaderFragment : BaseReader<FragmentReaderWebtoonBinding>() {
} }
override fun onPagesChanged(pages: List<ReaderPage>, pendingState: ReaderState?) { override fun onPagesChanged(pages: List<ReaderPage>, pendingState: ReaderState?) {
viewLifecycleScope.launchWhenCreated { viewLifecycleScope.launch {
val setItems = async { webtoonAdapter?.setItems(pages) } val setItems = async { webtoonAdapter?.setItems(pages) }
if (pendingState != null) { if (pendingState != null) {
val position = pages.indexOfFirst { val position = pages.indexOfFirst {
it.chapterId == pendingState.chapterId && it.index == pendingState.page it.chapterId == pendingState.chapterId && it.index == pendingState.page
} }
setItems.await() ?: return@launchWhenCreated setItems.await() ?: return@launch
if (position != -1) { if (position != -1) {
with(binding.recyclerView) { with(binding.recyclerView) {
firstVisibleItemPosition = position firstVisibleItemPosition = position

@ -18,7 +18,7 @@ import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.remotelist.ui.RemoteListFragment import org.koitharu.kotatsu.remotelist.ui.RemoteListFragment
import org.koitharu.kotatsu.utils.ext.getParcelableExtraCompat import org.koitharu.kotatsu.utils.ext.getParcelableExtraCompat
import kotlin.text.Typography.dagger import org.koitharu.kotatsu.utils.ext.getSerializableExtraCompat
@AndroidEntryPoint @AndroidEntryPoint
class MangaListActivity : class MangaListActivity :
@ -33,7 +33,7 @@ class MangaListActivity :
setContentView(ActivityContainerBinding.inflate(layoutInflater)) setContentView(ActivityContainerBinding.inflate(layoutInflater))
val tags = intent.getParcelableExtraCompat<ParcelableMangaTags>(EXTRA_TAGS)?.tags val tags = intent.getParcelableExtraCompat<ParcelableMangaTags>(EXTRA_TAGS)?.tags
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
val source = intent.getSerializableExtra(EXTRA_SOURCE) as? MangaSource ?: tags?.firstOrNull()?.source val source = intent.getSerializableExtraCompat(EXTRA_SOURCE) ?: tags?.firstOrNull()?.source
if (source == null) { if (source == null) {
finishAfterTransition() finishAfterTransition()
return return

@ -15,6 +15,7 @@ import org.koitharu.kotatsu.base.ui.BaseActivity
import org.koitharu.kotatsu.databinding.ActivitySearchBinding import org.koitharu.kotatsu.databinding.ActivitySearchBinding
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionViewModel import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionViewModel
import org.koitharu.kotatsu.utils.ext.getSerializableExtraCompat
import org.koitharu.kotatsu.utils.ext.showKeyboard import org.koitharu.kotatsu.utils.ext.showKeyboard
@AndroidEntryPoint @AndroidEntryPoint
@ -26,7 +27,7 @@ class SearchActivity : BaseActivity<ActivitySearchBinding>(), SearchView.OnQuery
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(ActivitySearchBinding.inflate(layoutInflater)) setContentView(ActivitySearchBinding.inflate(layoutInflater))
source = intent.getSerializableExtra(EXTRA_SOURCE) as? MangaSource ?: run { source = intent.getSerializableExtraCompat(EXTRA_SOURCE) ?: run {
finishAfterTransition() finishAfterTransition()
return return
} }

@ -2,6 +2,7 @@ package org.koitharu.kotatsu.settings
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.lifecycle.Lifecycle
import androidx.preference.Preference import androidx.preference.Preference
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
@ -18,6 +19,7 @@ import org.koitharu.kotatsu.local.data.LocalStorageManager
import org.koitharu.kotatsu.search.domain.MangaSearchRepository import org.koitharu.kotatsu.search.domain.MangaSearchRepository
import org.koitharu.kotatsu.tracker.domain.TrackingRepository import org.koitharu.kotatsu.tracker.domain.TrackingRepository
import org.koitharu.kotatsu.utils.FileSize import org.koitharu.kotatsu.utils.FileSize
import org.koitharu.kotatsu.utils.ext.awaitStateAtLeast
import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.getDisplayMessage
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
import javax.inject.Inject import javax.inject.Inject
@ -51,17 +53,17 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
findPreference<Preference>(AppSettings.KEY_PAGES_CACHE_CLEAR)?.bindSummaryToCacheSize(CacheDir.PAGES) findPreference<Preference>(AppSettings.KEY_PAGES_CACHE_CLEAR)?.bindSummaryToCacheSize(CacheDir.PAGES)
findPreference<Preference>(AppSettings.KEY_THUMBS_CACHE_CLEAR)?.bindSummaryToCacheSize(CacheDir.THUMBS) findPreference<Preference>(AppSettings.KEY_THUMBS_CACHE_CLEAR)?.bindSummaryToCacheSize(CacheDir.THUMBS)
findPreference<Preference>(AppSettings.KEY_SEARCH_HISTORY_CLEAR)?.let { pref -> findPreference<Preference>(AppSettings.KEY_SEARCH_HISTORY_CLEAR)?.let { pref ->
viewLifecycleScope.launchWhenResumed { viewLifecycleScope.launch {
lifecycle.awaitStateAtLeast(Lifecycle.State.RESUMED)
val items = searchRepository.getSearchHistoryCount() val items = searchRepository.getSearchHistoryCount()
pref.summary = pref.summary = pref.context.resources.getQuantityString(R.plurals.items, items, items)
pref.context.resources.getQuantityString(R.plurals.items, items, items)
} }
} }
findPreference<Preference>(AppSettings.KEY_UPDATES_FEED_CLEAR)?.let { pref -> findPreference<Preference>(AppSettings.KEY_UPDATES_FEED_CLEAR)?.let { pref ->
viewLifecycleScope.launchWhenResumed { viewLifecycleScope.launch {
lifecycle.awaitStateAtLeast(Lifecycle.State.RESUMED)
val items = trackerRepo.getLogsCount() val items = trackerRepo.getLogsCount()
pref.summary = pref.summary = pref.context.resources.getQuantityString(R.plurals.items, items, items)
pref.context.resources.getQuantityString(R.plurals.items, items, items)
} }
} }
} }

@ -90,6 +90,7 @@ class SettingsActivity :
} }
} }
@Suppress("DEPRECATION")
override fun onPreferenceStartFragment( override fun onPreferenceStartFragment(
caller: PreferenceFragmentCompat, caller: PreferenceFragmentCompat,
pref: Preference, pref: Preference,

@ -22,8 +22,8 @@ import org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity
import org.koitharu.kotatsu.utils.ext.awaitViewLifecycle import org.koitharu.kotatsu.utils.ext.awaitViewLifecycle
import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.getDisplayMessage
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
import org.koitharu.kotatsu.utils.ext.requireSerializable
import org.koitharu.kotatsu.utils.ext.runCatchingCancellable import org.koitharu.kotatsu.utils.ext.runCatchingCancellable
import org.koitharu.kotatsu.utils.ext.serializableArgument
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
import org.koitharu.kotatsu.utils.ext.withArgs import org.koitharu.kotatsu.utils.ext.withArgs
import javax.inject.Inject import javax.inject.Inject
@ -34,10 +34,16 @@ class SourceSettingsFragment : BasePreferenceFragment(0) {
@Inject @Inject
lateinit var mangaRepositoryFactory: MangaRepository.Factory lateinit var mangaRepositoryFactory: MangaRepository.Factory
private val source by serializableArgument<MangaSource>(EXTRA_SOURCE) private lateinit var source: MangaSource
private var repository: RemoteMangaRepository? = null private var repository: RemoteMangaRepository? = null
private val exceptionResolver = ExceptionResolver(this) private val exceptionResolver = ExceptionResolver(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
source = requireArguments().requireSerializable(EXTRA_SOURCE)
repository = mangaRepositoryFactory.create(source) as? RemoteMangaRepository
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
setTitle(source.title) setTitle(source.title)
@ -45,8 +51,7 @@ class SourceSettingsFragment : BasePreferenceFragment(0) {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.sharedPreferencesName = source.name preferenceManager.sharedPreferencesName = source.name
val repo = mangaRepositoryFactory.create(source) as? RemoteMangaRepository ?: return val repo = repository ?: return
repository = repo
addPreferencesFromResource(R.xml.pref_source) addPreferencesFromResource(R.xml.pref_source)
addPreferencesFromRepository(repo) addPreferencesFromRepository(repo)

@ -26,6 +26,7 @@ import org.koitharu.kotatsu.databinding.ActivityBrowserBinding
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.utils.TaggedActivityResult import org.koitharu.kotatsu.utils.TaggedActivityResult
import org.koitharu.kotatsu.utils.ext.getSerializableExtraCompat
import javax.inject.Inject import javax.inject.Inject
import com.google.android.material.R as materialR import com.google.android.material.R as materialR
@ -42,7 +43,7 @@ class SourceAuthActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallba
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(ActivityBrowserBinding.inflate(layoutInflater)) setContentView(ActivityBrowserBinding.inflate(layoutInflater))
val source = intent?.getSerializableExtra(EXTRA_SOURCE) as? MangaSource val source = intent?.getSerializableExtraCompat(EXTRA_SOURCE) as? MangaSource
if (source == null) { if (source == null) {
finishAfterTransition() finishAfterTransition()
return return

@ -1,8 +1,67 @@
package org.koitharu.kotatsu.utils.ext package org.koitharu.kotatsu.utils.ext
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleCoroutineScope import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.LifecycleDestroyedException
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
val processLifecycleScope: LifecycleCoroutineScope val processLifecycleScope: LifecycleCoroutineScope
inline get() = ProcessLifecycleOwner.get().lifecycleScope inline get() = ProcessLifecycleOwner.get().lifecycleScope
suspend fun Lifecycle.awaitStateAtLeast(state: Lifecycle.State) {
if (currentState.isAtLeast(state)) {
return
}
suspendCancellableCoroutine { cont ->
val observer = ContinuationLifecycleObserver(this, cont, state)
addObserverFromAnyThread(observer)
cont.invokeOnCancellation {
removeObserverFromAnyThread(observer)
}
}
}
private class ContinuationLifecycleObserver(
private val lifecycle: Lifecycle,
private val continuation: CancellableContinuation<Unit>,
private val targetState: Lifecycle.State,
) : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (event == Lifecycle.Event.upTo(targetState)) {
lifecycle.removeObserver(this)
continuation.resume(Unit)
} else if (event == Lifecycle.Event.ON_DESTROY) {
lifecycle.removeObserver(this)
continuation.resumeWithException(LifecycleDestroyedException())
}
}
}
private fun Lifecycle.addObserverFromAnyThread(observer: LifecycleObserver) {
val dispatcher = Dispatchers.Main.immediate
if (dispatcher.isDispatchNeeded(EmptyCoroutineContext)) {
dispatcher.dispatch(EmptyCoroutineContext) { addObserver(observer) }
} else {
addObserver(observer)
}
}
private fun Lifecycle.removeObserverFromAnyThread(observer: LifecycleObserver) {
val dispatcher = Dispatchers.Main.immediate
if (dispatcher.isDispatchNeeded(EmptyCoroutineContext)) {
dispatcher.dispatch(EmptyCoroutineContext) { removeObserver(observer) }
} else {
removeObserver(observer)
}
}

@ -1,15 +1,25 @@
package org.koitharu.kotatsu.utils.ext package org.koitharu.kotatsu.utils.ext
import android.content.Context import android.app.Activity
import android.graphics.Rect
import android.os.Build import android.os.Build
import android.util.DisplayMetrics
import android.view.Display import android.view.Display
import android.view.WindowManager
import androidx.core.content.getSystemService
val Context.displayCompat: Display? @Suppress("DEPRECATION")
val Activity.displayCompat: Display
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
display display ?: windowManager.defaultDisplay
} else { } else {
@Suppress("DEPRECATION") windowManager.defaultDisplay
getSystemService<WindowManager>()?.defaultDisplay
} }
fun Activity.getDisplaySize(): Rect {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
windowManager.currentWindowMetrics.bounds
} else {
val dm = DisplayMetrics()
displayCompat.getRealMetrics(dm)
Rect(0, 0, dm.widthPixels, dm.heightPixels)
}
}

@ -1,6 +1,7 @@
package org.koitharu.kotatsu.utils.ext package org.koitharu.kotatsu.utils.ext
import android.os.Bundle import android.os.Bundle
import androidx.annotation.MainThread
import androidx.core.view.MenuProvider import androidx.core.view.MenuProvider
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
@ -10,7 +11,6 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.coroutineScope import androidx.lifecycle.coroutineScope
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
import java.io.Serializable
import kotlin.coroutines.resume import kotlin.coroutines.resume
inline fun <T : Fragment> T.withArgs(size: Int, block: Bundle.() -> Unit): T { inline fun <T : Fragment> T.withArgs(size: Int, block: Bundle.() -> Unit): T {
@ -23,21 +23,6 @@ inline fun <T : Fragment> T.withArgs(size: Int, block: Bundle.() -> Unit): T {
val Fragment.viewLifecycleScope val Fragment.viewLifecycleScope
inline get() = viewLifecycleOwner.lifecycle.coroutineScope inline get() = viewLifecycleOwner.lifecycle.coroutineScope
@Deprecated("")
fun <T : Serializable> Fragment.serializableArgument(name: String): Lazy<T> {
return lazy(LazyThreadSafetyMode.NONE) {
@Suppress("UNCHECKED_CAST")
requireNotNull(arguments?.getSerializableCompat(name)) {
"No argument $name passed into ${javaClass.simpleName}"
} as T
}
}
@Deprecated("")
fun Fragment.stringArgument(name: String) = lazy(LazyThreadSafetyMode.NONE) {
arguments?.getString(name)
}
fun DialogFragment.showAllowStateLoss(manager: FragmentManager, tag: String?) { fun DialogFragment.showAllowStateLoss(manager: FragmentManager, tag: String?) {
if (!manager.isStateSaved) { if (!manager.isStateSaved) {
show(manager, tag) show(manager, tag)
@ -48,6 +33,7 @@ fun Fragment.addMenuProvider(provider: MenuProvider) {
requireActivity().addMenuProvider(provider, viewLifecycleOwner, Lifecycle.State.STARTED) requireActivity().addMenuProvider(provider, viewLifecycleOwner, Lifecycle.State.STARTED)
} }
@MainThread
suspend fun Fragment.awaitViewLifecycle(): LifecycleOwner = suspendCancellableCoroutine { cont -> suspend fun Fragment.awaitViewLifecycle(): LifecycleOwner = suspendCancellableCoroutine { cont ->
val liveData = viewLifecycleOwnerLiveData val liveData = viewLifecycleOwnerLiveData
val observer = object : Observer<LifecycleOwner?> { val observer = object : Observer<LifecycleOwner?> {

Loading…
Cancel
Save