mirror of
https://github.com/mihonapp/mihon.git
synced 2024-11-06 02:37:26 +01:00
Compare commits
10 Commits
6863ac9a9b
...
4f874fcbca
Author | SHA1 | Date | |
---|---|---|---|
|
4f874fcbca | ||
|
9580a00aa6 | ||
|
cb2b0464d0 | ||
|
ef7992f912 | ||
|
261bbef997 | ||
|
a5349a881b | ||
|
2ca2cec02b | ||
|
2f4bb7cadb | ||
|
bb4d9fc81a | ||
|
ee134fce58 |
2
.github/workflows/build_push.yml
vendored
2
.github/workflows/build_push.yml
vendored
@ -95,7 +95,7 @@ jobs:
|
||||
|
||||
- name: Create Release
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.repository == 'mihonapp/mihon'
|
||||
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8
|
||||
uses: softprops/action-gh-release@e7a8f85e1c67a31e6ed99a94b41bd0b71bbee6b8 # v2.0.9
|
||||
with:
|
||||
tag_name: ${{ env.VERSION_TAG }}
|
||||
name: Mihon ${{ env.VERSION_TAG }}
|
||||
|
@ -18,6 +18,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
|
||||
- Fixed "currentTab was used multiple times"
|
||||
- Fixed a rare crash when invoking "Mark previous as read" action
|
||||
- Fixed long strip images not loading in some old devices
|
||||
- Added option to always use SSIV for image decoding
|
||||
|
||||
### Improved
|
||||
- Bangumi search now shows the score and summary of a search result ([@MajorTanya](https://github.com/MajorTanya)) ([#1396](https://github.com/mihonapp/mihon/pull/1396))
|
||||
|
@ -68,7 +68,7 @@ The developer(s) of this application does not have any affiliation with the cont
|
||||
|
||||
<pre>
|
||||
Copyright © 2015 Javier Tomás
|
||||
Copyright © 2024 The Mihon Open Source Project
|
||||
Copyright © 2024 Mihon Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -1,5 +1,6 @@
|
||||
package eu.kanade.core.util
|
||||
|
||||
import androidx.compose.ui.util.fastFilter
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
@ -45,21 +46,6 @@ fun <E> HashSet<E>.addOrRemove(value: E, shouldAdd: Boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing only elements matching the given [predicate].
|
||||
*
|
||||
* **Do not use for collections that come from public APIs**, since they may not support random
|
||||
* access in an efficient way, and this method may actually be a lot slower. Only use for
|
||||
* collections that are created by code we control and are known to support random access.
|
||||
*/
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun <T> List<T>.fastFilter(predicate: (T) -> Boolean): List<T> {
|
||||
contract { callsInPlace(predicate) }
|
||||
val destination = ArrayList<T>()
|
||||
fastForEach { if (predicate(it)) destination.add(it) }
|
||||
return destination
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all elements not matching the given [predicate].
|
||||
*
|
||||
@ -70,27 +56,7 @@ inline fun <T> List<T>.fastFilter(predicate: (T) -> Boolean): List<T> {
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun <T> List<T>.fastFilterNot(predicate: (T) -> Boolean): List<T> {
|
||||
contract { callsInPlace(predicate) }
|
||||
val destination = ArrayList<T>()
|
||||
fastForEach { if (!predicate(it)) destination.add(it) }
|
||||
return destination
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing only the non-null results of applying the
|
||||
* given [transform] function to each element in the original collection.
|
||||
*
|
||||
* **Do not use for collections that come from public APIs**, since they may not support random
|
||||
* access in an efficient way, and this method may actually be a lot slower. Only use for
|
||||
* collections that are created by code we control and are known to support random access.
|
||||
*/
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun <T, R> List<T>.fastMapNotNull(transform: (T) -> R?): List<R> {
|
||||
contract { callsInPlace(transform) }
|
||||
val destination = ArrayList<R>()
|
||||
fastForEach { element ->
|
||||
transform(element)?.let(destination::add)
|
||||
}
|
||||
return destination
|
||||
return fastFilter { !predicate(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,26 +97,3 @@ inline fun <T> List<T>.fastCountNot(predicate: (T) -> Boolean): Int {
|
||||
fastForEach { if (predicate(it)) --count }
|
||||
return count
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing only elements from the given collection
|
||||
* having distinct keys returned by the given [selector] function.
|
||||
*
|
||||
* Among elements of the given collection with equal keys, only the first one will be present in the resulting list.
|
||||
* The elements in the resulting list are in the same order as they were in the source collection.
|
||||
*
|
||||
* **Do not use for collections that come from public APIs**, since they may not support random
|
||||
* access in an efficient way, and this method may actually be a lot slower. Only use for
|
||||
* collections that are created by code we control and are known to support random access.
|
||||
*/
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun <T, K> List<T>.fastDistinctBy(selector: (T) -> K): List<T> {
|
||||
contract { callsInPlace(selector) }
|
||||
val set = HashSet<K>()
|
||||
val list = ArrayList<T>()
|
||||
fastForEach {
|
||||
val key = selector(it)
|
||||
if (set.add(key)) list.add(it)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
@ -30,4 +30,6 @@ class BasePreferences(
|
||||
}
|
||||
|
||||
fun displayProfile() = preferenceStore.getString("pref_display_profile_key", "")
|
||||
|
||||
fun alwaysUseSSIVToDecode() = preferenceStore.getBoolean("pref_always_use_ssiv_to_decode", false)
|
||||
}
|
||||
|
@ -341,6 +341,10 @@ object SettingsAdvancedScreen : SearchableSettings {
|
||||
chooseColorProfile.launch(arrayOf("*/*"))
|
||||
},
|
||||
),
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = basePreferences.alwaysUseSSIVToDecode(),
|
||||
title = stringResource(MR.strings.pref_always_use_ssiv_to_decode),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -81,13 +81,12 @@ data class SourceSearchScreen(
|
||||
},
|
||||
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
||||
) { paddingValues ->
|
||||
val pagingFlow by screenModel.mangaPagerFlowFlow.collectAsState()
|
||||
val openMigrateDialog: (Manga) -> Unit = {
|
||||
screenModel.setDialog(BrowseSourceScreenModel.Dialog.Migrate(newManga = it, oldManga = oldManga))
|
||||
}
|
||||
BrowseSourceContent(
|
||||
source = screenModel.source,
|
||||
mangaList = pagingFlow.collectAsLazyPagingItems(),
|
||||
mangaList = screenModel.mangaPagerFlow.collectAsLazyPagingItems(),
|
||||
columns = screenModel.getColumnsPreference(LocalConfiguration.current.orientation),
|
||||
displayMode = screenModel.displayMode,
|
||||
snackbarHostState = snackbarHostState,
|
||||
|
@ -206,11 +206,9 @@ data class BrowseSourceScreen(
|
||||
},
|
||||
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
||||
) { paddingValues ->
|
||||
val pagingFlow by screenModel.mangaPagerFlowFlow.collectAsState()
|
||||
|
||||
BrowseSourceContent(
|
||||
source = screenModel.source,
|
||||
mangaList = pagingFlow.collectAsLazyPagingItems(),
|
||||
mangaList = screenModel.mangaPagerFlow.collectAsLazyPagingItems(),
|
||||
columns = screenModel.getColumnsPreference(LocalConfiguration.current.orientation),
|
||||
displayMode = screenModel.displayMode,
|
||||
snackbarHostState = snackbarHostState,
|
||||
|
@ -26,11 +26,10 @@ import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
@ -106,9 +105,9 @@ class BrowseSourceScreenModel(
|
||||
* Flow of Pager flow tied to [State.listing]
|
||||
*/
|
||||
private val hideInLibraryItems = sourcePreferences.hideInLibraryItems().get()
|
||||
val mangaPagerFlowFlow = state.map { it.listing }
|
||||
val mangaPagerFlow = state.map { it.listing }
|
||||
.distinctUntilChanged()
|
||||
.map { listing ->
|
||||
.flatMapLatest { listing ->
|
||||
Pager(PagingConfig(pageSize = 25)) {
|
||||
getRemoteManga.subscribe(sourceId, listing.query ?: "", listing.filters)
|
||||
}.flow.map { pagingData ->
|
||||
@ -120,9 +119,8 @@ class BrowseSourceScreenModel(
|
||||
}
|
||||
.filter { !hideInLibraryItems || !it.value.favorite }
|
||||
}
|
||||
.cachedIn(ioCoroutineScope)
|
||||
}
|
||||
.stateIn(ioCoroutineScope, SharingStarted.Lazily, emptyFlow())
|
||||
.cachedIn(ioCoroutineScope)
|
||||
|
||||
fun getColumnsPreference(orientation: Int): GridCells {
|
||||
val isLandscape = orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||
|
@ -4,15 +4,15 @@ import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.util.fastAny
|
||||
import androidx.compose.ui.util.fastDistinctBy
|
||||
import androidx.compose.ui.util.fastFilter
|
||||
import androidx.compose.ui.util.fastMap
|
||||
import androidx.compose.ui.util.fastMapNotNull
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import eu.kanade.core.preference.PreferenceMutableState
|
||||
import eu.kanade.core.preference.asState
|
||||
import eu.kanade.core.util.fastDistinctBy
|
||||
import eu.kanade.core.util.fastFilter
|
||||
import eu.kanade.core.util.fastFilterNot
|
||||
import eu.kanade.core.util.fastMapNotNull
|
||||
import eu.kanade.core.util.fastPartition
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.domain.chapter.interactor.SetReadStatus
|
||||
|
@ -33,6 +33,7 @@ import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView.EASE_IN_OUT
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView.EASE_OUT_QUAD
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE
|
||||
import com.github.chrisbanes.photoview.PhotoView
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.tachiyomi.data.coil.cropBorders
|
||||
import eu.kanade.tachiyomi.data.coil.customDecoder
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonSubsamplingImageView
|
||||
@ -41,6 +42,8 @@ import eu.kanade.tachiyomi.util.system.animatorDurationScale
|
||||
import eu.kanade.tachiyomi.util.view.isVisibleOnScreen
|
||||
import okio.BufferedSource
|
||||
import tachiyomi.core.common.util.system.ImageUtil
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
/**
|
||||
* A wrapper view for showing page image.
|
||||
@ -58,6 +61,8 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||
private val isWebtoon: Boolean = false,
|
||||
) : FrameLayout(context, attrs, defStyleAttrs, defStyleRes) {
|
||||
|
||||
private val alwaysUseSSIVToDecode by lazy { Injekt.get<BasePreferences>().alwaysUseSSIVToDecode().get() }
|
||||
|
||||
private var pageView: View? = null
|
||||
|
||||
private var config: Config? = null
|
||||
@ -295,7 +300,7 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||
isVisible = true
|
||||
}
|
||||
is BufferedSource -> {
|
||||
if (!isWebtoon || !ImageUtil.canUseCoilToDecode(data)) {
|
||||
if (alwaysUseSSIVToDecode || !isWebtoon || !ImageUtil.canUseCoilToDecode(data)) {
|
||||
setImage(ImageSource.inputStream(data.inputStream()))
|
||||
isVisible = true
|
||||
} else {
|
||||
|
@ -1,12 +1,12 @@
|
||||
package eu.kanade.tachiyomi.ui.stats
|
||||
|
||||
import androidx.compose.ui.util.fastDistinctBy
|
||||
import androidx.compose.ui.util.fastFilter
|
||||
import androidx.compose.ui.util.fastMapNotNull
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import eu.kanade.core.util.fastCountNot
|
||||
import eu.kanade.core.util.fastDistinctBy
|
||||
import eu.kanade.core.util.fastFilter
|
||||
import eu.kanade.core.util.fastFilterNot
|
||||
import eu.kanade.core.util.fastMapNotNull
|
||||
import eu.kanade.presentation.more.stats.StatsScreenState
|
||||
import eu.kanade.presentation.more.stats.data.StatsData
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
|
@ -1,5 +1,5 @@
|
||||
[versions]
|
||||
agp_version = "8.7.1"
|
||||
agp_version = "8.7.2"
|
||||
lifecycle_version = "2.8.7"
|
||||
paging_version = "3.3.2"
|
||||
interpolator_version = "1.0.0"
|
||||
@ -11,7 +11,7 @@ annotation = "androidx.annotation:annotation:1.9.1"
|
||||
appcompat = "androidx.appcompat:appcompat:1.7.0"
|
||||
biometricktx = "androidx.biometric:biometric-ktx:1.2.0-alpha05"
|
||||
constraintlayout = "androidx.constraintlayout:constraintlayout:2.2.0"
|
||||
corektx = "androidx.core:core-ktx:1.13.1"
|
||||
corektx = "androidx.core:core-ktx:1.15.0"
|
||||
splashscreen = "androidx.core:core-splashscreen:1.0.1"
|
||||
recyclerview = "androidx.recyclerview:recyclerview:1.3.2"
|
||||
viewpager = "androidx.viewpager:viewpager:1.1.0-beta01"
|
||||
|
@ -1,5 +1,5 @@
|
||||
[versions]
|
||||
compose-bom = "2024.10.00"
|
||||
compose-bom = "2024.10.01"
|
||||
|
||||
[libraries]
|
||||
activity = "androidx.activity:activity-compose:1.9.3"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[versions]
|
||||
kotlin_version = "2.0.21"
|
||||
serialization_version = "1.7.3"
|
||||
xml_serialization_version = "0.90.2"
|
||||
xml_serialization_version = "0.90.3"
|
||||
|
||||
[libraries]
|
||||
reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin_version" }
|
||||
|
@ -42,7 +42,7 @@ preferencektx = "androidx.preference:preference-ktx:1.2.1"
|
||||
|
||||
injekt = "com.github.mihonapp:injekt:91edab2317"
|
||||
|
||||
coil-bom = { module = "io.coil-kt.coil3:coil-bom", version = "3.0.0-rc02" }
|
||||
coil-bom = { module = "io.coil-kt.coil3:coil-bom", version = "3.0.0" }
|
||||
coil-core = { module = "io.coil-kt.coil3:coil" }
|
||||
coil-gif = { module = "io.coil-kt.coil3:coil-gif" }
|
||||
coil-compose = { module = "io.coil-kt.coil3:coil-compose" }
|
||||
|
@ -392,6 +392,7 @@
|
||||
<string name="pref_show_reading_mode">Show reading mode</string>
|
||||
<string name="pref_show_reading_mode_summary">Briefly show current mode when reader is opened</string>
|
||||
<string name="pref_display_profile">Custom display profile</string>
|
||||
<string name="pref_always_use_ssiv_to_decode">Always use SSIV to decode long strip images</string>
|
||||
<string name="pref_crop_borders">Crop borders</string>
|
||||
<string name="pref_custom_brightness">Custom brightness</string>
|
||||
<string name="pref_grayscale">Grayscale</string>
|
||||
|
Loading…
Reference in New Issue
Block a user