diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseBottomSheet.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseBottomSheet.kt index a7252ecb9..6207ce83f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseBottomSheet.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/BaseBottomSheet.kt @@ -2,7 +2,6 @@ package org.koitharu.kotatsu.base.ui import android.app.Dialog import android.os.Bundle -import android.util.DisplayMetrics import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -15,7 +14,8 @@ import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialogFragment import org.koitharu.kotatsu.R 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 abstract class BaseBottomSheet : BottomSheetDialogFragment() { @@ -41,21 +41,20 @@ abstract class BaseBottomSheet : BottomSheetDialogFragment() { ): View { val binding = onInflateView(inflater, container) viewBinding = binding + return binding.root + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) // Enforce max width for tablets val width = resources.getDimensionPixelSize(R.dimen.bottom_sheet_width) if (width > 0) { behavior?.maxWidth = width } - - // Set peek height to 50% display height - requireContext().displayCompat?.let { - val metrics = DisplayMetrics() - it.getRealMetrics(metrics) - behavior?.peekHeight = (metrics.heightPixels * 0.4).toInt() + // Set peek height to 40% display height + binding.root.context.findActivity()?.getDisplaySize()?.let { + behavior?.peekHeight = (it.height() * 0.4).toInt() } - - return binding.root } override fun onDestroyView() { diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/util/ReversibleActionObserver.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/util/ReversibleActionObserver.kt index b9af794f5..04a332cd2 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/util/ReversibleActionObserver.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/util/ReversibleActionObserver.kt @@ -12,13 +12,13 @@ class ReversibleActionObserver( private val snackbarHost: View, ) : Observer { - override fun onChanged(action: ReversibleAction?) { - if (action == null) { + override fun onChanged(value: ReversibleAction?) { + if (value == null) { return } - val handle = action.handle + val handle = value.handle 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) { snackbar.setAction(R.string.undo) { handle.reverseAsync() } } diff --git a/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt b/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt index 1a70db008..34f02003c 100644 --- a/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt +++ b/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt @@ -20,14 +20,13 @@ import org.koitharu.kotatsu.core.network.CommonHeaders import org.koitharu.kotatsu.core.network.CommonHeadersInterceptor import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar import org.koitharu.kotatsu.databinding.FragmentCloudflareBinding -import org.koitharu.kotatsu.utils.ext.stringArgument import org.koitharu.kotatsu.utils.ext.withArgs import javax.inject.Inject @AndroidEntryPoint class CloudFlareDialog : AlertDialogFragment(), CloudFlareCallback { - private val url by stringArgument(ARG_URL) + private lateinit var url: String private val pendingResult = Bundle(1) @Inject @@ -35,6 +34,11 @@ class CloudFlareDialog : AlertDialogFragment(), Cloud private var onBackPressedCallback: WebViewBackPressedCallback? = null + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + url = requireArguments().getString(ARG_URL).orEmpty() + } + override fun onInflateView( inflater: LayoutInflater, container: ViewGroup?, @@ -50,12 +54,12 @@ class CloudFlareDialog : AlertDialogFragment(), Cloud databaseEnabled = true 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) - if (url.isNullOrEmpty()) { + if (url.isEmpty()) { dismissAllowingStateLoss() } else { - binding.webView.loadUrl(url.orEmpty()) + binding.webView.loadUrl(url) } } diff --git a/app/src/main/java/org/koitharu/kotatsu/core/exceptions/resolve/DialogErrorObserver.kt b/app/src/main/java/org/koitharu/kotatsu/core/exceptions/resolve/DialogErrorObserver.kt index 365151648..c3bc2f893 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/exceptions/resolve/DialogErrorObserver.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/exceptions/resolve/DialogErrorObserver.kt @@ -22,22 +22,22 @@ class DialogErrorObserver( fragment: Fragment?, ) : this(host, fragment, null, null) - override fun onChanged(error: Throwable?) { - if (error == null) { + override fun onChanged(value: Throwable?) { + if (value == null) { return } - val listener = DialogListener(error) + val listener = DialogListener(value) val dialogBuilder = MaterialAlertDialogBuilder(activity ?: host.context) - .setMessage(error.getDisplayMessage(host.context.resources)) + .setMessage(value.getDisplayMessage(host.context.resources)) .setNegativeButton(R.string.close, listener) .setOnCancelListener(listener) - if (canResolve(error)) { - dialogBuilder.setPositiveButton(ExceptionResolver.getResolveStringId(error), listener) - } else if (error is ParseException) { + if (canResolve(value)) { + dialogBuilder.setPositiveButton(ExceptionResolver.getResolveStringId(value), listener) + } else if (value is ParseException) { val fm = fragmentManager if (fm != null) { dialogBuilder.setPositiveButton(R.string.details) { _, _ -> - ErrorDetailsDialog.show(fm, error, error.url) + ErrorDetailsDialog.show(fm, value, value.url) } } } diff --git a/app/src/main/java/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt b/app/src/main/java/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt index ff0df6ba6..fb3cea7d9 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt @@ -22,23 +22,23 @@ class SnackbarErrorObserver( fragment: Fragment?, ) : this(host, fragment, null, null) - override fun onChanged(error: Throwable?) { - if (error == null) { + override fun onChanged(value: Throwable?) { + if (value == null) { 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) { snackbar.anchorView = activity.bottomNav } - if (canResolve(error)) { - snackbar.setAction(ExceptionResolver.getResolveStringId(error)) { - resolve(error) + if (canResolve(value)) { + snackbar.setAction(ExceptionResolver.getResolveStringId(value)) { + resolve(value) } - } else if (error is ParseException) { + } else if (value is ParseException) { val fm = fragmentManager if (fm != null) { snackbar.setAction(R.string.details) { - ErrorDetailsDialog.show(fm, error, error.url) + ErrorDetailsDialog.show(fm, value, value.url) } } } diff --git a/app/src/main/java/org/koitharu/kotatsu/core/ui/ErrorDetailsDialog.kt b/app/src/main/java/org/koitharu/kotatsu/core/ui/ErrorDetailsDialog.kt index 02102ae0d..a9bb5eb8a 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/ui/ErrorDetailsDialog.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/ui/ErrorDetailsDialog.kt @@ -47,6 +47,7 @@ class ErrorDetailsDialog : AlertDialogFragment() { } } + @Suppress("NAME_SHADOWING") override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder { val builder = super.onBuildDialog(builder) .setCancelable(true) diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt index 0ac1023a4..1250b1df0 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt @@ -309,13 +309,13 @@ class DetailsActivity : private var isCalled = false - override fun onChanged(t: List?) { - if (t.isNullOrEmpty()) { + override fun onChanged(value: List?) { + if (value.isNullOrEmpty()) { return } if (!isCalled) { 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) } } diff --git a/app/src/main/java/org/koitharu/kotatsu/image/ui/ImageActivity.kt b/app/src/main/java/org/koitharu/kotatsu/image/ui/ImageActivity.kt index 0fe13a2d3..9794039e8 100644 --- a/app/src/main/java/org/koitharu/kotatsu/image/ui/ImageActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/image/ui/ImageActivity.kt @@ -21,6 +21,7 @@ import org.koitharu.kotatsu.base.ui.BaseActivity import org.koitharu.kotatsu.databinding.ActivityImageBinding import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.utils.ext.enqueueWith +import org.koitharu.kotatsu.utils.ext.getSerializableExtraCompat import org.koitharu.kotatsu.utils.ext.indicator import javax.inject.Inject @@ -57,7 +58,7 @@ class ImageActivity : BaseActivity() { .data(url) .memoryCachePolicy(CachePolicy.DISABLED) .lifecycle(this) - .tag(intent.getSerializableExtra(EXTRA_SOURCE) as? MangaSource) + .tag(intent.getSerializableExtraCompat(EXTRA_SOURCE)) .target(SsivTarget(binding.ssiv)) .indicator(binding.progressBar) .enqueueWith(coil) diff --git a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt index a132031fc..f226c686b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt @@ -26,7 +26,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentTransaction import androidx.fragment.app.commit import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.whenResumed +import androidx.lifecycle.withResumed import androidx.transition.TransitionManager import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS @@ -310,11 +310,11 @@ class MainActivity : private fun onFirstStart() { lifecycleScope.launch(Dispatchers.Main) { // not a default `Main.immediate` dispatcher when { - !settings.isSourcesSelected -> whenResumed { + !settings.isSourcesSelected -> withResumed { OnboardDialogFragment.showWelcome(supportFragmentManager) } - settings.newSources.isNotEmpty() -> whenResumed { + settings.newSources.isNotEmpty() -> withResumed { NewSourcesDialogFragment.show(supportFragmentManager) } } @@ -322,7 +322,7 @@ class MainActivity : TrackWorker.setup(applicationContext) SuggestionsWorker.setup(applicationContext) } - whenResumed { + withResumed { MangaPrefetchService.prefetchLast(this@MainActivity) requestNotificationsPermission() } diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt index bb1e8c37b..a517f630a 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/PageHolderDelegate.kt @@ -103,7 +103,7 @@ class PageHolderDelegate( } } - override fun onChanged(t: ReaderSettings) { + override fun onChanged(value: ReaderSettings) { if (state == State.SHOWN) { callback.onImageShowing(readerSettings) } diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt index d2a87ab44..19736f5c6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt @@ -8,6 +8,7 @@ import android.view.ViewGroup import androidx.core.view.children import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.async +import kotlinx.coroutines.launch import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.databinding.FragmentReaderStandardBinding import org.koitharu.kotatsu.reader.domain.PageLoader @@ -86,7 +87,7 @@ class ReversedReaderFragment : BaseReader() { override fun onPagesChanged(pages: List, pendingState: ReaderState?) { val reversedPages = pages.asReversed() - viewLifecycleScope.launchWhenCreated { + viewLifecycleScope.launch { val items = async { pagerAdapter?.setItems(reversedPages) } @@ -94,7 +95,7 @@ class ReversedReaderFragment : BaseReader() { val position = reversedPages.indexOfLast { it.chapterId == pendingState.chapterId && it.index == pendingState.page } - items.await() ?: return@launchWhenCreated + items.await() ?: return@launch if (position != -1) { binding.pager.setCurrentItem(position, false) notifyPageChanged(position) diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt index 56a414baf..4ec6d759f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt @@ -8,6 +8,7 @@ import android.view.ViewGroup import androidx.core.view.children import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.async +import kotlinx.coroutines.launch import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.databinding.FragmentReaderStandardBinding import org.koitharu.kotatsu.reader.domain.PageLoader @@ -71,7 +72,7 @@ class PagerReaderFragment : BaseReader() { } override fun onPagesChanged(pages: List, pendingState: ReaderState?) { - viewLifecycleScope.launchWhenCreated { + viewLifecycleScope.launch { val items = async { pagesAdapter?.setItems(pages) } @@ -79,7 +80,7 @@ class PagerReaderFragment : BaseReader() { val position = pages.indexOfFirst { it.chapterId == pendingState.chapterId && it.index == pendingState.page } - items.await() ?: return@launchWhenCreated + items.await() ?: return@launch if (position != -1) { binding.pager.setCurrentItem(position, false) notifyPageChanged(position) diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt index 80b48b1a6..ff1e79e6e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt @@ -7,6 +7,7 @@ import android.view.ViewGroup import android.view.animation.AccelerateDecelerateInterpolator import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.async +import kotlinx.coroutines.launch import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.databinding.FragmentReaderWebtoonBinding import org.koitharu.kotatsu.reader.domain.PageLoader @@ -62,13 +63,13 @@ class WebtoonReaderFragment : BaseReader() { } override fun onPagesChanged(pages: List, pendingState: ReaderState?) { - viewLifecycleScope.launchWhenCreated { + viewLifecycleScope.launch { val setItems = async { webtoonAdapter?.setItems(pages) } if (pendingState != null) { val position = pages.indexOfFirst { it.chapterId == pendingState.chapterId && it.index == pendingState.page } - setItems.await() ?: return@launchWhenCreated + setItems.await() ?: return@launch if (position != -1) { with(binding.recyclerView) { firstVisibleItemPosition = position diff --git a/app/src/main/java/org/koitharu/kotatsu/search/ui/MangaListActivity.kt b/app/src/main/java/org/koitharu/kotatsu/search/ui/MangaListActivity.kt index 08891d4ba..c1063de8c 100644 --- a/app/src/main/java/org/koitharu/kotatsu/search/ui/MangaListActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/search/ui/MangaListActivity.kt @@ -18,7 +18,7 @@ import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.remotelist.ui.RemoteListFragment import org.koitharu.kotatsu.utils.ext.getParcelableExtraCompat -import kotlin.text.Typography.dagger +import org.koitharu.kotatsu.utils.ext.getSerializableExtraCompat @AndroidEntryPoint class MangaListActivity : @@ -33,7 +33,7 @@ class MangaListActivity : setContentView(ActivityContainerBinding.inflate(layoutInflater)) val tags = intent.getParcelableExtraCompat(EXTRA_TAGS)?.tags 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) { finishAfterTransition() return diff --git a/app/src/main/java/org/koitharu/kotatsu/search/ui/SearchActivity.kt b/app/src/main/java/org/koitharu/kotatsu/search/ui/SearchActivity.kt index 6d14265be..f86f82b3e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/search/ui/SearchActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/search/ui/SearchActivity.kt @@ -15,6 +15,7 @@ import org.koitharu.kotatsu.base.ui.BaseActivity import org.koitharu.kotatsu.databinding.ActivitySearchBinding import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionViewModel +import org.koitharu.kotatsu.utils.ext.getSerializableExtraCompat import org.koitharu.kotatsu.utils.ext.showKeyboard @AndroidEntryPoint @@ -26,7 +27,7 @@ class SearchActivity : BaseActivity(), SearchView.OnQuery override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(ActivitySearchBinding.inflate(layoutInflater)) - source = intent.getSerializableExtra(EXTRA_SOURCE) as? MangaSource ?: run { + source = intent.getSerializableExtraCompat(EXTRA_SOURCE) ?: run { finishAfterTransition() return } diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt index cc0cf7cf4..c0b53620a 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/HistorySettingsFragment.kt @@ -2,6 +2,7 @@ package org.koitharu.kotatsu.settings import android.os.Bundle import android.view.View +import androidx.lifecycle.Lifecycle import androidx.preference.Preference import com.google.android.material.dialog.MaterialAlertDialogBuilder 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.tracker.domain.TrackingRepository 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.viewLifecycleScope import javax.inject.Inject @@ -51,17 +53,17 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach findPreference(AppSettings.KEY_PAGES_CACHE_CLEAR)?.bindSummaryToCacheSize(CacheDir.PAGES) findPreference(AppSettings.KEY_THUMBS_CACHE_CLEAR)?.bindSummaryToCacheSize(CacheDir.THUMBS) findPreference(AppSettings.KEY_SEARCH_HISTORY_CLEAR)?.let { pref -> - viewLifecycleScope.launchWhenResumed { + viewLifecycleScope.launch { + lifecycle.awaitStateAtLeast(Lifecycle.State.RESUMED) val items = searchRepository.getSearchHistoryCount() - pref.summary = - pref.context.resources.getQuantityString(R.plurals.items, items, items) + pref.summary = pref.context.resources.getQuantityString(R.plurals.items, items, items) } } findPreference(AppSettings.KEY_UPDATES_FEED_CLEAR)?.let { pref -> - viewLifecycleScope.launchWhenResumed { + viewLifecycleScope.launch { + lifecycle.awaitStateAtLeast(Lifecycle.State.RESUMED) val items = trackerRepo.getLogsCount() - pref.summary = - pref.context.resources.getQuantityString(R.plurals.items, items, items) + pref.summary = pref.context.resources.getQuantityString(R.plurals.items, items, items) } } } diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/SettingsActivity.kt b/app/src/main/java/org/koitharu/kotatsu/settings/SettingsActivity.kt index d2014a9ba..31dce19a6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/SettingsActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/SettingsActivity.kt @@ -90,6 +90,7 @@ class SettingsActivity : } } + @Suppress("DEPRECATION") override fun onPreferenceStartFragment( caller: PreferenceFragmentCompat, pref: Preference, diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsFragment.kt index dbad1e134..3079dc7b1 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/SourceSettingsFragment.kt @@ -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.getDisplayMessage 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.serializableArgument import org.koitharu.kotatsu.utils.ext.viewLifecycleScope import org.koitharu.kotatsu.utils.ext.withArgs import javax.inject.Inject @@ -34,10 +34,16 @@ class SourceSettingsFragment : BasePreferenceFragment(0) { @Inject lateinit var mangaRepositoryFactory: MangaRepository.Factory - private val source by serializableArgument(EXTRA_SOURCE) + private lateinit var source: MangaSource private var repository: RemoteMangaRepository? = null 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() { super.onResume() setTitle(source.title) @@ -45,8 +51,7 @@ class SourceSettingsFragment : BasePreferenceFragment(0) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { preferenceManager.sharedPreferencesName = source.name - val repo = mangaRepositoryFactory.create(source) as? RemoteMangaRepository ?: return - repository = repo + val repo = repository ?: return addPreferencesFromResource(R.xml.pref_source) addPreferencesFromRepository(repo) diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/sources/auth/SourceAuthActivity.kt b/app/src/main/java/org/koitharu/kotatsu/settings/sources/auth/SourceAuthActivity.kt index 8862948d5..9a64993a0 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/sources/auth/SourceAuthActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/sources/auth/SourceAuthActivity.kt @@ -26,6 +26,7 @@ import org.koitharu.kotatsu.databinding.ActivityBrowserBinding import org.koitharu.kotatsu.parsers.MangaParserAuthProvider import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.utils.TaggedActivityResult +import org.koitharu.kotatsu.utils.ext.getSerializableExtraCompat import javax.inject.Inject import com.google.android.material.R as materialR @@ -42,7 +43,7 @@ class SourceAuthActivity : BaseActivity(), BrowserCallba override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(ActivityBrowserBinding.inflate(layoutInflater)) - val source = intent?.getSerializableExtra(EXTRA_SOURCE) as? MangaSource + val source = intent?.getSerializableExtraCompat(EXTRA_SOURCE) as? MangaSource if (source == null) { finishAfterTransition() return diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoroutineExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoroutineExt.kt index 27e9ca459..3120f2f68 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoroutineExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoroutineExt.kt @@ -1,8 +1,67 @@ package org.koitharu.kotatsu.utils.ext +import androidx.lifecycle.Lifecycle 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.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 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, + 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) + } +} diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/DisplayExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/DisplayExt.kt index 205b98968..6f917ac1e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/DisplayExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/DisplayExt.kt @@ -1,15 +1,25 @@ package org.koitharu.kotatsu.utils.ext -import android.content.Context +import android.app.Activity +import android.graphics.Rect import android.os.Build +import android.util.DisplayMetrics 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) { - display + display ?: windowManager.defaultDisplay } else { - @Suppress("DEPRECATION") - getSystemService()?.defaultDisplay + 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) + } +} diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt index 44113f458..dec45bde0 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt @@ -1,6 +1,7 @@ package org.koitharu.kotatsu.utils.ext import android.os.Bundle +import androidx.annotation.MainThread import androidx.core.view.MenuProvider import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment @@ -10,7 +11,6 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.Observer import androidx.lifecycle.coroutineScope import kotlinx.coroutines.suspendCancellableCoroutine -import java.io.Serializable import kotlin.coroutines.resume inline fun T.withArgs(size: Int, block: Bundle.() -> Unit): T { @@ -23,21 +23,6 @@ inline fun T.withArgs(size: Int, block: Bundle.() -> Unit): T { val Fragment.viewLifecycleScope inline get() = viewLifecycleOwner.lifecycle.coroutineScope -@Deprecated("") -fun Fragment.serializableArgument(name: String): Lazy { - 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?) { if (!manager.isStateSaved) { show(manager, tag) @@ -48,6 +33,7 @@ fun Fragment.addMenuProvider(provider: MenuProvider) { requireActivity().addMenuProvider(provider, viewLifecycleOwner, Lifecycle.State.STARTED) } +@MainThread suspend fun Fragment.awaitViewLifecycle(): LifecycleOwner = suspendCancellableCoroutine { cont -> val liveData = viewLifecycleOwnerLiveData val observer = object : Observer {