Refactoring

pull/377/head
Koitharu 3 years ago
parent 65ed5c7e6b
commit 96c89a716e
No known key found for this signature in database
GPG Key ID: 8E861F8CE6E7CE27

@ -59,7 +59,7 @@ android {
} }
lint { lint {
abortOnError true abortOnError true
disable 'MissingTranslation', 'PrivateResource', 'NotifyDataSetChanged' disable 'MissingTranslation', 'PrivateResource', 'NotifyDataSetChanged', 'SetJavaScriptEnabled'
} }
testOptions { testOptions {
unitTests.includeAndroidResources true unitTests.includeAndroidResources true

@ -8,7 +8,7 @@
public static void checkParameterIsNotNull(...); public static void checkParameterIsNotNull(...);
public static void checkNotNullParameter(...); public static void checkNotNullParameter(...);
} }
-keep public class ** extends org.koitharu.kotatsu.base.ui.BaseFragment -keep public class ** extends org.koitharu.kotatsu.core.ui.BaseFragment
-keep class org.koitharu.kotatsu.core.db.entity.* { *; } -keep class org.koitharu.kotatsu.core.db.entity.* { *; }
-dontwarn okhttp3.internal.platform.** -dontwarn okhttp3.internal.platform.**
-dontwarn org.conscrypt.** -dontwarn org.conscrypt.**

@ -3,7 +3,6 @@ package org.koitharu.kotatsu.tracker.domain
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import javax.inject.Inject
import junit.framework.TestCase.* import junit.framework.TestCase.*
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Before import org.junit.Before
@ -11,8 +10,9 @@ import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.koitharu.kotatsu.SampleData import org.koitharu.kotatsu.SampleData
import org.koitharu.kotatsu.base.domain.MangaDataRepository import org.koitharu.kotatsu.core.parser.MangaDataRepository
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import javax.inject.Inject
@HiltAndroidTest @HiltAndroidTest
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.utils package org.koitharu.kotatsu.util
import android.util.Log import android.util.Log
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver

@ -0,0 +1,3 @@
package org.koitharu.kotatsu.util.ext
fun Throwable.printStackTraceDebug() = printStackTrace()

@ -1,3 +0,0 @@
package org.koitharu.kotatsu.utils.ext
fun Throwable.printStackTraceDebug() = printStackTrace()

@ -20,12 +20,12 @@ import org.acra.ktx.initAcra
import org.acra.sender.HttpSender import org.acra.sender.HttpSender
import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.WorkServiceStopHelper
import org.koitharu.kotatsu.core.util.ext.processLifecycleScope
import org.koitharu.kotatsu.local.data.PagesCache import org.koitharu.kotatsu.local.data.PagesCache
import org.koitharu.kotatsu.local.domain.LocalMangaRepository import org.koitharu.kotatsu.local.domain.LocalMangaRepository
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.utils.WorkServiceStopHelper
import org.koitharu.kotatsu.utils.ext.processLifecycleScope
import javax.inject.Inject import javax.inject.Inject
@HiltAndroidApp @HiltAndroidApp

@ -1,5 +0,0 @@
package org.koitharu.kotatsu.base.ui
import androidx.lifecycle.LifecycleService
abstract class BaseService : LifecycleService()

@ -5,7 +5,6 @@ import androidx.room.withTransaction
import dagger.Reusable import dagger.Reusable
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import org.koitharu.kotatsu.base.domain.ReversibleHandle
import org.koitharu.kotatsu.bookmarks.data.BookmarkEntity import org.koitharu.kotatsu.bookmarks.data.BookmarkEntity
import org.koitharu.kotatsu.bookmarks.data.toBookmark import org.koitharu.kotatsu.bookmarks.data.toBookmark
import org.koitharu.kotatsu.bookmarks.data.toBookmarks import org.koitharu.kotatsu.bookmarks.data.toBookmarks
@ -14,9 +13,10 @@ import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.db.entity.toEntities import org.koitharu.kotatsu.core.db.entity.toEntities
import org.koitharu.kotatsu.core.db.entity.toEntity import org.koitharu.kotatsu.core.db.entity.toEntity
import org.koitharu.kotatsu.core.db.entity.toManga import org.koitharu.kotatsu.core.db.entity.toManga
import org.koitharu.kotatsu.core.ui.util.ReversibleHandle
import org.koitharu.kotatsu.core.util.ext.mapItems
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.utils.ext.mapItems import org.koitharu.kotatsu.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
import javax.inject.Inject import javax.inject.Inject
@Reusable @Reusable

@ -3,16 +3,14 @@ package org.koitharu.kotatsu.bookmarks.ui
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.ViewGroup
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.commit import androidx.fragment.app.commit
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BaseActivity import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.databinding.ActivityContainerBinding import org.koitharu.kotatsu.databinding.ActivityContainerBinding
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
import org.koitharu.kotatsu.main.ui.owners.SnackbarOwner import org.koitharu.kotatsu.main.ui.owners.SnackbarOwner
@ -24,10 +22,10 @@ class BookmarksActivity :
SnackbarOwner { SnackbarOwner {
override val appBar: AppBarLayout override val appBar: AppBarLayout
get() = binding.appbar get() = viewBinding.appbar
override val snackbarHost: CoordinatorLayout override val snackbarHost: CoordinatorLayout
get() = binding.root get() = viewBinding.root
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -43,7 +41,7 @@ class BookmarksActivity :
} }
override fun onWindowInsetsChanged(insets: Insets) { override fun onWindowInsetsChanged(insets: Insets) {
binding.root.updatePadding( viewBinding.root.updatePadding(
left = insets.left, left = insets.left,
right = insets.right, right = insets.right,
) )

@ -16,19 +16,21 @@ import coil.ImageLoader
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.domain.reverseAsync
import org.koitharu.kotatsu.base.ui.BaseFragment
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.base.ui.list.SectionedSelectionController
import org.koitharu.kotatsu.base.ui.list.decor.AbstractSelectionItemDecoration
import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.base.ui.list.fastscroll.FastScroller
import org.koitharu.kotatsu.base.ui.util.ReversibleAction
import org.koitharu.kotatsu.bookmarks.data.ids import org.koitharu.kotatsu.bookmarks.data.ids
import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksGroupAdapter import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksGroupAdapter
import org.koitharu.kotatsu.bookmarks.ui.model.BookmarksGroup import org.koitharu.kotatsu.bookmarks.ui.model.BookmarksGroup
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
import org.koitharu.kotatsu.core.ui.BaseFragment
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.ui.list.SectionedSelectionController
import org.koitharu.kotatsu.core.ui.list.decor.AbstractSelectionItemDecoration
import org.koitharu.kotatsu.core.ui.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
import org.koitharu.kotatsu.core.ui.util.ReversibleAction
import org.koitharu.kotatsu.core.ui.util.reverseAsync
import org.koitharu.kotatsu.core.util.ext.invalidateNestedItemDecorations
import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf
import org.koitharu.kotatsu.databinding.FragmentListSimpleBinding import org.koitharu.kotatsu.databinding.FragmentListSimpleBinding
import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
@ -37,8 +39,6 @@ import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
import org.koitharu.kotatsu.main.ui.owners.SnackbarOwner import org.koitharu.kotatsu.main.ui.owners.SnackbarOwner
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.reader.ui.ReaderActivity import org.koitharu.kotatsu.reader.ui.ReaderActivity
import org.koitharu.kotatsu.utils.ext.invalidateNestedItemDecorations
import org.koitharu.kotatsu.utils.ext.scaleUpActivityOptionsOf
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
@ -56,12 +56,12 @@ class BookmarksFragment :
private var adapter: BookmarksGroupAdapter? = null private var adapter: BookmarksGroupAdapter? = null
private var selectionController: SectionedSelectionController<Manga>? = null private var selectionController: SectionedSelectionController<Manga>? = null
override fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): FragmentListSimpleBinding { override fun onCreateViewBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentListSimpleBinding {
return FragmentListSimpleBinding.inflate(inflater, container, false) return FragmentListSimpleBinding.inflate(inflater, container, false)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewBindingCreated(binding: FragmentListSimpleBinding, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewBindingCreated(binding, savedInstanceState)
selectionController = SectionedSelectionController( selectionController = SectionedSelectionController(
activity = requireActivity(), activity = requireActivity(),
owner = this, owner = this,
@ -77,7 +77,7 @@ class BookmarksFragment :
) )
binding.recyclerView.adapter = adapter binding.recyclerView.adapter = adapter
binding.recyclerView.setHasFixedSize(true) binding.recyclerView.setHasFixedSize(true)
val spacingDecoration = SpacingItemDecoration(view.resources.getDimensionPixelOffset(R.dimen.grid_spacing)) val spacingDecoration = SpacingItemDecoration(resources.getDimensionPixelOffset(R.dimen.grid_spacing))
binding.recyclerView.addItemDecoration(spacingDecoration) binding.recyclerView.addItemDecoration(spacingDecoration)
viewModel.content.observe(viewLifecycleOwner, ::onListChanged) viewModel.content.observe(viewLifecycleOwner, ::onListChanged)
@ -114,7 +114,7 @@ class BookmarksFragment :
override fun onFastScrollStop(fastScroller: FastScroller) = Unit override fun onFastScrollStop(fastScroller: FastScroller) = Unit
override fun onSelectionChanged(controller: SectionedSelectionController<Manga>, count: Int) { override fun onSelectionChanged(controller: SectionedSelectionController<Manga>, count: Int) {
binding.recyclerView.invalidateNestedItemDecorations() requireViewBinding().recyclerView.invalidateNestedItemDecorations()
} }
override fun onCreateActionMode( override fun onCreateActionMode(
@ -149,10 +149,10 @@ class BookmarksFragment :
): AbstractSelectionItemDecoration = BookmarksSelectionDecoration(requireContext()) ): AbstractSelectionItemDecoration = BookmarksSelectionDecoration(requireContext())
override fun onWindowInsetsChanged(insets: Insets) { override fun onWindowInsetsChanged(insets: Insets) {
binding.recyclerView.updatePadding( requireViewBinding().recyclerView.updatePadding(
bottom = insets.bottom, bottom = insets.bottom,
) )
binding.recyclerView.fastScroller.updateLayoutParams<ViewGroup.MarginLayoutParams> { requireViewBinding().recyclerView.fastScroller.updateLayoutParams<ViewGroup.MarginLayoutParams> {
bottomMargin = insets.bottom bottomMargin = insets.bottom
} }
} }

@ -4,8 +4,8 @@ import android.content.Context
import android.view.View import android.view.View
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.core.util.ext.getItem
import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration
import org.koitharu.kotatsu.utils.ext.getItem
class BookmarksSelectionDecoration(context: Context) : MangaSelectionDecoration(context) { class BookmarksSelectionDecoration(context: Context) : MangaSelectionDecoration(context) {
@ -14,5 +14,4 @@ class BookmarksSelectionDecoration(context: Context) : MangaSelectionDecoration(
val item = holder.getItem(Bookmark::class.java) ?: return RecyclerView.NO_ID val item = holder.getItem(Bookmark::class.java) ?: return RecyclerView.NO_ID
return item.pageId return item.pageId
} }
} }

@ -7,17 +7,17 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BaseViewModel
import org.koitharu.kotatsu.base.ui.util.ReversibleAction
import org.koitharu.kotatsu.bookmarks.domain.BookmarksRepository import org.koitharu.kotatsu.bookmarks.domain.BookmarksRepository
import org.koitharu.kotatsu.bookmarks.ui.model.BookmarksGroup import org.koitharu.kotatsu.bookmarks.ui.model.BookmarksGroup
import org.koitharu.kotatsu.core.ui.BaseViewModel
import org.koitharu.kotatsu.core.ui.util.ReversibleAction
import org.koitharu.kotatsu.core.util.SingleLiveEvent
import org.koitharu.kotatsu.core.util.asFlowLiveData
import org.koitharu.kotatsu.list.ui.model.EmptyState import org.koitharu.kotatsu.list.ui.model.EmptyState
import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.model.LoadingState import org.koitharu.kotatsu.list.ui.model.LoadingState
import org.koitharu.kotatsu.list.ui.model.toErrorState import org.koitharu.kotatsu.list.ui.model.toErrorState
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.utils.SingleLiveEvent
import org.koitharu.kotatsu.utils.asFlowLiveData
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel

@ -4,16 +4,16 @@ import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.list.AdapterDelegateClickListenerAdapter
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver
import org.koitharu.kotatsu.core.ui.list.AdapterDelegateClickListenerAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.util.ext.decodeRegion
import org.koitharu.kotatsu.core.util.ext.disposeImageRequest
import org.koitharu.kotatsu.core.util.ext.enqueueWith
import org.koitharu.kotatsu.core.util.ext.newImageRequest
import org.koitharu.kotatsu.core.util.ext.source
import org.koitharu.kotatsu.databinding.ItemBookmarkBinding import org.koitharu.kotatsu.databinding.ItemBookmarkBinding
import org.koitharu.kotatsu.utils.ext.decodeRegion
import org.koitharu.kotatsu.utils.ext.disposeImageRequest
import org.koitharu.kotatsu.utils.ext.enqueueWith
import org.koitharu.kotatsu.utils.ext.newImageRequest
import org.koitharu.kotatsu.utils.ext.source
import org.koitharu.kotatsu.utils.image.CoverSizeResolver
fun bookmarkListAD( fun bookmarkListAD(
coil: ImageLoader, coil: ImageLoader,

@ -4,8 +4,8 @@ import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import coil.ImageLoader import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
class BookmarksAdapter( class BookmarksAdapter(
coil: ImageLoader, coil: ImageLoader,
@ -13,7 +13,7 @@ class BookmarksAdapter(
clickListener: OnListItemClickListener<Bookmark>, clickListener: OnListItemClickListener<Bookmark>,
) : AsyncListDifferDelegationAdapter<Bookmark>( ) : AsyncListDifferDelegationAdapter<Bookmark>(
DiffCallback(), DiffCallback(),
bookmarkListAD(coil, lifecycleOwner, clickListener) bookmarkListAD(coil, lifecycleOwner, clickListener),
) { ) {
private class DiffCallback : DiffUtil.ItemCallback<Bookmark>() { private class DiffCallback : DiffUtil.ItemCallback<Bookmark>() {

@ -6,20 +6,20 @@ import androidx.recyclerview.widget.RecyclerView
import coil.ImageLoader import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.base.ui.list.SectionedSelectionController
import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.bookmarks.ui.model.BookmarksGroup import org.koitharu.kotatsu.bookmarks.ui.model.BookmarksGroup
import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.ui.list.SectionedSelectionController
import org.koitharu.kotatsu.core.ui.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.core.util.ext.clearItemDecorations
import org.koitharu.kotatsu.core.util.ext.disposeImageRequest
import org.koitharu.kotatsu.core.util.ext.enqueueWith
import org.koitharu.kotatsu.core.util.ext.newImageRequest
import org.koitharu.kotatsu.core.util.ext.source
import org.koitharu.kotatsu.databinding.ItemBookmarksGroupBinding import org.koitharu.kotatsu.databinding.ItemBookmarksGroupBinding
import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.utils.ext.clearItemDecorations
import org.koitharu.kotatsu.utils.ext.disposeImageRequest
import org.koitharu.kotatsu.utils.ext.enqueueWith
import org.koitharu.kotatsu.utils.ext.newImageRequest
import org.koitharu.kotatsu.utils.ext.source
import org.koitharu.kotatsu.utils.image.CoverSizeResolver
fun bookmarksGroupAD( fun bookmarksGroupAD(
coil: ImageLoader, coil: ImageLoader,

@ -5,10 +5,10 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import coil.ImageLoader import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.base.ui.list.SectionedSelectionController
import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.bookmarks.ui.model.BookmarksGroup import org.koitharu.kotatsu.bookmarks.ui.model.BookmarksGroup
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.ui.list.SectionedSelectionController
import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD import org.koitharu.kotatsu.list.ui.adapter.emptyStateListAD
import org.koitharu.kotatsu.list.ui.adapter.errorStateListAD import org.koitharu.kotatsu.list.ui.adapter.errorStateListAD

@ -12,10 +12,10 @@ import androidx.core.graphics.Insets
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BaseActivity
import org.koitharu.kotatsu.core.network.CommonHeadersInterceptor import org.koitharu.kotatsu.core.network.CommonHeadersInterceptor
import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.core.util.ext.catchingWebViewUnavailability
import org.koitharu.kotatsu.databinding.ActivityBrowserBinding import org.koitharu.kotatsu.databinding.ActivityBrowserBinding
import org.koitharu.kotatsu.utils.ext.catchingWebViewUnavailability
import com.google.android.material.R as materialR import com.google.android.material.R as materialR
@SuppressLint("SetJavaScriptEnabled") @SuppressLint("SetJavaScriptEnabled")
@ -32,13 +32,13 @@ class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback
setDisplayHomeAsUpEnabled(true) setDisplayHomeAsUpEnabled(true)
setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material) setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material)
} }
with(binding.webView.settings) { with(viewBinding.webView.settings) {
javaScriptEnabled = true javaScriptEnabled = true
userAgentString = CommonHeadersInterceptor.userAgentChrome userAgentString = CommonHeadersInterceptor.userAgentChrome
} }
binding.webView.webViewClient = BrowserClient(this) viewBinding.webView.webViewClient = BrowserClient(this)
binding.webView.webChromeClient = ProgressChromeClient(binding.progressBar) viewBinding.webView.webChromeClient = ProgressChromeClient(viewBinding.progressBar)
onBackPressedCallback = WebViewBackPressedCallback(binding.webView) onBackPressedCallback = WebViewBackPressedCallback(viewBinding.webView)
onBackPressedDispatcher.addCallback(onBackPressedCallback) onBackPressedDispatcher.addCallback(onBackPressedCallback)
if (savedInstanceState != null) { if (savedInstanceState != null) {
return return
@ -51,18 +51,18 @@ class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback
intent?.getStringExtra(EXTRA_TITLE) ?: getString(R.string.loading_), intent?.getStringExtra(EXTRA_TITLE) ?: getString(R.string.loading_),
url, url,
) )
binding.webView.loadUrl(url) viewBinding.webView.loadUrl(url)
} }
} }
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
binding.webView.saveState(outState) viewBinding.webView.saveState(outState)
} }
override fun onRestoreInstanceState(savedInstanceState: Bundle) { override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState) super.onRestoreInstanceState(savedInstanceState)
binding.webView.restoreState(savedInstanceState) viewBinding.webView.restoreState(savedInstanceState)
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
@ -73,14 +73,14 @@ class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback
override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) {
android.R.id.home -> { android.R.id.home -> {
binding.webView.stopLoading() viewBinding.webView.stopLoading()
finishAfterTransition() finishAfterTransition()
true true
} }
R.id.action_browser -> { R.id.action_browser -> {
val intent = Intent(Intent.ACTION_VIEW) val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse(binding.webView.url) intent.data = Uri.parse(viewBinding.webView.url)
try { try {
startActivity(Intent.createChooser(intent, item.title)) startActivity(Intent.createChooser(intent, item.title))
} catch (_: ActivityNotFoundException) { } catch (_: ActivityNotFoundException) {
@ -92,22 +92,22 @@ class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback
} }
override fun onPause() { override fun onPause() {
binding.webView.onPause() viewBinding.webView.onPause()
super.onPause() super.onPause()
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
binding.webView.onResume() viewBinding.webView.onResume()
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
binding.webView.destroy() viewBinding.webView.destroy()
} }
override fun onLoadingStateChanged(isLoading: Boolean) { override fun onLoadingStateChanged(isLoading: Boolean) {
binding.progressBar.isVisible = isLoading viewBinding.progressBar.isVisible = isLoading
} }
override fun onTitleChanged(title: CharSequence, subtitle: CharSequence?) { override fun onTitleChanged(title: CharSequence, subtitle: CharSequence?) {
@ -120,10 +120,10 @@ class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback
} }
override fun onWindowInsetsChanged(insets: Insets) { override fun onWindowInsetsChanged(insets: Insets) {
binding.appbar.updatePadding( viewBinding.appbar.updatePadding(
top = insets.top, top = insets.top,
) )
binding.root.updatePadding( viewBinding.root.updatePadding(
left = insets.left, left = insets.left,
right = insets.right, right = insets.right,
bottom = insets.bottom, bottom = insets.bottom,

@ -1,10 +1,8 @@
package org.koitharu.kotatsu.browser.cloudflare package org.koitharu.kotatsu.browser.cloudflare
import android.annotation.SuppressLint
import android.content.DialogInterface import android.content.DialogInterface
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.webkit.CookieManager import android.webkit.CookieManager
import android.webkit.WebSettings import android.webkit.WebSettings
@ -14,13 +12,13 @@ import androidx.fragment.app.setFragmentResult
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import okhttp3.Headers import okhttp3.Headers
import org.koitharu.kotatsu.base.ui.AlertDialogFragment
import org.koitharu.kotatsu.browser.WebViewBackPressedCallback import org.koitharu.kotatsu.browser.WebViewBackPressedCallback
import org.koitharu.kotatsu.core.network.CommonHeaders 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.core.ui.AlertDialogFragment
import org.koitharu.kotatsu.core.util.ext.withArgs
import org.koitharu.kotatsu.databinding.FragmentCloudflareBinding import org.koitharu.kotatsu.databinding.FragmentCloudflareBinding
import org.koitharu.kotatsu.utils.ext.withArgs
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
@ -39,14 +37,13 @@ class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), Cloud
url = requireArguments().getString(ARG_URL).orEmpty() url = requireArguments().getString(ARG_URL).orEmpty()
} }
override fun onInflateView( override fun onCreateViewBinding(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
) = FragmentCloudflareBinding.inflate(inflater, container, false) ) = FragmentCloudflareBinding.inflate(inflater, container, false)
@SuppressLint("SetJavaScriptEnabled") override fun onViewBindingCreated(binding: FragmentCloudflareBinding, savedInstanceState: Bundle?) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewBindingCreated(binding, savedInstanceState)
super.onViewCreated(view, savedInstanceState)
with(binding.webView.settings) { with(binding.webView.settings) {
javaScriptEnabled = true javaScriptEnabled = true
cacheMode = WebSettings.LOAD_DEFAULT cacheMode = WebSettings.LOAD_DEFAULT
@ -64,8 +61,8 @@ class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), Cloud
} }
override fun onDestroyView() { override fun onDestroyView() {
binding.webView.stopLoading() requireViewBinding().webView.stopLoading()
binding.webView.destroy() requireViewBinding().webView.destroy()
onBackPressedCallback = null onBackPressedCallback = null
super.onDestroyView() super.onDestroyView()
} }
@ -76,18 +73,18 @@ class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), Cloud
override fun onDialogCreated(dialog: AlertDialog) { override fun onDialogCreated(dialog: AlertDialog) {
super.onDialogCreated(dialog) super.onDialogCreated(dialog)
onBackPressedCallback = WebViewBackPressedCallback(binding.webView).also { onBackPressedCallback = WebViewBackPressedCallback(requireViewBinding().webView).also {
dialog.onBackPressedDispatcher.addCallback(it) dialog.onBackPressedDispatcher.addCallback(it)
} }
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
binding.webView.onResume() requireViewBinding().webView.onResume()
} }
override fun onPause() { override fun onPause() {
binding.webView.onPause() requireViewBinding().webView.onPause()
super.onPause() super.onPause()
} }
@ -97,7 +94,7 @@ class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), Cloud
} }
override fun onPageLoaded() { override fun onPageLoaded() {
bindingOrNull()?.progressBar?.isInvisible = true viewBinding?.progressBar?.isInvisible = true
} }
override fun onCheckPassed() { override fun onCheckPassed() {

@ -26,7 +26,6 @@ import kotlinx.coroutines.flow.asSharedFlow
import okhttp3.CookieJar import okhttp3.CookieJar
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.base.ui.util.ActivityRecreationHandle
import org.koitharu.kotatsu.core.cache.ContentCache import org.koitharu.kotatsu.core.cache.ContentCache
import org.koitharu.kotatsu.core.cache.MemoryContentCache import org.koitharu.kotatsu.core.cache.MemoryContentCache
import org.koitharu.kotatsu.core.cache.StubContentCache import org.koitharu.kotatsu.core.cache.StubContentCache
@ -41,6 +40,12 @@ import org.koitharu.kotatsu.core.parser.MangaLoaderContextImpl
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.favicon.FaviconFetcher import org.koitharu.kotatsu.core.parser.favicon.FaviconFetcher
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.image.CoilImageGetter
import org.koitharu.kotatsu.core.ui.util.ActivityRecreationHandle
import org.koitharu.kotatsu.core.util.IncognitoModeIndicator
import org.koitharu.kotatsu.core.util.ext.activityManager
import org.koitharu.kotatsu.core.util.ext.connectivityManager
import org.koitharu.kotatsu.core.util.ext.isLowRamDevice
import org.koitharu.kotatsu.local.data.CacheDir import org.koitharu.kotatsu.local.data.CacheDir
import org.koitharu.kotatsu.local.data.CbzFetcher import org.koitharu.kotatsu.local.data.CbzFetcher
import org.koitharu.kotatsu.local.data.LocalManga import org.koitharu.kotatsu.local.data.LocalManga
@ -53,11 +58,6 @@ import org.koitharu.kotatsu.reader.ui.thumbnails.MangaPageFetcher
import org.koitharu.kotatsu.search.ui.MangaSuggestionsProvider import org.koitharu.kotatsu.search.ui.MangaSuggestionsProvider
import org.koitharu.kotatsu.settings.backup.BackupObserver import org.koitharu.kotatsu.settings.backup.BackupObserver
import org.koitharu.kotatsu.sync.domain.SyncController import org.koitharu.kotatsu.sync.domain.SyncController
import org.koitharu.kotatsu.utils.IncognitoModeIndicator
import org.koitharu.kotatsu.utils.ext.activityManager
import org.koitharu.kotatsu.utils.ext.connectivityManager
import org.koitharu.kotatsu.utils.ext.isLowRamDevice
import org.koitharu.kotatsu.utils.image.CoilImageGetter
import org.koitharu.kotatsu.widget.WidgetUpdater import org.koitharu.kotatsu.widget.WidgetUpdater
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Singleton import javax.inject.Singleton
@ -159,7 +159,7 @@ interface AppModule {
.transformationDispatcher(Dispatchers.Default) .transformationDispatcher(Dispatchers.Default)
.diskCache(diskCacheFactory) .diskCache(diskCacheFactory)
.logger(if (BuildConfig.DEBUG) DebugLogger() else null) .logger(if (BuildConfig.DEBUG) DebugLogger() else null)
.allowRgb565(isLowRamDevice(context)) .allowRgb565(context.isLowRamDevice())
.components( .components(
ComponentRegistry.Builder() ComponentRegistry.Builder()
.add(SvgDecoder.Factory()) .add(SvgDecoder.Factory())

@ -7,7 +7,7 @@ import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.parsers.util.json.JSONIterator import org.koitharu.kotatsu.parsers.util.json.JSONIterator
import org.koitharu.kotatsu.parsers.util.json.mapJSON import org.koitharu.kotatsu.parsers.util.json.mapJSON
import org.koitharu.kotatsu.utils.ext.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import javax.inject.Inject import javax.inject.Inject
private const val PAGE_SIZE = 10 private const val PAGE_SIZE = 10

@ -5,10 +5,11 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runInterruptible import kotlinx.coroutines.runInterruptible
import okio.Closeable import okio.Closeable
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.util.ext.format
import org.koitharu.kotatsu.core.zip.ZipOutput import org.koitharu.kotatsu.core.zip.ZipOutput
import org.koitharu.kotatsu.utils.ext.format
import java.io.File import java.io.File
import java.util.* import java.util.Date
import java.util.Locale
import java.util.zip.Deflater import java.util.zip.Deflater
class BackupZipOutput(val file: File) : Closeable { class BackupZipOutput(val file: File) : Closeable {

@ -33,6 +33,7 @@ import org.koitharu.kotatsu.core.db.migrations.Migration6To7
import org.koitharu.kotatsu.core.db.migrations.Migration7To8 import org.koitharu.kotatsu.core.db.migrations.Migration7To8
import org.koitharu.kotatsu.core.db.migrations.Migration8To9 import org.koitharu.kotatsu.core.db.migrations.Migration8To9
import org.koitharu.kotatsu.core.db.migrations.Migration9To10 import org.koitharu.kotatsu.core.db.migrations.Migration9To10
import org.koitharu.kotatsu.core.util.ext.processLifecycleScope
import org.koitharu.kotatsu.favourites.data.FavouriteCategoriesDao import org.koitharu.kotatsu.favourites.data.FavouriteCategoriesDao
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
import org.koitharu.kotatsu.favourites.data.FavouriteEntity import org.koitharu.kotatsu.favourites.data.FavouriteEntity
@ -46,7 +47,6 @@ import org.koitharu.kotatsu.suggestions.data.SuggestionEntity
import org.koitharu.kotatsu.tracker.data.TrackEntity import org.koitharu.kotatsu.tracker.data.TrackEntity
import org.koitharu.kotatsu.tracker.data.TrackLogEntity import org.koitharu.kotatsu.tracker.data.TrackLogEntity
import org.koitharu.kotatsu.tracker.data.TracksDao import org.koitharu.kotatsu.tracker.data.TracksDao
import org.koitharu.kotatsu.utils.ext.processLifecycleScope
const val DATABASE_VERSION = 15 const val DATABASE_VERSION = 15

@ -1,13 +1,13 @@
package org.koitharu.kotatsu.core.db.entity package org.koitharu.kotatsu.core.db.entity
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.util.ext.longHashCode
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaState import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.mapToSet import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.toTitleCase import org.koitharu.kotatsu.parsers.util.toTitleCase
import org.koitharu.kotatsu.utils.ext.longHashCode
// Entity to model // Entity to model

@ -6,9 +6,9 @@ import androidx.core.util.Consumer
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.ErrorDetailsDialog import org.koitharu.kotatsu.core.ui.dialog.ErrorDetailsDialog
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
import org.koitharu.kotatsu.parsers.exception.ParseException import org.koitharu.kotatsu.parsers.exception.ParseException
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
class DialogErrorObserver( class DialogErrorObserver(
host: View, host: View,

@ -11,8 +11,8 @@ import androidx.lifecycle.Observer
import androidx.lifecycle.coroutineScope import androidx.lifecycle.coroutineScope
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koitharu.kotatsu.utils.ext.findActivity import org.koitharu.kotatsu.core.util.ext.findActivity
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope
abstract class ErrorObserver( abstract class ErrorObserver(
protected val host: View, protected val host: View,

@ -12,13 +12,13 @@ import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.browser.BrowserActivity import org.koitharu.kotatsu.browser.BrowserActivity
import org.koitharu.kotatsu.browser.cloudflare.CloudFlareDialog import org.koitharu.kotatsu.browser.cloudflare.CloudFlareDialog
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
import org.koitharu.kotatsu.core.ui.ErrorDetailsDialog import org.koitharu.kotatsu.core.ui.dialog.ErrorDetailsDialog
import org.koitharu.kotatsu.core.util.TaggedActivityResult
import org.koitharu.kotatsu.core.util.isSuccess
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
import org.koitharu.kotatsu.parsers.exception.NotFoundException import org.koitharu.kotatsu.parsers.exception.NotFoundException
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity import org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity
import org.koitharu.kotatsu.utils.TaggedActivityResult
import org.koitharu.kotatsu.utils.isSuccess
import kotlin.coroutines.Continuation import kotlin.coroutines.Continuation
import kotlin.coroutines.resume import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine import kotlin.coroutines.suspendCoroutine

@ -5,10 +5,10 @@ import androidx.core.util.Consumer
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.ErrorDetailsDialog import org.koitharu.kotatsu.core.ui.dialog.ErrorDetailsDialog
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner
import org.koitharu.kotatsu.parsers.exception.ParseException import org.koitharu.kotatsu.parsers.exception.ParseException
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
class SnackbarErrorObserver( class SnackbarErrorObserver(
host: View, host: View,

@ -14,13 +14,13 @@ import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.ext.asArrayList
import org.koitharu.kotatsu.parsers.util.await import org.koitharu.kotatsu.parsers.util.await
import org.koitharu.kotatsu.parsers.util.byte2HexFormatted import org.koitharu.kotatsu.parsers.util.byte2HexFormatted
import org.koitharu.kotatsu.parsers.util.json.mapJSONNotNull import org.koitharu.kotatsu.parsers.util.json.mapJSONNotNull
import org.koitharu.kotatsu.parsers.util.parseJsonArray import org.koitharu.kotatsu.parsers.util.parseJsonArray
import org.koitharu.kotatsu.utils.ext.asArrayList import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug import org.koitharu.kotatsu.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.utils.ext.runCatchingCancellable
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.InputStream import java.io.InputStream
import java.security.MessageDigest import java.security.MessageDigest

@ -14,10 +14,10 @@ import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.processLifecycleScope
import org.koitharu.kotatsu.utils.ext.processLifecycleScope import org.koitharu.kotatsu.core.util.ext.subdir
import org.koitharu.kotatsu.utils.ext.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.utils.ext.subdir import org.koitharu.kotatsu.util.ext.printStackTraceDebug
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.text.SimpleDateFormat import java.text.SimpleDateFormat

@ -1,11 +1,11 @@
package org.koitharu.kotatsu.core.model package org.koitharu.kotatsu.core.model
import androidx.core.os.LocaleListCompat import androidx.core.os.LocaleListCompat
import org.koitharu.kotatsu.core.util.ext.iterator
import org.koitharu.kotatsu.details.ui.model.ChapterListItem import org.koitharu.kotatsu.details.ui.model.ChapterListItem
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.util.mapToSet import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.utils.ext.iterator
fun Collection<Manga>.ids() = mapToSet { it.id } fun Collection<Manga>.ids() = mapToSet { it.id }

@ -2,12 +2,12 @@ package org.koitharu.kotatsu.core.model.parcelable
import android.os.Parcel import android.os.Parcel
import androidx.core.os.ParcelCompat import androidx.core.os.ParcelCompat
import org.koitharu.kotatsu.core.util.ext.readParcelableCompat
import org.koitharu.kotatsu.core.util.ext.readSerializableCompat
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.utils.ext.readParcelableCompat
import org.koitharu.kotatsu.utils.ext.readSerializableCompat
fun Manga.writeToParcel(out: Parcel, flags: Int, withChapters: Boolean) { fun Manga.writeToParcel(out: Parcel, flags: Int, withChapters: Boolean) {
out.writeLong(id) out.writeLong(id)

@ -2,15 +2,15 @@ package org.koitharu.kotatsu.core.model.parcelable
import android.os.Parcel import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import org.koitharu.kotatsu.core.util.ext.Set
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.utils.ext.Set
class ParcelableMangaTags( class ParcelableMangaTags(
val tags: Set<MangaTag>, val tags: Set<MangaTag>,
) : Parcelable { ) : Parcelable {
constructor(parcel: Parcel) : this( constructor(parcel: Parcel) : this(
Set(parcel.readInt()) { parcel.readMangaTag() } Set(parcel.readInt()) { parcel.readMangaTag() },
) )
override fun writeToParcel(parcel: Parcel, flags: Int) { override fun writeToParcel(parcel: Parcel, flags: Int) {

@ -12,7 +12,7 @@ import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.mergeWith import org.koitharu.kotatsu.parsers.util.mergeWith
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug import org.koitharu.kotatsu.util.ext.printStackTraceDebug
import java.net.IDN import java.net.IDN
import java.util.Locale import java.util.Locale
import javax.inject.Inject import javax.inject.Inject

@ -6,7 +6,7 @@ import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.dnsoverhttps.DnsOverHttps import okhttp3.dnsoverhttps.DnsOverHttps
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug import org.koitharu.kotatsu.util.ext.printStackTraceDebug
import java.net.InetAddress import java.net.InetAddress
import java.net.UnknownHostException import java.net.UnknownHostException
@ -52,8 +52,9 @@ class DoHManager(
tryGetByIp("8.8.8.8"), tryGetByIp("8.8.8.8"),
tryGetByIp("2001:4860:4860::8888"), tryGetByIp("2001:4860:4860::8888"),
tryGetByIp("2001:4860:4860::8844"), tryGetByIp("2001:4860:4860::8844"),
) ),
).build() ).build()
DoHProvider.CLOUDFLARE -> DnsOverHttps.Builder().client(bootstrapClient) DoHProvider.CLOUDFLARE -> DnsOverHttps.Builder().client(bootstrapClient)
.url("https://cloudflare-dns.com/dns-query".toHttpUrl()) .url("https://cloudflare-dns.com/dns-query".toHttpUrl())
.resolvePrivateAddresses(true) .resolvePrivateAddresses(true)
@ -68,8 +69,9 @@ class DoHManager(
tryGetByIp("2606:4700:4700::1001"), tryGetByIp("2606:4700:4700::1001"),
tryGetByIp("2606:4700:4700::0064"), tryGetByIp("2606:4700:4700::0064"),
tryGetByIp("2606:4700:4700::6400"), tryGetByIp("2606:4700:4700::6400"),
) ),
).build() ).build()
DoHProvider.ADGUARD -> DnsOverHttps.Builder().client(bootstrapClient) DoHProvider.ADGUARD -> DnsOverHttps.Builder().client(bootstrapClient)
.url("https://dns-unfiltered.adguard.com/dns-query".toHttpUrl()) .url("https://dns-unfiltered.adguard.com/dns-query".toHttpUrl())
.resolvePrivateAddresses(true) .resolvePrivateAddresses(true)
@ -79,7 +81,7 @@ class DoHManager(
tryGetByIp("94.140.14.141"), tryGetByIp("94.140.14.141"),
tryGetByIp("2a10:50c0::1:ff"), tryGetByIp("2a10:50c0::1:ff"),
tryGetByIp("2a10:50c0::2:ff"), tryGetByIp("2a10:50c0::2:ff"),
) ),
).build() ).build()
} }

@ -2,7 +2,7 @@ package org.koitharu.kotatsu.core.network
import android.annotation.SuppressLint import android.annotation.SuppressLint
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug import org.koitharu.kotatsu.util.ext.printStackTraceDebug
import java.security.SecureRandom import java.security.SecureRandom
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import javax.net.ssl.SSLContext import javax.net.ssl.SSLContext

@ -8,7 +8,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import okhttp3.Cookie import okhttp3.Cookie
import okhttp3.HttpUrl import okhttp3.HttpUrl
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug import org.koitharu.kotatsu.util.ext.printStackTraceDebug
private const val PREFS_NAME = "cookies" private const val PREFS_NAME = "cookies"

@ -6,8 +6,8 @@ import android.net.Network
import android.net.NetworkCapabilities import android.net.NetworkCapabilities
import android.net.NetworkRequest import android.net.NetworkRequest
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import org.koitharu.kotatsu.utils.MediatorStateFlow import org.koitharu.kotatsu.core.util.MediatorStateFlow
import org.koitharu.kotatsu.utils.ext.isOnline import org.koitharu.kotatsu.core.util.ext.isOnline
class NetworkState( class NetworkState(
private val connectivityManager: ConnectivityManager, private val connectivityManager: ConnectivityManager,

@ -22,16 +22,16 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.domain.MangaDataRepository
import org.koitharu.kotatsu.core.db.TABLE_HISTORY import org.koitharu.kotatsu.core.db.TABLE_HISTORY
import org.koitharu.kotatsu.core.parser.MangaDataRepository
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.ext.getDrawableOrThrow
import org.koitharu.kotatsu.core.util.ext.processLifecycleScope
import org.koitharu.kotatsu.history.domain.HistoryRepository import org.koitharu.kotatsu.history.domain.HistoryRepository
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.reader.ui.ReaderActivity import org.koitharu.kotatsu.reader.ui.ReaderActivity
import org.koitharu.kotatsu.utils.ext.getDrawableOrThrow import org.koitharu.kotatsu.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
import org.koitharu.kotatsu.utils.ext.processLifecycleScope
import org.koitharu.kotatsu.utils.ext.runCatchingCancellable
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.utils package org.koitharu.kotatsu.core.os
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.domain package org.koitharu.kotatsu.core.parser
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
@ -19,7 +19,6 @@ import org.koitharu.kotatsu.core.db.entity.toEntity
import org.koitharu.kotatsu.core.db.entity.toManga import org.koitharu.kotatsu.core.db.entity.toManga
import org.koitharu.kotatsu.core.db.entity.toMangaTags import org.koitharu.kotatsu.core.db.entity.toMangaTags
import org.koitharu.kotatsu.core.network.CommonHeaders import org.koitharu.kotatsu.core.network.CommonHeaders
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.prefs.ReaderMode import org.koitharu.kotatsu.core.prefs.ReaderMode
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.model.MangaPage
@ -33,8 +32,6 @@ import java.util.zip.ZipFile
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.roundToInt import kotlin.math.roundToInt
private const val MIN_WEBTOON_RATIO = 2
@Reusable @Reusable
class MangaDataRepository @Inject constructor( class MangaDataRepository @Inject constructor(
private val okHttpClient: OkHttpClient, private val okHttpClient: OkHttpClient,
@ -148,6 +145,8 @@ class MangaDataRepository @Inject constructor(
companion object { companion object {
private const val MIN_WEBTOON_RATIO = 2
suspend fun getImageMimeType(file: File): String? = runInterruptible(Dispatchers.IO) { suspend fun getImageMimeType(file: File): String? = runInterruptible(Dispatchers.IO) {
val options = BitmapFactory.Options().apply { val options = BitmapFactory.Options().apply {
inJustDecodeBounds = true inJustDecodeBounds = true

@ -1,14 +1,14 @@
package org.koitharu.kotatsu.base.domain package org.koitharu.kotatsu.core.parser
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.SavedStateHandle
import org.koitharu.kotatsu.base.ui.BaseActivity
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.core.util.ext.getParcelableCompat
import org.koitharu.kotatsu.core.util.ext.getParcelableExtraCompat
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.utils.ext.getParcelableCompat
import org.koitharu.kotatsu.utils.ext.getParcelableExtraCompat
class MangaIntent private constructor( class MangaIntent private constructor(
@JvmField val manga: Manga?, @JvmField val manga: Manga?,

@ -11,10 +11,10 @@ import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
import org.koitharu.kotatsu.core.prefs.SourceSettings import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.core.util.ext.toList
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.utils.ext.toList
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject

@ -14,6 +14,7 @@ import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.cache.ContentCache import org.koitharu.kotatsu.core.cache.ContentCache
import org.koitharu.kotatsu.core.cache.SafeDeferred import org.koitharu.kotatsu.core.cache.SafeDeferred
import org.koitharu.kotatsu.core.prefs.SourceSettings import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.core.util.ext.processLifecycleScope
import org.koitharu.kotatsu.parsers.MangaParser import org.koitharu.kotatsu.parsers.MangaParser
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
@ -25,8 +26,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.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.domain import org.koitharu.kotatsu.parsers.util.domain
import org.koitharu.kotatsu.utils.ext.processLifecycleScope import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.utils.ext.runCatchingCancellable
class RemoteMangaRepository( class RemoteMangaRepository(
private val parser: MangaParser, private val parser: MangaParser,

@ -14,16 +14,16 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.model.ZoomMode import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.core.network.DoHProvider import org.koitharu.kotatsu.core.network.DoHProvider
import org.koitharu.kotatsu.core.util.ext.connectivityManager
import org.koitharu.kotatsu.core.util.ext.filterToSet
import org.koitharu.kotatsu.core.util.ext.getEnumValue
import org.koitharu.kotatsu.core.util.ext.observe
import org.koitharu.kotatsu.core.util.ext.putEnumValue
import org.koitharu.kotatsu.core.util.ext.toUriOrNull
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.mapToSet import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.shelf.domain.ShelfSection import org.koitharu.kotatsu.shelf.domain.ShelfSection
import org.koitharu.kotatsu.utils.ext.connectivityManager
import org.koitharu.kotatsu.utils.ext.filterToSet
import org.koitharu.kotatsu.utils.ext.getEnumValue
import org.koitharu.kotatsu.utils.ext.observe
import org.koitharu.kotatsu.utils.ext.putEnumValue
import org.koitharu.kotatsu.utils.ext.toUriOrNull
import java.io.File import java.io.File
import java.util.Collections import java.util.Collections
import java.util.EnumSet import java.util.EnumSet

@ -2,13 +2,13 @@ package org.koitharu.kotatsu.core.prefs
import android.content.Context import android.content.Context
import androidx.core.content.edit import androidx.core.content.edit
import org.koitharu.kotatsu.core.util.ext.getEnumValue
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
import org.koitharu.kotatsu.core.util.ext.putEnumValue
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.utils.ext.getEnumValue
import org.koitharu.kotatsu.utils.ext.ifNullOrEmpty
import org.koitharu.kotatsu.utils.ext.putEnumValue
private const val KEY_SORT_ORDER = "sort_order" private const val KEY_SORT_ORDER = "sort_order"

@ -1,8 +1,9 @@
package org.koitharu.kotatsu.base.ui package org.koitharu.kotatsu.core.ui
import android.app.Dialog import android.app.Dialog
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
@ -12,13 +13,15 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
abstract class AlertDialogFragment<B : ViewBinding> : DialogFragment() { abstract class AlertDialogFragment<B : ViewBinding> : DialogFragment() {
private var viewBinding: B? = null var viewBinding: B? = null
private set
@Deprecated("", ReplaceWith("requireViewBinding()"))
protected val binding: B protected val binding: B
get() = checkNotNull(viewBinding) get() = requireViewBinding()
final override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { final override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val binding = onInflateView(layoutInflater, null) val binding = onCreateViewBinding(layoutInflater, null)
viewBinding = binding viewBinding = binding
return MaterialAlertDialogBuilder(requireContext(), theme) return MaterialAlertDialogBuilder(requireContext(), theme)
.setView(binding.root) .setView(binding.root)
@ -32,6 +35,11 @@ abstract class AlertDialogFragment<B : ViewBinding> : DialogFragment() {
savedInstanceState: Bundle?, savedInstanceState: Bundle?,
) = viewBinding?.root ) = viewBinding?.root
final override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
onViewBindingCreated(requireViewBinding(), savedInstanceState)
}
@CallSuper @CallSuper
override fun onDestroyView() { override fun onDestroyView() {
viewBinding = null viewBinding = null
@ -42,7 +50,14 @@ abstract class AlertDialogFragment<B : ViewBinding> : DialogFragment() {
open fun onDialogCreated(dialog: AlertDialog) = Unit open fun onDialogCreated(dialog: AlertDialog) = Unit
protected fun bindingOrNull(): B? = viewBinding @Deprecated("", ReplaceWith("viewBinding"))
protected fun bindingOrNull() = viewBinding
fun requireViewBinding(): B = checkNotNull(viewBinding) {
"Fragment $this did not return a ViewBinding from onCreateView() or this was called before onCreateView()."
}
protected abstract fun onCreateViewBinding(inflater: LayoutInflater, container: ViewGroup?): B
protected abstract fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): B protected open fun onViewBindingCreated(binding: B, savedInstanceState: Bundle?) = Unit
} }

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui package org.koitharu.kotatsu.core.ui
import android.content.Intent import android.content.Intent
import android.content.res.Configuration import android.content.res.Configuration
@ -25,11 +25,11 @@ import androidx.viewbinding.ViewBinding
import dagger.hilt.android.EntryPointAccessors import dagger.hilt.android.EntryPointAccessors
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.util.ActionModeDelegate
import org.koitharu.kotatsu.base.ui.util.BaseActivityEntryPoint
import org.koitharu.kotatsu.base.ui.util.WindowInsetsDelegate
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.utils.ext.getThemeColor import org.koitharu.kotatsu.core.ui.util.ActionModeDelegate
import org.koitharu.kotatsu.core.ui.util.BaseActivityEntryPoint
import org.koitharu.kotatsu.core.ui.util.WindowInsetsDelegate
import org.koitharu.kotatsu.core.util.ext.getThemeColor
@Suppress("LeakingThis") @Suppress("LeakingThis")
abstract class BaseActivity<B : ViewBinding> : abstract class BaseActivity<B : ViewBinding> :
@ -38,7 +38,7 @@ abstract class BaseActivity<B : ViewBinding> :
private var isAmoledTheme = false private var isAmoledTheme = false
protected lateinit var binding: B lateinit var viewBinding: B
private set private set
@JvmField @JvmField
@ -88,7 +88,7 @@ abstract class BaseActivity<B : ViewBinding> :
} }
protected fun setContentView(binding: B) { protected fun setContentView(binding: B) {
this.binding = binding this.viewBinding = binding
super.setContentView(binding.root) super.setContentView(binding.root)
val toolbar = (binding.root.findViewById<View>(R.id.toolbar) as? Toolbar) val toolbar = (binding.root.findViewById<View>(R.id.toolbar) as? Toolbar)
toolbar?.let(this::setSupportActionBar) toolbar?.let(this::setSupportActionBar)
@ -131,7 +131,7 @@ abstract class BaseActivity<B : ViewBinding> :
} else { } else {
ContextCompat.getColor(this, R.color.kotatsu_secondaryContainer) ContextCompat.getColor(this, R.color.kotatsu_secondaryContainer)
} }
val insets = ViewCompat.getRootWindowInsets(binding.root) val insets = ViewCompat.getRootWindowInsets(viewBinding.root)
?.getInsets(WindowInsetsCompat.Type.systemBars()) ?: return ?.getInsets(WindowInsetsCompat.Type.systemBars()) ?: return
findViewById<ActionBarContextView?>(androidx.appcompat.R.id.action_mode_bar).apply { findViewById<ActionBarContextView?>(androidx.appcompat.R.id.action_mode_bar).apply {
setBackgroundColor(actionModeColor) setBackgroundColor(actionModeColor)

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui package org.koitharu.kotatsu.core.ui
import android.app.Dialog import android.app.Dialog
import android.os.Bundle import android.os.Bundle
@ -13,17 +13,19 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog 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.core.ui.dialog.AppBottomSheetDialog
import org.koitharu.kotatsu.utils.ext.findActivity import org.koitharu.kotatsu.core.util.ext.findActivity
import org.koitharu.kotatsu.utils.ext.getDisplaySize import org.koitharu.kotatsu.core.util.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() {
private var viewBinding: B? = null var viewBinding: B? = null
private set
@Deprecated("", ReplaceWith("requireViewBinding()"))
protected val binding: B protected val binding: B
get() = checkNotNull(viewBinding) get() = requireViewBinding()
protected val behavior: BottomSheetBehavior<*>? protected val behavior: BottomSheetBehavior<*>?
get() = (dialog as? BottomSheetDialog)?.behavior get() = (dialog as? BottomSheetDialog)?.behavior
@ -39,13 +41,14 @@ abstract class BaseBottomSheet<B : ViewBinding> : BottomSheetDialogFragment() {
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle?, savedInstanceState: Bundle?,
): View { ): View {
val binding = onInflateView(inflater, container) val binding = onCreateViewBinding(inflater, container)
viewBinding = binding viewBinding = binding
return binding.root return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { final override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val binding = requireViewBinding()
// 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) {
@ -55,6 +58,7 @@ abstract class BaseBottomSheet<B : ViewBinding> : BottomSheetDialogFragment() {
binding.root.context.findActivity()?.getDisplaySize()?.let { binding.root.context.findActivity()?.getDisplaySize()?.let {
behavior?.peekHeight = (it.height() * 0.4).toInt() behavior?.peekHeight = (it.height() * 0.4).toInt()
} }
onViewBindingCreated(binding, savedInstanceState)
} }
override fun onDestroyView() { override fun onDestroyView() {
@ -75,7 +79,9 @@ abstract class BaseBottomSheet<B : ViewBinding> : BottomSheetDialogFragment() {
} }
} }
protected abstract fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): B protected abstract fun onCreateViewBinding(inflater: LayoutInflater, container: ViewGroup?): B
protected open fun onViewBindingCreated(binding: B, savedInstanceState: Bundle?) = Unit
protected fun setExpanded(isExpanded: Boolean, isLocked: Boolean) { protected fun setExpanded(isExpanded: Boolean, isLocked: Boolean) {
val b = behavior ?: return val b = behavior ?: return
@ -89,4 +95,8 @@ abstract class BaseBottomSheet<B : ViewBinding> : BottomSheetDialogFragment() {
} }
b.isDraggable = !isLocked b.isDraggable = !isLocked
} }
fun requireViewBinding(): B = checkNotNull(viewBinding) {
"Fragment $this did not return a ViewBinding from onCreateView() or this was called before onCreateView()."
}
} }

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui package org.koitharu.kotatsu.core.ui
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
@ -6,19 +6,21 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import org.koitharu.kotatsu.base.ui.util.ActionModeDelegate
import org.koitharu.kotatsu.base.ui.util.WindowInsetsDelegate
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.ui.util.ActionModeDelegate
import org.koitharu.kotatsu.core.ui.util.WindowInsetsDelegate
@Suppress("LeakingThis") @Suppress("LeakingThis")
abstract class BaseFragment<B : ViewBinding> : abstract class BaseFragment<B : ViewBinding> :
Fragment(), Fragment(),
WindowInsetsDelegate.WindowInsetsListener { WindowInsetsDelegate.WindowInsetsListener {
private var viewBinding: B? = null var viewBinding: B? = null
private set
@Deprecated("", ReplaceWith("requireViewBinding()"))
protected val binding: B protected val binding: B
get() = checkNotNull(viewBinding) get() = requireViewBinding()
@JvmField @JvmField
protected val exceptionResolver = ExceptionResolver(this) protected val exceptionResolver = ExceptionResolver(this)
@ -29,19 +31,20 @@ abstract class BaseFragment<B : ViewBinding> :
protected val actionModeDelegate: ActionModeDelegate protected val actionModeDelegate: ActionModeDelegate
get() = (requireActivity() as BaseActivity<*>).actionModeDelegate get() = (requireActivity() as BaseActivity<*>).actionModeDelegate
override fun onCreateView( final override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View {
val binding = onInflateView(inflater, container) val binding = onCreateViewBinding(inflater, container)
viewBinding = binding viewBinding = binding
return binding.root return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { final override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
insetsDelegate.onViewCreated(view) insetsDelegate.onViewCreated(view)
onViewBindingCreated(requireViewBinding(), savedInstanceState)
} }
override fun onDestroyView() { override fun onDestroyView() {
@ -50,7 +53,14 @@ abstract class BaseFragment<B : ViewBinding> :
super.onDestroyView() super.onDestroyView()
} }
fun requireViewBinding(): B = checkNotNull(viewBinding) {
"Fragment $this did not return a ViewBinding from onCreateView() or this was called before onCreateView()."
}
@Deprecated("", ReplaceWith("viewBinding"))
protected fun bindingOrNull() = viewBinding protected fun bindingOrNull() = viewBinding
protected abstract fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): B protected abstract fun onCreateViewBinding(inflater: LayoutInflater, container: ViewGroup?): B
protected open fun onViewBindingCreated(binding: B, savedInstanceState: Bundle?) = Unit
} }

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui package org.koitharu.kotatsu.core.ui
import android.graphics.Color import android.graphics.Color
import android.os.Build import android.os.Build

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui package org.koitharu.kotatsu.core.ui
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
@ -9,9 +9,9 @@ import androidx.core.view.updatePadding
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner
import org.koitharu.kotatsu.base.ui.util.WindowInsetsDelegate
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.util.RecyclerViewOwner
import org.koitharu.kotatsu.core.ui.util.WindowInsetsDelegate
import org.koitharu.kotatsu.settings.SettingsHeadersFragment import org.koitharu.kotatsu.settings.SettingsHeadersFragment
import javax.inject.Inject import javax.inject.Inject
@ -56,6 +56,7 @@ abstract class BasePreferenceFragment(@StringRes private val titleId: Int) :
) )
} }
@Suppress("UsePropertyAccessSyntax")
protected fun setTitle(title: CharSequence) { protected fun setTitle(title: CharSequence) {
(parentFragment as? SettingsHeadersFragment)?.setTitle(title) (parentFragment as? SettingsHeadersFragment)?.setTitle(title)
?: activity?.setTitle(title) ?: activity?.setTitle(title)

@ -0,0 +1,5 @@
package org.koitharu.kotatsu.core.ui
import androidx.lifecycle.LifecycleService
abstract class BaseService : LifecycleService()

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui package org.koitharu.kotatsu.core.ui
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
@ -9,9 +9,9 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koitharu.kotatsu.base.ui.util.CountedBooleanLiveData import org.koitharu.kotatsu.core.ui.util.CountedBooleanLiveData
import org.koitharu.kotatsu.utils.SingleLiveEvent import org.koitharu.kotatsu.core.util.SingleLiveEvent
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug import org.koitharu.kotatsu.util.ext.printStackTraceDebug
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.EmptyCoroutineContext

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui package org.koitharu.kotatsu.core.ui
import android.content.Intent import android.content.Intent
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@ -9,7 +9,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug import org.koitharu.kotatsu.util.ext.printStackTraceDebug
abstract class CoroutineIntentService : BaseService() { abstract class CoroutineIntentService : BaseService() {

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui package org.koitharu.kotatsu.core.ui
import android.app.Activity import android.app.Activity
import android.app.Application.ActivityLifecycleCallbacks import android.app.Application.ActivityLifecycleCallbacks

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.dialog package org.koitharu.kotatsu.core.ui.dialog
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.dialog package org.koitharu.kotatsu.core.ui.dialog
import android.content.Context import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.core.ui package org.koitharu.kotatsu.core.ui.dialog
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
@ -6,7 +6,6 @@ import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.text.HtmlCompat import androidx.core.text.HtmlCompat
import androidx.core.text.htmlEncode import androidx.core.text.htmlEncode
@ -14,12 +13,12 @@ import androidx.core.text.parseAsHtml
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.AlertDialogFragment import org.koitharu.kotatsu.core.ui.AlertDialogFragment
import org.koitharu.kotatsu.core.util.ext.isReportable
import org.koitharu.kotatsu.core.util.ext.report
import org.koitharu.kotatsu.core.util.ext.requireSerializable
import org.koitharu.kotatsu.core.util.ext.withArgs
import org.koitharu.kotatsu.databinding.DialogErrorDetailsBinding import org.koitharu.kotatsu.databinding.DialogErrorDetailsBinding
import org.koitharu.kotatsu.utils.ext.isReportable
import org.koitharu.kotatsu.utils.ext.report
import org.koitharu.kotatsu.utils.ext.requireSerializable
import org.koitharu.kotatsu.utils.ext.withArgs
class ErrorDetailsDialog : AlertDialogFragment<DialogErrorDetailsBinding>() { class ErrorDetailsDialog : AlertDialogFragment<DialogErrorDetailsBinding>() {
@ -31,12 +30,12 @@ class ErrorDetailsDialog : AlertDialogFragment<DialogErrorDetailsBinding>() {
exception = args.requireSerializable(ARG_ERROR) exception = args.requireSerializable(ARG_ERROR)
} }
override fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): DialogErrorDetailsBinding { override fun onCreateViewBinding(inflater: LayoutInflater, container: ViewGroup?): DialogErrorDetailsBinding {
return DialogErrorDetailsBinding.inflate(inflater, container, false) return DialogErrorDetailsBinding.inflate(inflater, container, false)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewBindingCreated(binding: DialogErrorDetailsBinding, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewBindingCreated(binding, savedInstanceState)
with(binding.textViewMessage) { with(binding.textViewMessage) {
movementMethod = LinkMovementMethod.getInstance() movementMethod = LinkMovementMethod.getInstance()
text = context.getString( text = context.getString(

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.dialog package org.koitharu.kotatsu.core.ui.dialog
import android.content.Context import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.dialog package org.koitharu.kotatsu.core.ui.dialog
import android.content.DialogInterface import android.content.DialogInterface

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.dialog package org.koitharu.kotatsu.core.ui.dialog
import android.content.Context import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.dialog package org.koitharu.kotatsu.core.ui.dialog
import android.content.Context import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.utils.image package org.koitharu.kotatsu.core.ui.image
import android.content.Context import android.content.Context
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.utils.image package org.koitharu.kotatsu.core.ui.image
import android.view.View import android.view.View
import android.view.View.OnLayoutChangeListener import android.view.View.OnLayoutChangeListener
@ -7,10 +7,10 @@ import android.widget.ImageView
import coil.size.Dimension import coil.size.Dimension
import coil.size.Size import coil.size.Size
import coil.size.SizeResolver import coil.size.SizeResolver
import kotlin.coroutines.resume
import kotlin.math.roundToInt
import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
import kotlin.math.roundToInt
private const val ASPECT_RATIO_HEIGHT = 18f private const val ASPECT_RATIO_HEIGHT = 18f
private const val ASPECT_RATIO_WIDTH = 13f private const val ASPECT_RATIO_WIDTH = 13f

@ -1,7 +1,12 @@
package org.koitharu.kotatsu.utils.image package org.koitharu.kotatsu.core.ui.image
import android.content.Context import android.content.Context
import android.graphics.* import android.graphics.Canvas
import android.graphics.Color
import android.graphics.ColorFilter
import android.graphics.Paint
import android.graphics.PixelFormat
import android.graphics.Rect
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import com.google.android.material.color.MaterialColors import com.google.android.material.color.MaterialColors

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.utils.image package org.koitharu.kotatsu.core.ui.image
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
@ -13,7 +13,11 @@ import coil.decode.Decoder
import coil.decode.ImageSource import coil.decode.ImageSource
import coil.fetch.SourceResult import coil.fetch.SourceResult
import coil.request.Options import coil.request.Options
import coil.size.* import coil.size.Dimension
import coil.size.Scale
import coil.size.Size
import coil.size.isOriginal
import coil.size.pxOrElse
import kotlinx.coroutines.runInterruptible import kotlinx.coroutines.runInterruptible
import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit import kotlinx.coroutines.sync.withPermit

@ -1,8 +1,12 @@
package org.koitharu.kotatsu.utils.image package org.koitharu.kotatsu.core.ui.image
import android.graphics.Bitmap import android.graphics.Bitmap
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import androidx.core.graphics.* import androidx.core.graphics.alpha
import androidx.core.graphics.blue
import androidx.core.graphics.get
import androidx.core.graphics.green
import androidx.core.graphics.red
import coil.size.Size import coil.size.Size
import coil.transform.Transformation import coil.transform.Transformation
import kotlin.math.abs import kotlin.math.abs

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list package org.koitharu.kotatsu.core.ui.list
import android.view.View import android.view.View
import android.view.View.OnClickListener import android.view.View.OnClickListener

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list package org.koitharu.kotatsu.core.ui.list
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list package org.koitharu.kotatsu.core.ui.list
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list package org.koitharu.kotatsu.core.ui.list
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list package org.koitharu.kotatsu.core.ui.list
import android.app.Activity import android.app.Activity
import android.os.Bundle import android.os.Bundle
@ -12,9 +12,9 @@ import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.savedstate.SavedStateRegistry import androidx.savedstate.SavedStateRegistry
import androidx.savedstate.SavedStateRegistryOwner import androidx.savedstate.SavedStateRegistryOwner
import kotlin.coroutines.EmptyCoroutineContext
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import org.koitharu.kotatsu.base.ui.list.decor.AbstractSelectionItemDecoration import org.koitharu.kotatsu.core.ui.list.decor.AbstractSelectionItemDecoration
import kotlin.coroutines.EmptyCoroutineContext
private const val KEY_SELECTION = "selection" private const val KEY_SELECTION = "selection"
private const val PROVIDER_NAME = "selection_decoration" private const val PROVIDER_NAME = "selection_decoration"

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list package org.koitharu.kotatsu.core.ui.list
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable import android.os.Parcelable

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list package org.koitharu.kotatsu.core.ui.list
import android.view.View import android.view.View

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list package org.koitharu.kotatsu.core.ui.list
interface OnTipCloseListener<T> { interface OnTipCloseListener<T> {

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list package org.koitharu.kotatsu.core.ui.list
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list package org.koitharu.kotatsu.core.ui.list
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list package org.koitharu.kotatsu.core.ui.list
import android.app.Activity import android.app.Activity
import android.os.Bundle import android.os.Bundle
@ -14,7 +14,7 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.savedstate.SavedStateRegistry import androidx.savedstate.SavedStateRegistry
import androidx.savedstate.SavedStateRegistryOwner import androidx.savedstate.SavedStateRegistryOwner
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import org.koitharu.kotatsu.base.ui.list.decor.AbstractSelectionItemDecoration import org.koitharu.kotatsu.core.ui.list.decor.AbstractSelectionItemDecoration
import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.EmptyCoroutineContext
private const val PROVIDER_NAME = "selection_decoration_sectioned" private const val PROVIDER_NAME = "selection_decoration_sectioned"

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list.decor package org.koitharu.kotatsu.core.ui.list.decor
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
@ -59,7 +59,7 @@ abstract class AbstractDividerItemDecoration(context: Context) : RecyclerView.It
left, left,
parent.paddingTop.toFloat(), parent.paddingTop.toFloat(),
right, right,
(parent.height - parent.paddingBottom).toFloat() (parent.height - parent.paddingBottom).toFloat(),
) )
} else { } else {
left = 0f left = 0f

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list.decor package org.koitharu.kotatsu.core.ui.list.decor
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Rect import android.graphics.Rect
@ -67,7 +67,7 @@ abstract class AbstractSelectionItemDecoration : RecyclerView.ItemDecoration() {
if (parent.clipToPadding) { if (parent.clipToPadding) {
canvas.clipRect( canvas.clipRect(
parent.paddingLeft, parent.paddingTop, parent.width - parent.paddingRight, parent.paddingLeft, parent.paddingTop, parent.width - parent.paddingRight,
parent.height - parent.paddingBottom parent.height - parent.paddingBottom,
) )
} }

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list.decor package org.koitharu.kotatsu.core.ui.list.decor
import android.graphics.Rect import android.graphics.Rect
import android.view.View import android.view.View

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list.decor package org.koitharu.kotatsu.core.ui.list.decor
import android.graphics.Rect import android.graphics.Rect
import android.util.SparseIntArray import android.util.SparseIntArray

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list.fastscroll package org.koitharu.kotatsu.core.ui.list.fastscroll
import android.animation.Animator import android.animation.Animator
import android.animation.AnimatorListenerAdapter import android.animation.AnimatorListenerAdapter
@ -8,9 +8,9 @@ import android.view.animation.AccelerateInterpolator
import android.view.animation.DecelerateInterpolator import android.view.animation.DecelerateInterpolator
import androidx.core.view.isInvisible import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
import org.koitharu.kotatsu.core.util.ext.animatorDurationScale
import org.koitharu.kotatsu.core.util.ext.measureWidth
import kotlin.math.hypot import kotlin.math.hypot
import org.koitharu.kotatsu.utils.ext.animatorDurationScale
import org.koitharu.kotatsu.utils.ext.measureWidth
class BubbleAnimator( class BubbleAnimator(
private val bubble: View, private val bubble: View,

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list.fastscroll package org.koitharu.kotatsu.core.ui.list.fastscroll
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list.fastscroll package org.koitharu.kotatsu.core.ui.list.fastscroll
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
@ -22,9 +22,9 @@ import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.util.ext.getThemeColor
import org.koitharu.kotatsu.core.util.ext.isLayoutReversed
import org.koitharu.kotatsu.databinding.FastScrollerBinding import org.koitharu.kotatsu.databinding.FastScrollerBinding
import org.koitharu.kotatsu.utils.ext.getThemeColor
import org.koitharu.kotatsu.utils.ext.isLayoutReversed
import kotlin.math.roundToInt import kotlin.math.roundToInt
import com.google.android.material.R as materialR import com.google.android.material.R as materialR
@ -98,6 +98,7 @@ class FastScroller @JvmOverloads constructor(
showScrollbar() showScrollbar()
if (showBubbleAlways && sectionIndexer != null) showBubble() if (showBubbleAlways && sectionIndexer != null) showBubble()
} }
RecyclerView.SCROLL_STATE_IDLE -> if (hideScrollbar && !binding.thumb.isSelected) { RecyclerView.SCROLL_STATE_IDLE -> if (hideScrollbar && !binding.thumb.isSelected) {
handler.postDelayed(scrollbarHider, SCROLLBAR_HIDE_DELAY) handler.postDelayed(scrollbarHider, SCROLLBAR_HIDE_DELAY)
} }
@ -176,10 +177,12 @@ class FastScroller @JvmOverloads constructor(
setYPositions() setYPositions()
return true return true
} }
MotionEvent.ACTION_MOVE -> { MotionEvent.ACTION_MOVE -> {
setYPositions() setYPositions()
return true return true
} }
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
requestDisallowInterceptTouchEvent(false) requestDisallowInterceptTouchEvent(false)
setHandleSelected(false) setHandleSelected(false)
@ -248,17 +251,20 @@ class FastScroller @JvmOverloads constructor(
setMargins(0, marginTop, 0, marginBottom) setMargins(0, marginTop, 0, marginBottom)
} }
} }
is CoordinatorLayout -> layoutParams = (layoutParams as CoordinatorLayout.LayoutParams).apply { is CoordinatorLayout -> layoutParams = (layoutParams as CoordinatorLayout.LayoutParams).apply {
height = LayoutParams.MATCH_PARENT height = LayoutParams.MATCH_PARENT
anchorGravity = GravityCompat.END anchorGravity = GravityCompat.END
anchorId = recyclerViewId anchorId = recyclerViewId
setMargins(0, marginTop, 0, marginBottom) setMargins(0, marginTop, 0, marginBottom)
} }
is FrameLayout -> layoutParams = (layoutParams as FrameLayout.LayoutParams).apply { is FrameLayout -> layoutParams = (layoutParams as FrameLayout.LayoutParams).apply {
height = LayoutParams.MATCH_PARENT height = LayoutParams.MATCH_PARENT
gravity = GravityCompat.END gravity = GravityCompat.END
setMargins(0, marginTop, 0, marginBottom) setMargins(0, marginTop, 0, marginBottom)
} }
is RelativeLayout -> layoutParams = (layoutParams as RelativeLayout.LayoutParams).apply { is RelativeLayout -> layoutParams = (layoutParams as RelativeLayout.LayoutParams).apply {
height = 0 height = 0
addRule(RelativeLayout.ALIGN_TOP, recyclerViewId) addRule(RelativeLayout.ALIGN_TOP, recyclerViewId)
@ -266,6 +272,7 @@ class FastScroller @JvmOverloads constructor(
addRule(RelativeLayout.ALIGN_END, recyclerViewId) addRule(RelativeLayout.ALIGN_END, recyclerViewId)
setMargins(0, marginTop, 0, marginBottom) setMargins(0, marginTop, 0, marginBottom)
} }
else -> throw IllegalArgumentException("Parent ViewGroup must be a ConstraintLayout, CoordinatorLayout, FrameLayout, or RelativeLayout") else -> throw IllegalArgumentException("Parent ViewGroup must be a ConstraintLayout, CoordinatorLayout, FrameLayout, or RelativeLayout")
} }

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.list.fastscroll package org.koitharu.kotatsu.core.ui.list.fastscroll
import android.animation.Animator import android.animation.Animator
import android.animation.AnimatorListenerAdapter import android.animation.AnimatorListenerAdapter
@ -7,7 +7,7 @@ import android.view.ViewPropertyAnimator
import androidx.core.view.isInvisible import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.utils.ext.animatorDurationScale import org.koitharu.kotatsu.core.util.ext.animatorDurationScale
class ScrollbarAnimator( class ScrollbarAnimator(
private val scrollbar: View, private val scrollbar: View,

@ -1,10 +1,10 @@
package org.koitharu.kotatsu.core.ui package org.koitharu.kotatsu.core.ui.model
import android.content.res.Resources import android.content.res.Resources
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.util.ext.daysDiff
import org.koitharu.kotatsu.core.util.ext.format
import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.utils.ext.daysDiff
import org.koitharu.kotatsu.utils.ext.format
import java.util.Date import java.util.Date
sealed class DateTimeAgo : ListModel { sealed class DateTimeAgo : ListModel {
@ -107,9 +107,7 @@ sealed class DateTimeAgo : ListModel {
other as Absolute other as Absolute
if (day != other.day) return false return day == other.day
return true
} }
override fun hashCode(): Int { override fun hashCode(): Int {

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.core.ui package org.koitharu.kotatsu.core.ui.model
import androidx.annotation.StringRes import androidx.annotation.StringRes
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.util package org.koitharu.kotatsu.core.ui.util
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.util package org.koitharu.kotatsu.core.ui.util
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode

@ -1,9 +1,9 @@
package org.koitharu.kotatsu.base.ui.util package org.koitharu.kotatsu.core.ui.util
import android.app.Activity import android.app.Activity
import android.os.Bundle import android.os.Bundle
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import org.koitharu.kotatsu.base.ui.DefaultActivityLifecycleCallbacks import org.koitharu.kotatsu.core.ui.DefaultActivityLifecycleCallbacks
import java.util.WeakHashMap import java.util.WeakHashMap
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.util package org.koitharu.kotatsu.core.ui.util
import dagger.hilt.EntryPoint import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn import dagger.hilt.InstallIn

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.util package org.koitharu.kotatsu.core.ui.util
import android.view.MenuItem import android.view.MenuItem
import android.view.MenuItem.OnActionExpandListener import android.view.MenuItem.OnActionExpandListener

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.util package org.koitharu.kotatsu.core.ui.util
import androidx.annotation.AnyThread import androidx.annotation.AnyThread
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.util package org.koitharu.kotatsu.core.ui.util
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.base.ui.util package org.koitharu.kotatsu.core.ui.util
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView

@ -1,7 +1,6 @@
package org.koitharu.kotatsu.base.ui.util package org.koitharu.kotatsu.core.ui.util
import androidx.annotation.StringRes import androidx.annotation.StringRes
import org.koitharu.kotatsu.base.domain.ReversibleHandle
class ReversibleAction( class ReversibleAction(
@StringRes val stringResId: Int, @StringRes val stringResId: Int,

@ -1,10 +1,9 @@
package org.koitharu.kotatsu.base.ui.util package org.koitharu.kotatsu.core.ui.util
import android.view.View import android.view.View
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.domain.reverseAsync
class ReversibleActionObserver( class ReversibleActionObserver(
private val snackbarHost: View, private val snackbarHost: View,

@ -1,12 +1,12 @@
package org.koitharu.kotatsu.base.domain package org.koitharu.kotatsu.core.ui.util
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.processLifecycleScope
import org.koitharu.kotatsu.utils.ext.processLifecycleScope import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.utils.ext.runCatchingCancellable import org.koitharu.kotatsu.util.ext.printStackTraceDebug
fun interface ReversibleHandle { fun interface ReversibleHandle {

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save