Fix warnings and code cleanup

master
Koitharu 1 year ago
parent 10bd46f077
commit f91f55fa66
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -70,6 +70,7 @@ android {
'-opt-in=kotlin.ExperimentalStdlibApi',
'-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi',
'-opt-in=kotlinx.coroutines.ExperimentalForInheritanceCoroutinesApi',
'-opt-in=kotlinx.coroutines.InternalForInheritanceCoroutinesApi',
'-opt-in=kotlinx.coroutines.FlowPreview',
'-opt-in=kotlin.contracts.ExperimentalContracts',
'-opt-in=coil3.annotation.ExperimentalCoilApi',

@ -4,9 +4,9 @@ import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.BadParcelableException
import androidx.core.app.PendingIntentCompat
import androidx.core.net.toUri
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.nav.AppRouter
import org.koitharu.kotatsu.core.util.ext.getSerializableExtraCompat
@ -27,7 +27,7 @@ class ErrorReporterReceiver : BroadcastReceiver() {
fun getPendingIntent(context: Context, e: Throwable): PendingIntent? = try {
val intent = Intent(context, ErrorReporterReceiver::class.java)
intent.setAction(ACTION_REPORT)
intent.setData(Uri.parse("err://${e.hashCode()}"))
intent.setData("err://${e.hashCode()}".toUri())
intent.putExtra(AppRouter.KEY_ERROR, e)
PendingIntentCompat.getBroadcast(context, 0, intent, 0, false)
} catch (e: BadParcelableException) {

@ -1,13 +1,9 @@
package org.koitharu.kotatsu.core.model
import android.content.Context
import android.graphics.Color
import android.os.Build
import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import android.text.style.ImageSpan
import android.text.style.RelativeSizeSpan
import android.text.style.SuperscriptSpan
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
@ -16,7 +12,6 @@ import androidx.core.text.inSpans
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.parser.external.ExternalMangaSource
import org.koitharu.kotatsu.core.util.ext.getDisplayName
import org.koitharu.kotatsu.core.util.ext.getThemeColor
import org.koitharu.kotatsu.core.util.ext.toLocale
import org.koitharu.kotatsu.core.util.ext.toLocaleOrNull
import org.koitharu.kotatsu.parsers.model.ContentType
@ -24,7 +19,6 @@ import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.splitTwoParts
import java.util.Locale
import androidx.appcompat.R as appcompatR
data object LocalMangaSource : MangaSource {
override val name = "LOCAL"
@ -102,14 +96,6 @@ fun MangaSource.getTitle(context: Context): String = when (val source = unwrap()
else -> context.getString(R.string.unknown)
}
fun SpannableStringBuilder.appendNsfwLabel(context: Context) = inSpans(
ForegroundColorSpan(context.getThemeColor(appcompatR.attr.colorError, Color.RED)),
RelativeSizeSpan(0.74f),
SuperscriptSpan(),
) {
append(context.getString(R.string.nsfw))
}
fun SpannableStringBuilder.appendIcon(textView: TextView, @DrawableRes resId: Int): SpannableStringBuilder {
val icon = ContextCompat.getDrawable(textView.context, resId) ?: return this
icon.setTintList(textView.textColors)

@ -675,7 +675,7 @@ class AppRouter private constructor(
companion object {
fun from(view: View): AppRouter? = runCatching {
AppRouter(view.findFragment<Fragment>())
AppRouter(view.findFragment())
}.getOrElse {
(view.context.findActivity() as? FragmentActivity)?.let(::AppRouter)
}

@ -7,7 +7,7 @@ import java.io.InputStreamReader
object RomCompat {
val isMiui = suspendLazy<Boolean>(Dispatchers.IO) {
val isMiui = suspendLazy(Dispatchers.IO) {
getProp("ro.miui.ui.version.name").isNotEmpty()
}

@ -1,6 +1,7 @@
package org.koitharu.kotatsu.core.parser
import android.graphics.Canvas
import androidx.core.graphics.createBitmap
import org.koitharu.kotatsu.parsers.bitmap.Bitmap
import org.koitharu.kotatsu.parsers.bitmap.Rect
import java.io.OutputStream
@ -35,7 +36,7 @@ class BitmapWrapper private constructor(
companion object {
fun create(width: Int, height: Int) = BitmapWrapper(
AndroidBitmap.createBitmap(width, height, AndroidBitmap.Config.ARGB_8888),
createBitmap(width, height, AndroidBitmap.Config.ARGB_8888),
)
fun create(bitmap: AndroidBitmap) = BitmapWrapper(

@ -2,11 +2,11 @@ package org.koitharu.kotatsu.core.parser.favicon
import android.graphics.Color
import android.graphics.drawable.AdaptiveIconDrawable
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.net.Uri
import android.os.Build
import coil3.ColorImage
import coil3.ImageLoader
import coil3.asImage
import coil3.decode.DataSource
@ -45,7 +45,7 @@ class FaviconFetcher(
is ParserMangaRepository -> fetchParserFavicon(repo)
is ExternalMangaRepository -> fetchPluginIcon(repo)
is EmptyMangaRepository -> ImageFetchResult(
image = ColorDrawable(Color.WHITE).asImage(),
image = ColorImage(Color.WHITE),
isSampled = false,
dataSource = DataSource.MEMORY,
)

@ -30,7 +30,7 @@ abstract class FragmentContainerActivity(private val fragmentClass: Class<out Fr
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityContainerBinding.inflate(layoutInflater))
setDisplayHomeAsUp(true, false)
setDisplayHomeAsUp(isEnabled = true, showUpAsClose = false)
val fm = supportFragmentManager
if (fm.findFragmentById(R.id.container) == null) {
fm.commit {

@ -2,6 +2,7 @@ package org.koitharu.kotatsu.core.ui.list.lifecycle
import android.view.View
import androidx.core.view.children
import androidx.core.view.isEmpty
import androidx.viewpager2.widget.ViewPager2
import org.koitharu.kotatsu.core.util.ext.recyclerView
@ -28,7 +29,7 @@ class PagerLifecycleDispatcher(
pendingUpdate = null
var hasResumedItem = false
val rv = pager.recyclerView ?: return
if (rv.childCount == 0) {
if (rv.isEmpty()) {
return
}
for (child in rv.children) {

@ -5,7 +5,6 @@ import android.os.Parcel
import android.os.Parcelable
import android.os.Parcelable.Creator
import android.util.AttributeSet
import android.view.View
import android.widget.Checkable
import androidx.annotation.AttrRes
import androidx.appcompat.widget.AppCompatImageView
@ -63,12 +62,6 @@ class CheckableImageView @JvmOverloads constructor(
}
}
class ToggleOnClickListener : OnClickListener {
override fun onClick(view: View) {
(view as? Checkable)?.toggle()
}
}
fun interface OnCheckedChangeListener {
fun onCheckedChanged(view: CheckableImageView, isChecked: Boolean)

@ -7,6 +7,7 @@ import android.widget.ImageView
import android.widget.LinearLayout
import androidx.annotation.DrawableRes
import androidx.core.content.withStyledAttributes
import androidx.core.view.isNotEmpty
import androidx.core.view.isVisible
import org.koitharu.kotatsu.R
@ -82,7 +83,7 @@ class IconsView @JvmOverloads constructor(
private fun addImageView() = ImageView(context).also {
it.scaleType = ImageView.ScaleType.FIT_CENTER
val lp = LayoutParams(iconSize, iconSize)
if (childCount != 0) {
if (isNotEmpty()) {
lp.marginStart = iconSpacing
}
addView(it, lp)

@ -1,29 +1,18 @@
package org.koitharu.kotatsu.core.util.ext
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleDestroyedException
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.lifecycle.RetainedLifecycle
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.plus
import kotlinx.coroutines.suspendCancellableCoroutine
import org.koitharu.kotatsu.core.util.AcraCoroutineErrorHandler
import org.koitharu.kotatsu.core.util.RetainedLifecycleCoroutineScope
import org.koitharu.kotatsu.parsers.util.cancelAll
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.cancellation.CancellationException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
val processLifecycleScope: CoroutineScope
get() = ProcessLifecycleOwner.get().lifecycleScope + AcraCoroutineErrorHandler()
@ -31,54 +20,6 @@ val processLifecycleScope: CoroutineScope
val RetainedLifecycle.lifecycleScope: RetainedLifecycleCoroutineScope
inline get() = RetainedLifecycleCoroutineScope(this)
suspend fun Lifecycle.awaitStateAtLeast(state: Lifecycle.State) {
if (currentState.isAtLeast(state)) {
return
}
suspendCancellableCoroutine { cont ->
val observer = ContinuationLifecycleObserver(this, cont, state)
addObserverFromAnyThread(observer)
cont.invokeOnCancellation {
removeObserverFromAnyThread(observer)
}
}
}
private class ContinuationLifecycleObserver(
private val lifecycle: Lifecycle,
private val continuation: CancellableContinuation<Unit>,
private val targetState: Lifecycle.State,
) : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (event == Lifecycle.Event.upTo(targetState)) {
lifecycle.removeObserver(this)
continuation.resume(Unit)
} else if (event == Lifecycle.Event.ON_DESTROY) {
lifecycle.removeObserver(this)
continuation.resumeWithException(LifecycleDestroyedException())
}
}
}
private fun Lifecycle.addObserverFromAnyThread(observer: LifecycleObserver) {
val dispatcher = Dispatchers.Main.immediate
if (dispatcher.isDispatchNeeded(EmptyCoroutineContext)) {
dispatcher.dispatch(EmptyCoroutineContext) { addObserver(observer) }
} else {
addObserver(observer)
}
}
private fun Lifecycle.removeObserverFromAnyThread(observer: LifecycleObserver) {
val dispatcher = Dispatchers.Main.immediate
if (dispatcher.isDispatchNeeded(EmptyCoroutineContext)) {
dispatcher.dispatch(EmptyCoroutineContext) { removeObserver(observer) }
} else {
removeObserver(observer)
}
}
fun <T> Deferred<T>.getCompletionResultOrNull(): Result<T>? = if (isCompleted) {
getCompletionExceptionOrNull()?.let { error ->
Result.failure(error)

@ -35,7 +35,6 @@ fun calculateTimeAgo(instant: Instant, showMonths: Boolean = false): DateTimeAgo
}
}
@Suppress("KotlinConstantConditions")
fun Long.toInstantOrNull() = if (this == 0L) null else Instant.ofEpochMilli(this)
fun Resources.formatDurationShort(millis: Long): String? {

@ -2,17 +2,17 @@ package org.koitharu.kotatsu.core.util.ext
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.view.View
import android.widget.TextView
import androidx.annotation.AttrRes
import androidx.annotation.StringRes
import androidx.annotation.StyleRes
import androidx.core.content.res.use
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.core.widget.TextViewCompat
var TextView.textAndVisible: CharSequence?
get() = text?.takeIf { visibility == View.VISIBLE }
get() = text?.takeIf { isVisible }
set(value) {
text = value
isGone = value.isNullOrEmpty()

@ -158,7 +158,7 @@ class ZipOutput(
private fun Closeable.closeSafe() {
try {
cachedOutput?.close()
close()
} catch (e: NullPointerException) {
// Don't throw the "Deflater has been closed" exception
e.printStackTraceDebug()

@ -5,7 +5,6 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.observeAsFlow
@ -31,11 +30,6 @@ class DetailsInteractor @Inject constructor(
private val scrobblers: Set<@JvmSuppressWildcards Scrobbler>,
) {
fun observeIsFavourite(mangaId: Long): Flow<Boolean> {
return favouritesRepository.observeCategoriesIds(mangaId)
.map { it.isNotEmpty() }
}
fun observeFavourite(mangaId: Long): Flow<Set<FavouriteCategory>> {
return favouritesRepository.observeCategories(mangaId)
}

@ -126,7 +126,7 @@ class DetailsActivity :
super.onCreate(savedInstanceState)
setContentView(ActivityDetailsBinding.inflate(layoutInflater))
infoBinding = LayoutDetailsTableBinding.bind(viewBinding.root)
setDisplayHomeAsUp(true, false)
setDisplayHomeAsUp(isEnabled = true, showUpAsClose = false)
supportActionBar?.setDisplayShowTitleEnabled(false)
viewBinding.chipFavorite.setOnClickListener(this)
infoBinding.textViewLocal.setOnClickListener(this)
@ -377,7 +377,7 @@ class DetailsActivity :
if (adapter != null) {
adapter.items = scrobblings
} else {
adapter = ScrollingInfoAdapter(this, coil, router)
adapter = ScrollingInfoAdapter(router)
adapter.items = scrobblings
viewBinding.recyclerViewScrobbling.adapter = adapter
viewBinding.recyclerViewScrobbling.addItemDecoration(ScrobblingItemDecoration())

@ -1,8 +1,6 @@
package org.koitharu.kotatsu.details.ui.pager.pages
import android.content.Context
import androidx.lifecycle.LifecycleOwner
import coil3.ImageLoader
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
@ -11,8 +9,6 @@ import org.koitharu.kotatsu.list.ui.adapter.listHeaderAD
import org.koitharu.kotatsu.list.ui.model.ListModel
class PageThumbnailAdapter(
coil: ImageLoader,
lifecycleOwner: LifecycleOwner,
clickListener: OnListItemClickListener<PageThumbnail>,
) : BaseListAdapter<ListModel>(), FastScroller.SectionIndexer {

@ -15,7 +15,6 @@ import androidx.core.view.isVisible
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import coil3.ImageLoader
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.combine
@ -59,9 +58,6 @@ class PagesFragment :
RecyclerViewOwner,
ListSelectionController.Callback {
@Inject
lateinit var coil: ImageLoader
@Inject
lateinit var settings: AppSettings
@ -113,8 +109,6 @@ class PagesFragment :
callback = this,
)
thumbnailsAdapter = PageThumbnailAdapter(
coil = coil,
lifecycleOwner = viewLifecycleOwner,
clickListener = this@PagesFragment,
)
viewModel.gridScale.observe(viewLifecycleOwner, ::onGridScaleChanged) // before rv initialization

@ -13,7 +13,6 @@ import androidx.core.text.method.LinkMovementMethodCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.activityViewModels
import coil3.ImageLoader
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
@ -29,7 +28,6 @@ import org.koitharu.kotatsu.databinding.SheetScrobblingBinding
import org.koitharu.kotatsu.details.ui.DetailsViewModel
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
import javax.inject.Inject
@AndroidEntryPoint
class ScrobblingInfoSheet :
@ -42,9 +40,6 @@ class ScrobblingInfoSheet :
private val viewModel by activityViewModels<DetailsViewModel>()
private var scrobblerIndex: Int = -1
@Inject
lateinit var coil: ImageLoader
private var menu: PopupMenu? = null
override fun onCreate(savedInstanceState: Bundle?) {

@ -1,14 +1,10 @@
package org.koitharu.kotatsu.details.ui.scrobbling
import androidx.lifecycle.LifecycleOwner
import coil3.ImageLoader
import org.koitharu.kotatsu.core.nav.AppRouter
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.list.ui.model.ListModel
class ScrollingInfoAdapter(
lifecycleOwner: LifecycleOwner,
coil: ImageLoader,
router: AppRouter,
) : BaseListAdapter<ListModel>() {

@ -7,7 +7,6 @@ import androidx.core.text.bold
import androidx.core.text.buildSpannedString
import androidx.core.text.color
import androidx.work.WorkInfo
import coil3.memory.MemoryCache
import kotlinx.coroutines.flow.StateFlow
import org.koitharu.kotatsu.core.util.ext.getThemeColor
import org.koitharu.kotatsu.download.ui.list.chapters.DownloadChapter
@ -35,8 +34,6 @@ data class DownloadItemModel(
val chapters: StateFlow<List<DownloadChapter>?>,
) : ListModel, Comparable<DownloadItemModel> {
val coverCacheKey = MemoryCache.Key(manga?.coverUrl.orEmpty(), mapOf("dl" to "1"))
val percent: Float
get() = if (max > 0) progress / max.toFloat() else 0f

@ -43,7 +43,7 @@ class DownloadsActivity : BaseActivity<ActivityDownloadsBinding>(),
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityDownloadsBinding.inflate(layoutInflater))
setDisplayHomeAsUp(true, false)
setDisplayHomeAsUp(isEnabled = true, showUpAsClose = false)
val downloadsAdapter = DownloadsAdapter(this, this)
val decoration = TypedListSpacingDecoration(this, false)
selectionController = ListSelectionController(
@ -80,7 +80,7 @@ class DownloadsActivity : BaseActivity<ActivityDownloadsBinding>(),
right = bars.right,
top = bars.top,
)
return return WindowInsetsCompat.Builder(insets)
return WindowInsetsCompat.Builder(insets)
.setInsets(WindowInsetsCompat.Type.systemBars(), Insets.NONE)
.build()
}

@ -4,9 +4,9 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import android.os.PatternMatcher
import androidx.core.app.PendingIntentCompat
import androidx.core.net.toUri
import org.koitharu.kotatsu.core.util.ext.toUUIDOrNull
import java.util.UUID
@ -81,7 +81,7 @@ class PausingReceiver(
)
private fun createIntent(context: Context, id: UUID, action: String) = Intent(action)
.setData(Uri.parse("$SCHEME://$id"))
.setData("$SCHEME://$id".toUri())
.setPackage(context.packageName)
.putExtra(EXTRA_UUID, id.toString())
}

@ -1,7 +1,6 @@
package org.koitharu.kotatsu.favourites.ui
import android.os.Bundle
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.core.nav.AppRouter
import org.koitharu.kotatsu.core.ui.FragmentContainerActivity
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment

@ -49,7 +49,7 @@ class FavouriteCategoriesActivity :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityCategoriesBinding.inflate(layoutInflater))
setDisplayHomeAsUp(true, false)
setDisplayHomeAsUp(isEnabled = true, showUpAsClose = false)
adapter = CategoriesAdapter(this, this)
selectionController = ListSelectionController(
appCompatDelegate = delegate,

@ -40,7 +40,7 @@ class FavouritesCategoryEditActivity :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityCategoryEditBinding.inflate(layoutInflater))
setDisplayHomeAsUp(true, true)
setDisplayHomeAsUp(isEnabled = true, showUpAsClose = true)
initSortSpinner()
viewBinding.buttonDone.setOnClickListener(this)
viewBinding.editName.addTextChangedListener(this)

@ -18,12 +18,12 @@ import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
import org.koitharu.kotatsu.core.util.ext.joinToStringWithLimit
import org.koitharu.kotatsu.core.util.ext.observe
import org.koitharu.kotatsu.core.util.ext.observeEvent
import org.koitharu.kotatsu.databinding.SheetFavoriteCategoriesBinding
import org.koitharu.kotatsu.databinding.DialogFavoriteBinding
import org.koitharu.kotatsu.favourites.ui.categories.select.adapter.MangaCategoriesAdapter
import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem
@AndroidEntryPoint
class FavoriteDialog : AlertDialogFragment<SheetFavoriteCategoriesBinding>(),
class FavoriteDialog : AlertDialogFragment<DialogFavoriteBinding>(),
OnListItemClickListener<MangaCategoryItem>, DialogInterface.OnClickListener {
private val viewModel by viewModels<FavoriteDialogViewModel>()
@ -31,7 +31,7 @@ class FavoriteDialog : AlertDialogFragment<SheetFavoriteCategoriesBinding>(),
override fun onCreateViewBinding(
inflater: LayoutInflater,
container: ViewGroup?,
) = SheetFavoriteCategoriesBinding.inflate(inflater, container, false)
) = DialogFavoriteBinding.inflate(inflater, container, false)
override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder {
return super.onBuildDialog(builder)
@ -40,7 +40,7 @@ class FavoriteDialog : AlertDialogFragment<SheetFavoriteCategoriesBinding>(),
}
override fun onViewBindingCreated(
binding: SheetFavoriteCategoriesBinding,
binding: DialogFavoriteBinding,
savedInstanceState: Bundle?,
) {
super.onViewBindingCreated(binding, savedInstanceState)

@ -66,10 +66,6 @@ class HistoryRepository @Inject constructor(
return entities.toMangaList()
}
suspend fun getCount(): Int {
return db.getHistoryDao().getCount()
}
suspend fun getLastOrNull(): Manga? {
val entity = db.getHistoryDao().findAll(0, 1).firstOrNull() ?: return null
return entity.toManga()
@ -116,12 +112,6 @@ class HistoryRepository @Inject constructor(
}
}
fun observeHasItems(): Flow<Boolean> {
return db.getHistoryDao().observeCount()
.map { it > 0 }
.distinctUntilChanged()
}
suspend fun addOrUpdate(manga: Manga, chapterId: Long, page: Int, scroll: Int, percent: Float, force: Boolean) {
if (!force && shouldSkip(manga)) {
return
@ -158,7 +148,7 @@ class HistoryRepository @Inject constructor(
return ReadingProgress(
percent = fixedPercent,
totalChapters = entity.chaptersCount,
mode = mode
mode = mode,
).takeIf { it.isValid() }
}

@ -9,6 +9,7 @@ import androidx.annotation.Px
import androidx.core.content.withStyledAttributes
import androidx.core.graphics.ColorUtils
import androidx.core.view.children
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.widget.ImageViewCompat
@ -33,10 +34,12 @@ class CoverStackView @JvmOverloads constructor(
binding.imageViewCover2,
binding.imageViewCover3,
)
private var hideEmptyView: Boolean = true
private var hideEmptyView: Boolean = false
init {
context.withStyledAttributes(attrs, R.styleable.CoverStackView, defStyleAttr) {
hideEmptyView = getBoolean(R.styleable.CoverStackView_hideEmptyViews, hideEmptyView)
children.forEach { it.isGone = hideEmptyView }
val coverSize = getDimension(R.styleable.CoverStackView_coverSize, 0f)
if (coverSize > 0f) {
setCoverSize(coverSize)

@ -9,7 +9,6 @@ import androidx.core.text.method.LinkMovementMethodCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.fragment.app.viewModels
import coil3.ImageLoader
import com.google.android.material.chip.Chip
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
@ -24,14 +23,10 @@ import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
import org.koitharu.kotatsu.search.ui.MangaListActivity
import javax.inject.Inject
@AndroidEntryPoint
class PreviewFragment : BaseFragment<FragmentPreviewBinding>(), View.OnClickListener, ChipsView.OnChipClickListener {
@Inject
lateinit var coil: ImageLoader
private val viewModel: PreviewViewModel by viewModels()
override fun onCreateViewBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentPreviewBinding {
@ -64,9 +59,9 @@ class PreviewFragment : BaseFragment<FragmentPreviewBinding>(), View.OnClickList
R.id.button_open -> router.openDetails(manga)
R.id.button_read -> router.openReader(manga)
R.id.textView_author -> router.openSearch(
R.id.textView_author -> router.showAuthorDialog(
author = manga.authors.firstOrNull() ?: return,
source = manga.source,
query = manga.author ?: return,
)
R.id.imageView_cover -> router.openImage(
@ -93,8 +88,8 @@ class PreviewFragment : BaseFragment<FragmentPreviewBinding>(), View.OnClickList
// Main
loadCover(manga)
textViewTitle.text = manga.title
textViewSubtitle.textAndVisible = manga.altTitle
textViewAuthor.textAndVisible = manga.author
textViewSubtitle.textAndVisible = manga.altTitles.firstOrNull()
textViewAuthor.textAndVisible = manga.authors.firstOrNull()
if (manga.hasRating) {
ratingBar.rating = manga.rating * ratingBar.numStars
ratingBar.isVisible = true
@ -110,8 +105,8 @@ class PreviewFragment : BaseFragment<FragmentPreviewBinding>(), View.OnClickList
buttonRead.setText(
when {
footer == null -> R.string.loading_
footer.isIncognito == true -> R.string.incognito
footer.isInProgress() == true -> R.string._continue
footer.isIncognito -> R.string.incognito
footer.isInProgress() -> R.string._continue
else -> R.string.read
},
)

@ -1,6 +0,0 @@
package org.koitharu.kotatsu.main.ui.owners
interface NoModalBottomSheetOwner {
fun getBottomSheetCollapsedHeight(): Int
}

@ -3,7 +3,6 @@ package org.koitharu.kotatsu.main.ui.welcome
import android.content.Context
import androidx.core.os.ConfigurationCompat
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow

@ -1,9 +1,9 @@
package org.koitharu.kotatsu.reader.domain
import android.graphics.BitmapFactory
import android.net.Uri
import android.util.Size
import androidx.core.net.toFile
import androidx.core.net.toUri
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runInterruptible
import okhttp3.OkHttpClient
@ -62,7 +62,7 @@ class DetectReaderModeUseCase @Inject constructor(
val pageIndex = (pages.size * 0.3).roundToInt()
val page = requireNotNull(pages.getOrNull(pageIndex)) { "No pages" }
val url = repository.getPageUrl(page)
val uri = Uri.parse(url)
val uri = url.toUri()
val size = when {
uri.isZipUri() -> runInterruptible(Dispatchers.IO) {

@ -3,7 +3,6 @@ package org.koitharu.kotatsu.reader.domain
import android.content.Context
import android.graphics.Rect
import android.net.Uri
import android.util.Log
import androidx.annotation.AnyThread
import androidx.annotation.CheckResult
import androidx.collection.LongSparseArray

@ -11,7 +11,6 @@ import androidx.documentfile.provider.DocumentFile
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runInterruptible

@ -33,9 +33,6 @@ class ColorFilterConfigViewModel @Inject constructor(
val isChanged: Boolean
get() = colorFilter.value != initialColorFilter
val is32BitColorsEnabled: Boolean
get() = settings.is32BitColorsEnabled
init {
launchLoadingJob {
initialColorFilter = mangaDataRepository.getColorFilter(manga.id) ?: settings.readerColorFilter

@ -1,8 +0,0 @@
package org.koitharu.kotatsu.reader.ui.pager
interface OnBoundsScrollListener {
fun onScrolledToStart()
fun onScrolledToEnd()
}

@ -1,21 +1,13 @@
package org.koitharu.kotatsu.reader.ui.pager.reversed
import android.graphics.PointF
import android.os.Build
import android.view.Gravity
import android.view.RoundedCorner
import android.view.ViewGroup
import android.view.WindowInsets
import android.widget.FrameLayout
import androidx.annotation.RequiresApi
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.LifecycleOwner
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.core.os.NetworkState
import org.koitharu.kotatsu.core.util.ext.isRtl
import org.koitharu.kotatsu.databinding.ItemPageBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.config.ReaderSettings

@ -5,6 +5,8 @@ import android.util.AttributeSet
import android.view.View
import androidx.core.view.ViewCompat.TYPE_TOUCH
import androidx.core.view.forEach
import androidx.core.view.isEmpty
import androidx.core.view.isNotEmpty
import androidx.core.view.iterator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@ -33,7 +35,7 @@ class WebtoonRecyclerView @JvmOverloads constructor(
override fun startNestedScroll(axes: Int) = startNestedScroll(axes, TYPE_TOUCH)
override fun startNestedScroll(axes: Int, type: Int): Boolean = childCount != 0
override fun startNestedScroll(axes: Int, type: Int): Boolean = isNotEmpty()
override fun dispatchNestedPreScroll(
dx: Int,
@ -59,7 +61,7 @@ class WebtoonRecyclerView @JvmOverloads constructor(
}
private fun consumeVerticalScroll(dy: Int): Int {
if (childCount == 0) {
if (isEmpty()) {
return 0
}
when {
@ -123,7 +125,7 @@ class WebtoonRecyclerView @JvmOverloads constructor(
}
}
fun updateChildrenScroll() {
fun updateChildrenScroll() {
if (isFixingScroll) {
return
}

@ -3,7 +3,7 @@ package org.koitharu.kotatsu.scrobbling.common.ui
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.core.net.toUri
import org.koitharu.kotatsu.scrobbling.common.domain.ScrobblerRepositoryMap
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerUser
@ -31,7 +31,7 @@ class ScrobblerAuthHelper @Inject constructor(
} else {
val repository = repositoriesMap[scrobbler]
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse(repository.oauthUrl)
intent.data = repository.oauthUrl.toUri()
context.startActivity(intent)
}
}

@ -6,7 +6,6 @@ import android.view.View
import androidx.activity.viewModels
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import coil3.ImageLoader
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
@ -24,25 +23,21 @@ import org.koitharu.kotatsu.list.ui.adapter.TypedListSpacingDecoration
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerUser
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo
import org.koitharu.kotatsu.scrobbling.common.ui.config.adapter.ScrobblingMangaAdapter
import javax.inject.Inject
import androidx.appcompat.R as appcompatR
@AndroidEntryPoint
class ScrobblerConfigActivity : BaseActivity<ActivityScrobblerConfigBinding>(),
OnListItemClickListener<ScrobblingInfo>, View.OnClickListener {
@Inject
lateinit var coil: ImageLoader
private val viewModel: ScrobblerConfigViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityScrobblerConfigBinding.inflate(layoutInflater))
setTitle(viewModel.titleResId)
setDisplayHomeAsUp(true, false)
setDisplayHomeAsUp(isEnabled = true, showUpAsClose = false)
val listAdapter = ScrobblingMangaAdapter(this, coil, this)
val listAdapter = ScrobblingMangaAdapter(this)
with(viewBinding.recyclerView) {
adapter = listAdapter
setHasFixedSize(true)

@ -1,7 +1,5 @@
package org.koitharu.kotatsu.scrobbling.common.ui.config.adapter
import androidx.lifecycle.LifecycleOwner
import coil3.ImageLoader
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
@ -11,8 +9,6 @@ import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo
class ScrobblingMangaAdapter(
clickListener: OnListItemClickListener<ScrobblingInfo>,
coil: ImageLoader,
lifecycleOwner: LifecycleOwner,
) : BaseListAdapter<ListModel>() {
init {

@ -12,7 +12,6 @@ import androidx.core.view.updatePadding
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.RecyclerView.NO_ID
import coil3.ImageLoader
import com.google.android.material.tabs.TabLayout
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
@ -40,7 +39,6 @@ import org.koitharu.kotatsu.list.ui.model.LoadingFooter
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
import org.koitharu.kotatsu.scrobbling.common.ui.selector.adapter.ScrobblerMangaSelectionDecoration
import org.koitharu.kotatsu.scrobbling.common.ui.selector.adapter.ScrobblerSelectorAdapter
import javax.inject.Inject
@AndroidEntryPoint
class ScrobblingSelectorSheet :
@ -54,9 +52,6 @@ class ScrobblingSelectorSheet :
ListStateHolderListener,
AsyncListDiffer.ListListener<ListModel> {
@Inject
lateinit var coil: ImageLoader
private var collapsibleActionViewCallback: CollapseActionViewCallback? = null
private var paginationScrollListener: PaginationScrollListener? = null
private val viewModel by viewModels<ScrobblingSelectorViewModel>()
@ -68,7 +63,7 @@ class ScrobblingSelectorSheet :
override fun onViewBindingCreated(binding: SheetScrobblingSelectorBinding, savedInstanceState: Bundle?) {
super.onViewBindingCreated(binding, savedInstanceState)
disableFitToContents()
val listAdapter = ScrobblerSelectorAdapter(viewLifecycleOwner, coil, this, this)
val listAdapter = ScrobblerSelectorAdapter(this, this)
listAdapter.addListListener(this)
val decoration = ScrobblerMangaSelectionDecoration(binding.root.context)
with(binding.recyclerView) {

@ -1,7 +1,5 @@
package org.koitharu.kotatsu.scrobbling.common.ui.selector.adapter
import androidx.lifecycle.LifecycleOwner
import coil3.ImageLoader
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
@ -12,8 +10,6 @@ import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
class ScrobblerSelectorAdapter(
lifecycleOwner: LifecycleOwner,
coil: ImageLoader,
clickListener: OnListItemClickListener<ScrobblerManga>,
stateHolderListener: ListStateHolderListener,
) : BaseListAdapter<ListModel>() {

@ -76,7 +76,7 @@ class MangaListActivity :
val filter = intent.getParcelableExtraCompat<ParcelableMangaListFilter>(AppRouter.KEY_FILTER)?.filter
val sortOrder = intent.getSerializableExtraCompat<SortOrder>(AppRouter.KEY_SORT_ORDER)
source = MangaSource(intent.getStringExtra(AppRouter.KEY_SOURCE))
setDisplayHomeAsUp(true, false)
setDisplayHomeAsUp(isEnabled = true, showUpAsClose = false)
if (viewBinding.containerFilterHeader != null) {
viewBinding.appbar.addOnOffsetChangedListener(this)
}

@ -6,6 +6,7 @@ import android.content.Context
import android.content.SearchRecentSuggestionsProvider
import android.net.Uri
import android.provider.SearchRecentSuggestions
import androidx.core.net.toUri
import org.koitharu.kotatsu.BuildConfig
class MangaSuggestionsProvider : SearchRecentSuggestionsProvider() {
@ -29,6 +30,6 @@ class MangaSuggestionsProvider : SearchRecentSuggestionsProvider() {
.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY)
.build()
val URI: Uri = Uri.parse("content://$AUTHORITY/suggestions")
val URI: Uri = "content://$AUTHORITY/suggestions".toUri()
}
}

@ -9,7 +9,6 @@ import androidx.activity.viewModels
import androidx.appcompat.view.ActionMode
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import coil3.ImageLoader
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
@ -44,9 +43,6 @@ class SearchActivity :
MangaListListener,
ListSelectionController.Callback {
@Inject
lateinit var coil: ImageLoader
@Inject
lateinit var settings: AppSettings
@ -85,8 +81,6 @@ class SearchActivity :
callback = this,
)
val adapter = SearchAdapter(
lifecycleOwner = this,
coil = coil,
listener = this,
itemClickListener = itemClickListener,
sizeResolver = sizeResolver,
@ -96,7 +90,7 @@ class SearchActivity :
viewBinding.recyclerView.setHasFixedSize(true)
viewBinding.recyclerView.addItemDecoration(TypedListSpacingDecoration(this, true))
setDisplayHomeAsUp(true, false)
setDisplayHomeAsUp(isEnabled = true, showUpAsClose = false)
supportActionBar?.setSubtitle(R.string.search_results)
addMenuProvider(SearchKindMenuProvider(this, viewModel.query, viewModel.kind))

@ -1,9 +1,7 @@
package org.koitharu.kotatsu.search.ui.multi.adapter
import android.content.Context
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
import coil3.ImageLoader
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
@ -20,8 +18,6 @@ import org.koitharu.kotatsu.list.ui.size.ItemSizeResolver
import org.koitharu.kotatsu.search.ui.multi.SearchResultsListModel
class SearchAdapter(
lifecycleOwner: LifecycleOwner,
coil: ImageLoader,
listener: MangaListListener,
itemClickListener: OnListItemClickListener<SearchResultsListModel>,
sizeResolver: ItemSizeResolver,

@ -1,5 +1,6 @@
package org.koitharu.kotatsu.search.ui.multi.adapter
import android.annotation.SuppressLint
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
@ -20,6 +21,7 @@ import org.koitharu.kotatsu.list.ui.size.ItemSizeResolver
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.search.ui.multi.SearchResultsListModel
@SuppressLint("NotifyDataSetChanged")
fun searchResultsAD(
sharedPool: RecycledViewPool,
sizeResolver: ItemSizeResolver,

@ -7,7 +7,6 @@ import android.view.ViewGroup
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.ItemTouchHelper
import coil3.ImageLoader
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.core.os.VoiceInputContract
import org.koitharu.kotatsu.core.ui.BaseFragment
@ -16,16 +15,12 @@ import org.koitharu.kotatsu.core.util.ext.consumeAllSystemBarsInsets
import org.koitharu.kotatsu.core.util.ext.observe
import org.koitharu.kotatsu.databinding.FragmentSearchSuggestionBinding
import org.koitharu.kotatsu.search.ui.suggestion.adapter.SearchSuggestionAdapter
import javax.inject.Inject
@AndroidEntryPoint
class SearchSuggestionFragment :
BaseFragment<FragmentSearchSuggestionBinding>(),
SearchSuggestionItemCallback.SuggestionItemListener {
@Inject
lateinit var coil: ImageLoader
private val viewModel by activityViewModels<SearchSuggestionViewModel>()
private val voiceInputLauncher = registerForActivityResult(VoiceInputContract()) { result ->
if (result != null) {
@ -41,8 +36,6 @@ class SearchSuggestionFragment :
override fun onViewBindingCreated(binding: FragmentSearchSuggestionBinding, savedInstanceState: Bundle?) {
super.onViewBindingCreated(binding, savedInstanceState)
val adapter = SearchSuggestionAdapter(
coil = coil,
lifecycleOwner = viewLifecycleOwner,
listener = requireActivity() as SearchSuggestionListener,
)
addMenuProvider(SearchSuggestionMenuProvider(binding.root.context, voiceInputLauncher, viewModel))

@ -1,7 +1,5 @@
package org.koitharu.kotatsu.search.ui.suggestion.adapter
import androidx.lifecycle.LifecycleOwner
import coil3.ImageLoader
import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionListener
import org.koitharu.kotatsu.search.ui.suggestion.model.SearchSuggestionItem
@ -9,8 +7,6 @@ import org.koitharu.kotatsu.search.ui.suggestion.model.SearchSuggestionItem
const val SEARCH_SUGGESTION_ITEM_TYPE_QUERY = 0
class SearchSuggestionAdapter(
coil: ImageLoader,
lifecycleOwner: LifecycleOwner,
listener: SearchSuggestionListener,
) : BaseListAdapter<SearchSuggestionItem>() {

@ -6,25 +6,18 @@ import android.view.View
import androidx.preference.ListPreference
import androidx.preference.Preference
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.cache.MemoryContentCache
import org.koitharu.kotatsu.core.network.DoHProvider
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.BasePreferenceFragment
import org.koitharu.kotatsu.core.util.ext.setDefaultValueCompat
import org.koitharu.kotatsu.parsers.util.names
import java.net.Proxy
import javax.inject.Inject
@AndroidEntryPoint
class NetworkSettingsFragment :
BasePreferenceFragment(R.string.network),
SharedPreferences.OnSharedPreferenceChangeListener {
@Inject
lateinit var contentCache: MemoryContentCache
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_network)
findPreference<ListPreference>(AppSettings.KEY_DOH)?.run {

@ -8,7 +8,6 @@ import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia
import androidx.activity.viewModels
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import coil3.ImageLoader
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.filterNotNull
@ -24,7 +23,6 @@ import org.koitharu.kotatsu.core.util.ext.tryLaunch
import org.koitharu.kotatsu.databinding.ActivityOverrideEditBinding
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
import javax.inject.Inject
import androidx.appcompat.R as appcompatR
import com.google.android.material.R as materialR
@ -42,9 +40,6 @@ class OverrideConfigActivity : BaseActivity<ActivityOverrideEditBinding>(), View
}
}
@Inject
lateinit var coil: ImageLoader
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityOverrideEditBinding.inflate(layoutInflater))

@ -40,7 +40,7 @@ class ReaderTapGridConfigActivity : BaseActivity<ActivityReaderTapActionsBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityReaderTapActionsBinding.inflate(layoutInflater))
setDisplayHomeAsUp(true, false)
setDisplayHomeAsUp(isEnabled = true, showUpAsClose = false)
controls[TapGridArea.TOP_LEFT] = viewBinding.textViewTopLeft
controls[TapGridArea.TOP_CENTER] = viewBinding.textViewTopCenter
controls[TapGridArea.TOP_RIGHT] = viewBinding.textViewTopRight

@ -8,7 +8,6 @@ import androidx.preference.PreferenceManager
import androidx.preference.PreferenceScreen
import androidx.preference.get
import dagger.Reusable
import dagger.hilt.android.qualifiers.ApplicationContext
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.LocalizedAppContext
import org.koitharu.kotatsu.settings.AppearanceSettingsFragment

@ -1,14 +1,10 @@
package org.koitharu.kotatsu.settings.sources.adapter
import androidx.lifecycle.LifecycleOwner
import coil3.ImageLoader
import org.koitharu.kotatsu.core.ui.ReorderableListAdapter
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
class SourceConfigAdapter(
listener: SourceConfigListener,
coil: ImageLoader,
lifecycleOwner: LifecycleOwner,
) : ReorderableListAdapter<SourceConfigItem>() {
init {

@ -3,7 +3,6 @@ package org.koitharu.kotatsu.settings.sources.manage
import android.content.Context
import androidx.room.InvalidationTracker
import dagger.hilt.android.ViewModelLifecycle
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.android.scopes.ViewModelScoped
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancelAndJoin

@ -13,7 +13,6 @@ import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import coil3.ImageLoader
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.koitharu.kotatsu.R
@ -49,9 +48,6 @@ class SourcesManageFragment :
SourceConfigListener,
RecyclerViewOwner {
@Inject
lateinit var coil: ImageLoader
@Inject
lateinit var settings: AppSettings
@ -75,7 +71,7 @@ class SourcesManageFragment :
savedInstanceState: Bundle?,
) {
super.onViewBindingCreated(binding, savedInstanceState)
sourcesAdapter = SourceConfigAdapter(this, coil, viewLifecycleOwner)
sourcesAdapter = SourceConfigAdapter(this)
with(binding.recyclerView) {
setHasFixedSize(true)
adapter = sourcesAdapter

@ -62,7 +62,7 @@ class MangaDirectoriesActivity : BaseActivity<ActivityMangaDirectoriesBinding>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityMangaDirectoriesBinding.inflate(layoutInflater))
setDisplayHomeAsUp(true, false)
setDisplayHomeAsUp(isEnabled = true, showUpAsClose = false)
val adapter = AsyncListDifferDelegationAdapter(DirectoryDiffCallback(), directoryConfigAD(this))
viewBinding.recyclerView.adapter = adapter
viewBinding.fabAdd.setOnClickListener(this)

@ -7,6 +7,7 @@ import android.util.AttributeSet
import androidx.preference.ListPreference
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
@Suppress("unused")
class ActivityListPreference : ListPreference {
var activityIntent: Intent? = null

@ -11,6 +11,7 @@ import android.view.View
import android.view.ViewTreeObserver
import android.widget.HorizontalScrollView
import androidx.appcompat.view.ContextThemeWrapper
import androidx.core.view.isEmpty
import androidx.core.view.isVisible
import androidx.core.view.updatePaddingRelative
import androidx.customview.view.AbsSavedState
@ -55,7 +56,7 @@ class ThemeChooserPreference @JvmOverloads constructor(
val context = ContextThemeWrapper(context, theme.styleResId)
val item =
ItemColorSchemeBinding.inflate(LayoutInflater.from(context), binding.linear, false)
if (binding.linear.childCount == 0) {
if (binding.linear.isEmpty()) {
item.root.updatePaddingRelative(start = 0)
}
val isSelected = theme == currentValue

@ -16,7 +16,6 @@ import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePaddingRelative
import androidx.recyclerview.widget.AsyncListDiffer
import coil3.ImageLoader
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipDrawable
import dagger.hilt.android.AndroidEntryPoint
@ -42,7 +41,6 @@ import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.stats.domain.StatsPeriod
import org.koitharu.kotatsu.stats.domain.StatsRecord
import org.koitharu.kotatsu.stats.ui.views.PieChartView
import javax.inject.Inject
@AndroidEntryPoint
class StatsActivity : BaseActivity<ActivityStatsBinding>(),
@ -53,15 +51,12 @@ class StatsActivity : BaseActivity<ActivityStatsBinding>(),
View.OnClickListener,
CompoundButton.OnCheckedChangeListener {
@Inject
lateinit var coil: ImageLoader
private val viewModel: StatsViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityStatsBinding.inflate(layoutInflater))
setDisplayHomeAsUp(true, false)
setDisplayHomeAsUp(isEnabled = true, showUpAsClose = false)
val adapter = BaseListAdapter<StatsRecord>()
.addDelegate(ListItemType.FEED, statsAD(this))
.addListListener(this)

@ -1,6 +1,5 @@
package org.koitharu.kotatsu.stats.ui.sheet
import androidx.collection.IntList
import androidx.collection.MutableIntList
import androidx.collection.emptyIntList
import androidx.lifecycle.SavedStateHandle
@ -26,7 +25,7 @@ class MangaStatsViewModel @Inject constructor(
val manga = savedStateHandle.require<ParcelableManga>(AppRouter.KEY_MANGA).manga
val stats = MutableStateFlow<IntList>(emptyIntList())
val stats = MutableStateFlow(emptyIntList())
val startDate = MutableStateFlow<DateTimeAgo?>(null)
val totalPagesRead = MutableStateFlow(0)

@ -9,10 +9,10 @@ import android.content.OperationApplicationException
import android.content.SyncResult
import android.content.SyncStats
import android.database.Cursor
import android.net.Uri
import android.util.Log
import androidx.annotation.WorkerThread
import androidx.core.content.contentValuesOf
import androidx.core.net.toUri
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@ -288,7 +288,7 @@ class SyncHelper @AssistedInject constructor(
?: throw OperationApplicationException("Query failed: $uri")
}
private fun uri(authority: String, table: String) = Uri.parse("content://$authority/$table")
private fun uri(authority: String, table: String) = "content://$authority/$table".toUri()
private fun JSONObject.removeJSONObject(name: String) = remove(name) as JSONObject

@ -5,7 +5,6 @@ import android.view.View
import androidx.activity.viewModels
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import coil3.ImageLoader
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.core.nav.router
import org.koitharu.kotatsu.core.ui.BaseActivity
@ -17,20 +16,16 @@ import org.koitharu.kotatsu.core.util.ext.systemBarsInsets
import org.koitharu.kotatsu.databinding.ActivityTrackerDebugBinding
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
import org.koitharu.kotatsu.list.ui.adapter.TypedListSpacingDecoration
import javax.inject.Inject
@AndroidEntryPoint
class TrackerDebugActivity : BaseActivity<ActivityTrackerDebugBinding>(), OnListItemClickListener<TrackDebugItem> {
@Inject
lateinit var coil: ImageLoader
private val viewModel by viewModels<TrackerDebugViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityTrackerDebugBinding.inflate(layoutInflater))
setDisplayHomeAsUp(true, false)
setDisplayHomeAsUp(isEnabled = true, showUpAsClose = false)
val tracksAdapter = BaseListAdapter<TrackDebugItem>()
.addDelegate(ListItemType.FEED, trackDebugAD(this))
with(viewBinding.recyclerView) {

@ -23,7 +23,7 @@ class RecentWidgetConfigActivity :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityAppwidgetRecentBinding.inflate(layoutInflater))
setDisplayHomeAsUp(true, true)
setDisplayHomeAsUp(isEnabled = true, showUpAsClose = true)
viewBinding.buttonDone.setOnClickListener(this)
val appWidgetId = intent?.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,

@ -5,9 +5,9 @@ import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.net.Uri
import android.widget.RemoteViews
import androidx.core.app.PendingIntentCompat
import androidx.core.net.toUri
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.nav.ReaderIntent
import org.koitharu.kotatsu.core.prefs.AppWidgetConfig
@ -34,7 +34,7 @@ class RecentWidgetProvider : BaseAppWidgetProvider() {
}
val adapter = Intent(context, RecentWidgetService::class.java)
adapter.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, config.widgetId)
adapter.data = Uri.parse(adapter.toUri(Intent.URI_INTENT_SCHEME))
adapter.data = adapter.toUri(Intent.URI_INTENT_SCHEME).toUri()
views.setRemoteAdapter(R.id.stackView, adapter)
val intent = Intent(context, ReaderActivity::class.java)
intent.action = ReaderIntent.ACTION_MANGA_READ

@ -35,7 +35,7 @@ class ShelfWidgetConfigActivity :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(ActivityAppwidgetShelfBinding.inflate(layoutInflater))
setDisplayHomeAsUp(true, true)
setDisplayHomeAsUp(isEnabled = true, showUpAsClose = true)
adapter = CategorySelectAdapter(this)
viewBinding.recyclerView.adapter = adapter
viewBinding.buttonDone.setOnClickListener(this)

@ -5,9 +5,9 @@ import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.net.Uri
import android.widget.RemoteViews
import androidx.core.app.PendingIntentCompat
import androidx.core.net.toUri
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.nav.ReaderIntent
import org.koitharu.kotatsu.core.prefs.AppWidgetConfig
@ -34,7 +34,7 @@ class ShelfWidgetProvider : BaseAppWidgetProvider() {
}
val adapter = Intent(context, ShelfWidgetService::class.java)
adapter.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, config.widgetId)
adapter.data = Uri.parse(adapter.toUri(Intent.URI_INTENT_SCHEME))
adapter.data = adapter.toUri(Intent.URI_INTENT_SCHEME).toUri()
views.setRemoteAdapter(R.id.gridView, adapter)
val intent = Intent(context, ReaderActivity::class.java)
intent.action = ReaderIntent.ACTION_MANGA_READ

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="0.2" android:color="@color/kotatsu_primary" />
</selector>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/kotatsu_secondaryContainer" android:state_checked="true" />
<item android:color="@color/kotatsu_onSurfaceVariant" android:state_checked="false" />
</selector>

@ -1,11 +0,0 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="60dp"
android:height="60dp"
android:tint="?attr/colorTertiary"
android:viewportWidth="60"
android:viewportHeight="60">
<path
android:fillColor="#FF000000"
android:pathData="M21.7,40c-0.4,0 -0.8,-0.2 -1.2,-0.5c-0.3,-0.3 -0.5,-0.7 -0.5,-1.2V21.7c0,-0.4 0.2,-0.8 0.5,-1.2s0.7,-0.5 1.2,-0.5h16.7c0.4,0 0.8,0.2 1.2,0.5s0.5,0.7 0.5,1.2v16.7c0,0.4 -0.2,0.8 -0.5,1.2c-0.3,0.3 -0.7,0.5 -1.2,0.5H21.7zM22.9,31.3l4.8,-4.8l4.7,4.7l4.8,-4.8l1.2,1.2v-6H21.7v8.4L22.9,31.3zM21.7,38.4h16.7v-8.3l-1.2,-1.2l-4.8,4.8l-4.7,-4.7l-4.8,4.8l-1.2,-1.2V38.4zM21.7,38.4v-8.3v1.7V21.7V38.4z" />
</vector>

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000000"
android:pathData="M17,12A5,5 0 0,1 12,17A5,5 0 0,1 7,12C7,9.58 8.72,7.56 11,7.1V3H13V7.1C15.28,7.56 17,9.58 17,12M12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9Z" />
</vector>

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000000"
android:pathData="M7,12A5,5 0 0,1 12,7A5,5 0 0,1 17,12C17,14.42 15.28,16.44 13,16.9V21H11V16.9C8.72,16.44 7,14.42 7,12M12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15M13,3V5H11V3H13Z" />
</vector>

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000000"
android:pathData="M12,7A5,5 0 0,1 17,12C17,14.42 15.28,16.44 13,16.9V21H11V16.9C8.72,16.44 7,14.42 7,12A5,5 0 0,1 12,7M12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9Z" />
</vector>

@ -64,7 +64,7 @@
app:fabSize="normal"
app:layout_anchor="@id/recyclerView"
app:layout_anchorGravity="bottom|end"
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
app:layout_behavior="com.google.android.material.behavior.HideViewOnScrollBehavior"
app:layout_dodgeInsetEdges="bottom" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

@ -13,6 +13,7 @@
android:layout_height="@dimen/category_covers_height"
android:layout_marginStart="@dimen/screen_padding"
app:coverSize="3.4dp"
app:hideEmptyViews="true"
app:layout_constraintDimensionRatio="13:18"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_clear"

@ -31,6 +31,7 @@
<declare-styleable name="CoverStackView">
<attr name="coverSize" format="dimension" />
<attr name="hideEmptyViews" format="boolean" />
</declare-styleable>
<declare-styleable name="FaviconView">

@ -17,7 +17,7 @@ diskLruCache = "1.5"
fragment = "1.8.6"
gradle = "8.9.1"
guava = "33.4.8-android"
dagger = "2.56.1"
dagger = "2.56.2"
hilt = "1.2.0"
json = "20250107"
junit = "4.13.2"
@ -27,22 +27,22 @@ ksp = "2.1.20-2.0.0"
leakcanary = "3.0-alpha-8"
lifecycle = "2.8.7"
markwon = "4.6.2"
material = "1.13.0-alpha12"
material = "1.13.0-alpha13"
moshi = "1.15.2"
okhttp = "4.12.0"
okio = "3.11.0"
parsers = "e874837efb"
preference = "1.2.1"
recyclerview = "1.4.0"
room = "2.7.0"
room = "2.7.1"
ssiv = "9a67b6a7c9"
swiperefreshlayout = "1.1.0"
testRules = "1.6.1"
testRunner = "1.6.2"
transition = "1.5.1"
transition = "1.6.0"
viewpager2 = "1.1.0"
webkit = "1.13.0"
workRuntime = "2.10.0"
workRuntime = "2.10.1"
workinspector = "1.2"
[libraries]

Loading…
Cancel
Save