Extract common utils (#2620)

* Extract common utils

* Fix lint
This commit is contained in:
FooIbar authored and GitHub committed 2025-09-25 17:49:06 +08:00
1 parent feba6dfeb0
commit a8eb4ce47a
94 files changed
+421 -404

No files matched your search

-2
View File
@@ -216,8 +216,6 @@ dependencies {
// https://square.github.io/okhttp/changelogs/changelog/
implementation(platform(libs.okhttp.bom))
implementation(platform(libs.okio.bom))
implementation(libs.logcat)
implementation(libs.diff)
@@ -1,161 +0,0 @@
/*
* Copyright 2022 The Android 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.accompanist.systemuicontroller
import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.view.View
import android.view.Window
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.window.DialogWindowProvider
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
/**
* A class which provides easy-to-use utilities for updating the System UI bar
* colors within Jetpack Compose.
*/
@Stable
interface SystemUiController {
/**
* Control for the behavior of the system bars. This value should be one of the
* [WindowInsetsControllerCompat] behavior constants:
* [WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH] (Deprecated),
* [WindowInsetsControllerCompat.BEHAVIOR_DEFAULT] and
* [WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE].
*/
var systemBarsBehavior: Int
/**
* Property which holds the status bar visibility. If set to true, show the status bar,
* otherwise hide the status bar.
*/
var isStatusBarVisible: Boolean
/**
* Property which holds the navigation bar visibility. If set to true, show the navigation bar,
* otherwise hide the navigation bar.
*/
var isNavigationBarVisible: Boolean
/**
* Property which holds the status & navigation bar visibility. If set to true, show both bars,
* otherwise hide both bars.
*/
var isSystemBarsVisible: Boolean
get() = isNavigationBarVisible && isStatusBarVisible
set(value) {
isStatusBarVisible = value
isNavigationBarVisible = value
}
/**
* Property which holds whether the status bar icons + content are 'dark' or not.
*/
var statusBarDarkContentEnabled: Boolean
}
/**
* Remembers a [SystemUiController] for the given [window].
*
* If no [window] is provided, an attempt to find the correct [Window] is made.
*
* First, if the [LocalView]'s parent is a [DialogWindowProvider], then that dialog's [Window] will
* be used.
*
* Second, we attempt to find [Window] for the [Activity] containing the [LocalView].
*
* If none of these are found (such as may happen in a preview), then the functionality of the
* returned [SystemUiController] will be degraded, but won't throw an exception.
*/
@Composable
fun rememberSystemUiController(
window: Window? = findWindow(),
): SystemUiController {
val view = LocalView.current
return remember(view, window) { AndroidSystemUiController(view, window) }
}
@Composable
private fun findWindow(): Window? = (LocalView.current.parent as? DialogWindowProvider)?.window
?: LocalView.current.context.findWindow()
private tailrec fun Context.findWindow(): Window? = when (this) {
is Activity -> window
is ContextWrapper -> baseContext.findWindow()
else -> null
}
/**
* A helper class for setting the navigation and status bar colors for a [View], gracefully
* degrading behavior based upon API level.
*
* Typically you would use [rememberSystemUiController] to remember an instance of this.
*/
internal class AndroidSystemUiController(
private val view: View,
window: Window?,
) : SystemUiController {
private val windowInsetsController = window?.let {
WindowCompat.getInsetsController(it, view)
}
override var systemBarsBehavior: Int
get() = windowInsetsController?.systemBarsBehavior ?: 0
set(value) {
windowInsetsController?.systemBarsBehavior = value
}
override var isStatusBarVisible: Boolean
get() {
return ViewCompat.getRootWindowInsets(view)
?.isVisible(WindowInsetsCompat.Type.statusBars()) == true
}
set(value) {
if (value) {
windowInsetsController?.show(WindowInsetsCompat.Type.statusBars())
} else {
windowInsetsController?.hide(WindowInsetsCompat.Type.statusBars())
}
}
override var isNavigationBarVisible: Boolean
get() {
return ViewCompat.getRootWindowInsets(view)
?.isVisible(WindowInsetsCompat.Type.navigationBars()) == true
}
set(value) {
if (value) {
windowInsetsController?.show(WindowInsetsCompat.Type.navigationBars())
} else {
windowInsetsController?.hide(WindowInsetsCompat.Type.navigationBars())
}
}
override var statusBarDarkContentEnabled: Boolean
get() = windowInsetsController?.isAppearanceLightStatusBars == true
set(value) {
windowInsetsController?.isAppearanceLightStatusBars = value
}
}
@@ -38,8 +38,14 @@ import coil3.request.allowRgb565
import coil3.request.crossfade
import coil3.serviceLoaderEnabled
import coil3.util.DebugLogger
import com.ehviewer.core.files.deleteContent
import com.ehviewer.core.ui.util.initSETConnection
import com.ehviewer.core.util.isAtLeastO
import com.ehviewer.core.util.isAtLeastP
import com.ehviewer.core.util.isAtLeastS
import com.ehviewer.core.util.isAtLeastSExtension7
import com.ehviewer.core.util.launchIO
import com.ehviewer.core.util.logcat
import com.ehviewer.core.util.withUIContext
import com.hippo.ehviewer.client.EhTagDatabase
import com.hippo.ehviewer.coil.AnimatedWebPDecoder
@@ -68,12 +74,6 @@ import com.hippo.ehviewer.util.CrashHandler
import com.hippo.ehviewer.util.FavouriteStatusRouter
import com.hippo.ehviewer.util.FileUtils
import com.hippo.ehviewer.util.OSUtils
import com.hippo.ehviewer.util.isAtLeastO
import com.hippo.ehviewer.util.isAtLeastP
import com.hippo.ehviewer.util.isAtLeastS
import com.hippo.ehviewer.util.isAtLeastSExtension7
import com.hippo.files.deleteContent
import eu.kanade.tachiyomi.util.system.logcat
import io.ktor.client.HttpClient
import io.ktor.client.engine.okhttp.OkHttp
import kotlinx.coroutines.Dispatchers
@@ -19,6 +19,7 @@ import android.content.Context
import android.net.Uri
import arrow.fx.coroutines.resource
import arrow.fx.coroutines.resourceScope
import com.ehviewer.core.files.sendTo
import com.hippo.ehviewer.client.data.BaseGalleryInfo
import com.hippo.ehviewer.dao.DownloadArtist
import com.hippo.ehviewer.dao.DownloadDirname
@@ -32,7 +33,6 @@ import com.hippo.ehviewer.dao.ProgressInfo
import com.hippo.ehviewer.dao.QuickSearch
import com.hippo.ehviewer.dao.Schema17to18
import com.hippo.ehviewer.download.DownloadManager
import com.hippo.ehviewer.util.sendTo
import kotlinx.coroutines.flow.Flow
import okio.Path
import okio.Path.Companion.toOkioPath
@@ -4,13 +4,13 @@ import android.app.UiModeManager
import androidx.appcompat.app.AppCompatDelegate
import arrow.core.Either.Companion.catch
import com.ehviewer.core.preferences.PrefDelegate
import com.ehviewer.core.util.isAtLeastS
import com.ehviewer.core.util.logcat
import com.ehviewer.core.util.withIOContext
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhTagDatabase
import com.hippo.ehviewer.dailycheck.updateDailyCheckWork
import com.hippo.ehviewer.ui.keepNoMediaFileStatus
import com.hippo.ehviewer.util.isAtLeastS
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
@@ -22,6 +22,7 @@ import arrow.core.right
import arrow.fx.coroutines.parMap
import arrow.fx.coroutines.parZip
import com.ehviewer.core.i18n.R
import com.ehviewer.core.util.logcat
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.data.BaseGalleryInfo
@@ -61,7 +62,6 @@ import com.hippo.ehviewer.util.AppConfig
import com.hippo.ehviewer.util.ReadableTime
import com.hippo.ehviewer.util.bodyAsUtf8Text
import com.hippo.ehviewer.util.ensureSuccess
import eu.kanade.tachiyomi.util.system.logcat
import io.ktor.client.statement.HttpResponse
import io.ktor.client.statement.HttpStatement
import io.ktor.client.statement.bodyAsChannel
@@ -15,11 +15,11 @@
*/
package com.hippo.ehviewer.client
import com.ehviewer.core.util.logcat
import com.hippo.ehviewer.EhApplication.Companion.ktorClient
import com.hippo.ehviewer.EhApplication.Companion.noRedirectKtorClient
import com.hippo.ehviewer.util.bodyAsUtf8Text
import com.hippo.ehviewer.util.ensureSuccess
import eu.kanade.tachiyomi.util.system.logcat
import io.ktor.client.request.HttpRequestBuilder
import io.ktor.client.request.forms.FormDataContent
import io.ktor.client.request.header
@@ -20,6 +20,10 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import arrow.core.Either
import com.ehviewer.core.files.metadataOrNull
import com.ehviewer.core.files.read
import com.ehviewer.core.files.write
import com.ehviewer.core.util.logcat
import com.hippo.ehviewer.EhApplication.Companion.ktorClient
import com.hippo.ehviewer.R
import com.hippo.ehviewer.client.data.TagNamespace
@@ -27,10 +31,6 @@ import com.hippo.ehviewer.util.AppConfig
import com.hippo.ehviewer.util.bodyAsUtf8Text
import com.hippo.ehviewer.util.ensureSuccess
import com.hippo.ehviewer.util.utf8
import com.hippo.files.metadataOrNull
import com.hippo.files.read
import com.hippo.files.write
import eu.kanade.tachiyomi.util.system.logcat
import io.ktor.client.request.prepareGet
import kotlin.time.Clock
import kotlin.time.Duration.Companion.days
@@ -15,7 +15,7 @@
*/
package com.hippo.ehviewer.client.data
import moe.tarsin.kt.unreachable
import com.ehviewer.core.util.unreachable
interface GalleryInfo {
var gid: Long
@@ -1,7 +1,7 @@
package com.hippo.ehviewer.client.parser
import com.ehviewer.core.util.unescapeXml
import com.hippo.ehviewer.client.exception.ParseException
import com.hippo.ehviewer.util.unescapeXml
import java.nio.ByteBuffer
import kotlinx.serialization.Serializable
import moe.tarsin.coroutines.runSuspendCatching
@@ -15,11 +15,11 @@
*/
package com.hippo.ehviewer.client.parser
import com.ehviewer.core.util.unescapeXml
import com.hippo.ehviewer.client.EhUtils.getCategory
import com.hippo.ehviewer.client.data.GalleryInfo
import com.hippo.ehviewer.client.getThumbKey
import com.hippo.ehviewer.client.parseAs
import com.hippo.ehviewer.util.unescapeXml
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@@ -15,8 +15,8 @@
*/
package com.hippo.ehviewer.client.parser
import com.ehviewer.core.util.unescapeXml
import com.hippo.ehviewer.client.exception.ParseException
import com.hippo.ehviewer.util.unescapeXml
object GalleryPageParser {
private val PATTERN_IMAGE_URL = Regex("<img[^>]*src=\"([^\"]+)\" style")
@@ -15,9 +15,9 @@
*/
package com.hippo.ehviewer.client.parser
import com.hippo.ehviewer.util.toEpochMillis
import com.hippo.ehviewer.util.toIntOrDefault
import com.hippo.ehviewer.util.toLocalDateTime
import com.ehviewer.core.util.toEpochMillis
import com.ehviewer.core.util.toIntOrDefault
import com.ehviewer.core.util.toLocalDateTime
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.format.char
@@ -9,7 +9,7 @@ import android.graphics.drawable.Animatable
import android.graphics.drawable.Drawable
import android.os.SystemClock
import androidx.core.graphics.createBitmap
import eu.kanade.tachiyomi.util.system.logcat
import com.ehviewer.core.util.logcat
import java.nio.ByteBuffer
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
@@ -12,9 +12,9 @@ import coil3.asImage
import coil3.intercept.Interceptor
import coil3.request.ImageResult
import coil3.request.SuccessResult
import com.ehviewer.core.util.isAtLeastQ
import com.ehviewer.core.util.logcat
import com.hippo.ehviewer.image.copyBitmapToAHB
import com.hippo.ehviewer.util.isAtLeastQ
import eu.kanade.tachiyomi.util.system.logcat
import moe.tarsin.coroutines.runSuspendCatching
@RequiresApi(Build.VERSION_CODES.O)
@@ -6,16 +6,16 @@ import coil3.intercept.Interceptor
import coil3.request.ImageRequest
import coil3.request.ImageResult
import coil3.request.SuccessResult
import com.ehviewer.core.files.delete
import com.ehviewer.core.files.isDirectory
import com.ehviewer.core.files.isFile
import com.ehviewer.core.files.sendTo
import com.ehviewer.core.files.toUri
import com.hippo.ehviewer.EhApplication.Companion.imageCache
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.client.getThumbKey
import com.hippo.ehviewer.dao.DownloadInfo
import com.hippo.ehviewer.download.downloadLocation
import com.hippo.ehviewer.util.sendTo
import com.hippo.files.delete
import com.hippo.files.isDirectory
import com.hippo.files.isFile
import com.hippo.files.toUri
private val downloadInfoKey = Extras.Key<DownloadInfo?>(default = null)
@@ -19,11 +19,11 @@ import androidx.work.PeriodicWorkRequest
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import com.ehviewer.core.util.logcat
import com.ehviewer.core.util.withIOContext
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhEngine
import eu.kanade.tachiyomi.util.system.logcat
import java.time.Duration
import java.util.concurrent.TimeUnit
import kotlin.time.Clock
@@ -26,7 +26,13 @@ import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.core.util.size
import arrow.fx.coroutines.parMapNotNull
import com.ehviewer.core.files.delete
import com.ehviewer.core.files.find
import com.ehviewer.core.files.toOkioPath
import com.ehviewer.core.files.toUri
import com.ehviewer.core.preferences.edit
import com.ehviewer.core.util.logcat
import com.ehviewer.core.util.mapNotNull
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.data.BaseGalleryInfo
@@ -46,13 +52,7 @@ import com.hippo.ehviewer.spider.readCompatFromPath
import com.hippo.ehviewer.spider.toSimpleTags
import com.hippo.ehviewer.util.AppConfig
import com.hippo.ehviewer.util.insertWith
import com.hippo.ehviewer.util.mapNotNull
import com.hippo.ehviewer.util.runAssertingNotMainThread
import com.hippo.files.delete
import com.hippo.files.find
import com.hippo.files.toOkioPath
import com.hippo.files.toUri
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -32,6 +32,8 @@ import androidx.core.content.ContextCompat
import androidx.savedstate.serialization.decodeFromSavedState
import androidx.savedstate.serialization.encodeToSavedState
import com.ehviewer.core.i18n.R
import com.ehviewer.core.util.isAtLeastS
import com.ehviewer.core.util.logcat
import com.ehviewer.core.util.unsafeLazy
import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.client.data.BaseGalleryInfo
@@ -43,8 +45,6 @@ import com.hippo.ehviewer.dao.DownloadInfo
import com.hippo.ehviewer.ui.MainActivity
import com.hippo.ehviewer.util.FileUtils
import com.hippo.ehviewer.util.ReadableTime
import com.hippo.ehviewer.util.isAtLeastS
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
@@ -16,6 +16,8 @@
package com.hippo.ehviewer.gallery
import arrow.autoCloseScope
import com.ehviewer.core.files.openFileDescriptor
import com.ehviewer.core.util.logcat
import com.hippo.ehviewer.Settings.archivePasswds
import com.hippo.ehviewer.image.ImageSource
import com.hippo.ehviewer.image.byteBufferSource
@@ -29,8 +31,6 @@ import com.hippo.ehviewer.jni.providePassword
import com.hippo.ehviewer.jni.releaseByteBuffer
import com.hippo.ehviewer.util.FileUtils
import com.hippo.ehviewer.util.displayName
import com.hippo.files.openFileDescriptor
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.coroutineScope
import moe.tarsin.kt.install
import okio.Path
@@ -4,6 +4,7 @@ import androidx.collection.SieveCache
import androidx.collection.mutableIntObjectMapOf
import arrow.fx.coroutines.ExitCase
import arrow.fx.coroutines.bracketCase
import com.ehviewer.core.util.isAtLeastO
import com.ehviewer.core.util.withNonCancellableContext
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.Settings
@@ -13,7 +14,6 @@ import com.hippo.ehviewer.util.FileUtils
import com.hippo.ehviewer.util.OSUtils
import com.hippo.ehviewer.util.detectAds
import com.hippo.ehviewer.util.displayString
import com.hippo.ehviewer.util.isAtLeastO
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.atomics.AtomicInt
import kotlin.concurrent.read
@@ -36,6 +36,10 @@ import coil3.size.Dimension
import coil3.size.Precision
import coil3.size.Size
import coil3.size.SizeResolver
import com.ehviewer.core.files.openFileDescriptor
import com.ehviewer.core.files.toUri
import com.ehviewer.core.util.isAtLeastP
import com.ehviewer.core.util.isAtLeastU
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.coil.AnimatedWebPDrawable
import com.hippo.ehviewer.coil.BitmapImageWithExtraInfo
@@ -48,10 +52,6 @@ import com.hippo.ehviewer.jni.munmap
import com.hippo.ehviewer.jni.rewriteGifSource
import com.hippo.ehviewer.ktbuilder.execute
import com.hippo.ehviewer.ktbuilder.imageRequest
import com.hippo.ehviewer.util.isAtLeastP
import com.hippo.ehviewer.util.isAtLeastU
import com.hippo.files.openFileDescriptor
import com.hippo.files.toUri
import java.nio.ByteBuffer
import kotlin.concurrent.atomics.AtomicInt
import kotlin.concurrent.atomics.decrementAndFetch
@@ -1,6 +1,6 @@
package com.hippo.ehviewer.ktor
import com.hippo.ehviewer.util.isAtLeastQ
import com.ehviewer.core.util.isAtLeastQ
import io.ktor.client.engine.okhttp.OkHttpConfig
import okhttp3.AsyncDns
import okhttp3.android.AndroidAsyncDns
@@ -1,7 +1,7 @@
package com.hippo.ehviewer.legacy
import com.ehviewer.core.files.read
import com.hippo.ehviewer.spider.SpiderInfo
import com.hippo.files.read
import kotlinx.io.readLineStrict
import okio.Path
@@ -1,5 +1,7 @@
package com.hippo.ehviewer.spider
import com.ehviewer.core.files.read
import com.ehviewer.core.files.write
import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.client.data.GalleryDetail
import com.hippo.ehviewer.client.data.GalleryInfo
@@ -17,8 +19,6 @@ import com.hippo.ehviewer.client.data.TagNamespace.Male
import com.hippo.ehviewer.client.data.TagNamespace.Mixed
import com.hippo.ehviewer.client.data.TagNamespace.Other
import com.hippo.ehviewer.client.data.TagNamespace.Parody
import com.hippo.files.read
import com.hippo.files.write
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@@ -20,6 +20,16 @@ import arrow.fx.coroutines.autoCloseable
import arrow.fx.coroutines.closeable
import arrow.fx.coroutines.parMap
import arrow.fx.coroutines.resourceScope
import com.ehviewer.core.files.delete
import com.ehviewer.core.files.exists
import com.ehviewer.core.files.find
import com.ehviewer.core.files.isDirectory
import com.ehviewer.core.files.list
import com.ehviewer.core.files.mkdirs
import com.ehviewer.core.files.moveTo
import com.ehviewer.core.files.openFileDescriptor
import com.ehviewer.core.files.sendTo
import com.ehviewer.core.util.logcat
import com.hippo.ehviewer.EhApplication.Companion.imageCache as sCache
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.Settings
@@ -39,17 +49,7 @@ import com.hippo.ehviewer.image.PathSource
import com.hippo.ehviewer.jni.archiveFdBatch
import com.hippo.ehviewer.util.FileUtils
import com.hippo.ehviewer.util.copyTo
import com.hippo.ehviewer.util.sendTo
import com.hippo.ehviewer.util.sha1
import com.hippo.files.delete
import com.hippo.files.exists
import com.hippo.files.find
import com.hippo.files.isDirectory
import com.hippo.files.list
import com.hippo.files.mkdirs
import com.hippo.files.moveTo
import com.hippo.files.openFileDescriptor
import eu.kanade.tachiyomi.util.system.logcat
import io.ktor.client.statement.HttpResponse
import io.ktor.client.statement.bodyAsChannel
import io.ktor.client.statement.request
@@ -1,12 +1,12 @@
package com.hippo.ehviewer.spider
import com.ehviewer.core.files.read
import com.ehviewer.core.files.write
import com.ehviewer.core.util.logcat
import com.hippo.ehviewer.coil.edit
import com.hippo.ehviewer.coil.read
import com.hippo.ehviewer.ktbuilder.diskCache
import com.hippo.ehviewer.legacy.readLegacySpiderInfo
import com.hippo.files.read
import com.hippo.files.write
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.io.readByteArray
import kotlinx.serialization.Serializable
import kotlinx.serialization.cbor.Cbor
@@ -20,7 +20,9 @@ import androidx.annotation.IntDef
import arrow.core.Either
import arrow.core.getOrElse
import arrow.core.partially1
import com.ehviewer.core.files.find
import com.ehviewer.core.i18n.R
import com.ehviewer.core.util.logcat
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhUrl
@@ -32,8 +34,6 @@ import com.hippo.ehviewer.client.data.GalleryPreview
import com.hippo.ehviewer.client.exception.FatalException
import com.hippo.ehviewer.client.exception.QuotaExceededException
import com.hippo.ehviewer.util.displayString
import com.hippo.files.find
import eu.kanade.tachiyomi.util.system.logcat
import kotlin.concurrent.atomics.AtomicInt
import kotlin.concurrent.atomics.decrementAndFetch
import kotlin.concurrent.atomics.incrementAndFetch
@@ -35,8 +35,16 @@ import androidx.compose.material3.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.ehviewer.core.files.delete
import com.ehviewer.core.files.exists
import com.ehviewer.core.files.isDirectory
import com.ehviewer.core.files.write
import com.ehviewer.core.i18n.R
import com.ehviewer.core.ui.component.LabeledCheckbox
import com.ehviewer.core.util.isAtLeastT
import com.ehviewer.core.util.mapToLongArray
import com.ehviewer.core.util.toEpochMillis
import com.ehviewer.core.util.toLocalDateTime
import com.ehviewer.core.util.withIOContext
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.Settings
@@ -65,16 +73,8 @@ import com.hippo.ehviewer.ui.tools.awaitSelectItemWithIcon
import com.hippo.ehviewer.ui.tools.awaitSelectItemWithIconAndTextField
import com.hippo.ehviewer.util.FavouriteStatusRouter
import com.hippo.ehviewer.util.bgWork
import com.hippo.ehviewer.util.isAtLeastT
import com.hippo.ehviewer.util.mapToLongArray
import com.hippo.ehviewer.util.requestPermission
import com.hippo.ehviewer.util.restartApplication
import com.hippo.ehviewer.util.toEpochMillis
import com.hippo.ehviewer.util.toLocalDateTime
import com.hippo.files.delete
import com.hippo.files.exists
import com.hippo.files.isDirectory
import com.hippo.files.write
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlin.time.Clock
import kotlinx.coroutines.sync.Mutex
@@ -20,8 +20,8 @@ import android.view.View
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.ActivityNavigator
import com.ehviewer.core.util.isAtLeastR
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.util.isAtLeastR
import eu.kanade.tachiyomi.util.view.setSecureScreen
abstract class EhActivity : AppCompatActivity() {
@@ -102,6 +102,8 @@ import androidx.core.net.toUri
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.navigation.compose.rememberNavController
import com.ehviewer.core.files.isDirectory
import com.ehviewer.core.files.toOkioPath
import com.ehviewer.core.i18n.R
import com.ehviewer.core.ui.component.LabeledCheckbox
import com.ehviewer.core.ui.component.LocalSideSheetState
@@ -110,6 +112,8 @@ import com.ehviewer.core.ui.icons.EhIcons
import com.ehviewer.core.ui.icons.filled.Subscriptions
import com.ehviewer.core.ui.util.LocalSnackBarFabPadding
import com.ehviewer.core.ui.util.LocalWindowSizeClass
import com.ehviewer.core.util.isAtLeastQ
import com.ehviewer.core.util.isAtLeastS
import com.ehviewer.core.util.withIOContext
import com.hippo.ehviewer.EhApplication.Companion.initialized
import com.hippo.ehviewer.Settings
@@ -144,11 +148,7 @@ import com.hippo.ehviewer.util.calculateFraction
import com.hippo.ehviewer.util.displayString
import com.hippo.ehviewer.util.getParcelableExtraCompat
import com.hippo.ehviewer.util.getUrlFromClipboard
import com.hippo.ehviewer.util.isAtLeastQ
import com.hippo.ehviewer.util.isAtLeastS
import com.hippo.ehviewer.util.sha1
import com.hippo.files.isDirectory
import com.hippo.files.toOkioPath
import com.ramcosta.composedestinations.DestinationsNavHost
import com.ramcosta.composedestinations.spec.Direction
import com.ramcosta.composedestinations.utils.currentDestinationAsState
@@ -14,10 +14,10 @@ import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.navigation.NavBackStackEntry
import com.ehviewer.core.ui.util.ProvideVectorPainterCache
import com.hippo.ehviewer.ui.theme.EhTheme
import com.hippo.ehviewer.ui.tools.DialogState
import com.hippo.ehviewer.ui.tools.LocalGlobalDialogState
import com.hippo.ehviewer.ui.tools.ProvideVectorPainterCache
import com.ramcosta.composedestinations.animations.NavHostAnimatedDestinationStyle
import me.zhanghai.compose.preference.ProvidePreferenceTheme
import me.zhanghai.compose.preference.preferenceTheme
@@ -7,8 +7,8 @@ import coil3.decode.DecodeUtils
import coil3.imageLoader
import coil3.request.crossfade
import coil3.size.Scale
import com.ehviewer.core.util.toIntOrDefault
import com.hippo.ehviewer.ktbuilder.imageRequest
import com.hippo.ehviewer.util.toIntOrDefault
import kotlin.math.roundToInt
import splitties.init.appCtx
@@ -1,11 +1,11 @@
package com.hippo.ehviewer.ui.login
import arrow.core.Either.Companion.catch
import com.ehviewer.core.util.logcat
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhCookieStore
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhUrl
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
@@ -60,6 +60,7 @@ import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import com.ehviewer.core.i18n.R
import com.ehviewer.core.ui.util.LocalWindowSizeClass
import com.ehviewer.core.ui.util.ifTrueThen
import com.ehviewer.core.ui.util.isExpanded
import com.ehviewer.core.ui.util.thenIf
import com.ehviewer.core.util.launchIO
@@ -73,7 +74,6 @@ import com.hippo.ehviewer.ui.destinations.WebViewSignInScreenDestination
import com.hippo.ehviewer.ui.openBrowser
import com.hippo.ehviewer.ui.tools.awaitConfirmationOrCancel
import com.hippo.ehviewer.util.displayString
import com.jamal.composeprefs3.ui.ifTrueThen
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@@ -41,13 +41,13 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.ehviewer.core.i18n.R
import com.ehviewer.core.ui.component.CrystalCard
import com.ehviewer.core.ui.component.GalleryListCardRating
import com.ehviewer.core.ui.util.TransitionsVisibilityScope
import com.ehviewer.core.ui.util.listThumbGenerator
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.dao.DownloadInfo
import com.hippo.ehviewer.download.DownloadManager
import com.hippo.ehviewer.ui.tools.GalleryListCardRating
import com.hippo.ehviewer.util.FileUtils
@Composable
@@ -40,6 +40,7 @@ import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
import com.ehviewer.core.ui.component.CrystalCard
import com.ehviewer.core.ui.component.ElevatedCard
import com.ehviewer.core.ui.component.GalleryListCardRating
import com.ehviewer.core.ui.util.SharedElementBox
import com.ehviewer.core.ui.util.TransitionsVisibilityScope
import com.ehviewer.core.ui.util.listThumbGenerator
@@ -48,7 +49,6 @@ import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.client.data.GalleryInfo
import com.hippo.ehviewer.client.data.GalleryInfo.Companion.NOT_FAVORITED
import com.hippo.ehviewer.download.DownloadManager
import com.hippo.ehviewer.ui.tools.GalleryListCardRating
import com.hippo.ehviewer.util.FavouriteStatusRouter
@Composable
@@ -37,6 +37,7 @@ import com.ehviewer.core.i18n.R
import com.ehviewer.core.ui.component.DropdownFilterChip
import com.ehviewer.core.ui.util.thenIf
import com.ehviewer.core.util.launch
import com.ehviewer.core.util.toIntOrDefault
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhTagDatabase
import com.hippo.ehviewer.client.EhUtils
@@ -44,7 +45,6 @@ import com.hippo.ehviewer.client.data.GalleryInfo.Companion.S_LANG_TAGS
import com.hippo.ehviewer.collectAsState
import com.hippo.ehviewer.ui.tools.DialogState
import com.hippo.ehviewer.ui.tools.awaitResult
import com.hippo.ehviewer.util.toIntOrDefault
import kotlinx.coroutines.CoroutineScope
private val categoryTable = arrayOf(
@@ -13,7 +13,11 @@ import android.webkit.MimeTypeMap
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.material3.SnackbarHostState
import androidx.core.content.FileProvider
import com.ehviewer.core.files.toOkioPath
import com.ehviewer.core.i18n.R
import com.ehviewer.core.util.isAtLeastQ
import com.ehviewer.core.util.isAtLeastT
import com.ehviewer.core.util.logcat
import com.hippo.ehviewer.BuildConfig.APPLICATION_ID
import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.client.data.GalleryInfo
@@ -23,11 +27,7 @@ import com.hippo.ehviewer.util.AppConfig
import com.hippo.ehviewer.util.FileUtils
import com.hippo.ehviewer.util.awaitActivityResult
import com.hippo.ehviewer.util.displayPath
import com.hippo.ehviewer.util.isAtLeastQ
import com.hippo.ehviewer.util.isAtLeastT
import com.hippo.ehviewer.util.requestPermission
import com.hippo.files.toOkioPath
import eu.kanade.tachiyomi.util.system.logcat
import java.io.File
import kotlin.time.Clock
import moe.tarsin.coroutines.runSuspendCatching
@@ -39,6 +39,7 @@ import coil3.compose.SubcomposeAsyncImage
import coil3.compose.SubcomposeAsyncImageContent
import com.ehviewer.core.i18n.R
import com.ehviewer.core.ui.util.thenIf
import com.ehviewer.core.util.unreachable
import com.google.accompanist.drawablepainter.DrawablePainter
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.collectAsState
@@ -52,7 +53,6 @@ import com.hippo.ehviewer.util.AdsPlaceholderFile
import eu.kanade.tachiyomi.ui.reader.viewer.CombinedCircularProgressIndicator
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.drop
import moe.tarsin.kt.unreachable
@Composable
fun PagerItem(
@@ -12,9 +12,9 @@ import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringArrayResource
import androidx.compose.ui.res.stringResource
import com.ehviewer.core.i18n.R
import com.ehviewer.core.util.isAtLeastP
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.util.isAtLeastP
@Composable
fun ReaderGeneralSetting() = Column(modifier = Modifier.verticalScroll(rememberScrollState()).navigationBarsPadding()) {
@@ -54,7 +54,6 @@ import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.keepScreenOn
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.zIndex
import androidx.core.view.WindowInsetsControllerCompat
import arrow.core.Either
import arrow.core.Either.Companion.catch
import arrow.core.raise.ensure
@@ -62,10 +61,11 @@ import arrow.core.right
import com.ehviewer.core.i18n.R
import com.ehviewer.core.ui.util.Await
import com.ehviewer.core.ui.util.asyncInVM
import com.ehviewer.core.ui.util.rememberSystemUiController
import com.ehviewer.core.ui.util.thenIf
import com.ehviewer.core.util.launch
import com.ehviewer.core.util.launchIO
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.ehviewer.core.util.unreachable
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.data.BaseGalleryInfo
@@ -104,7 +104,6 @@ import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.serialization.Serializable
import moe.tarsin.kt.unreachable
import moe.tarsin.string
import okio.Path.Companion.toPath
@@ -209,10 +208,10 @@ fun ReaderScreen(pageLoader: PageLoader, info: BaseGalleryInfo?) {
val keepScreenOn by Settings.keepScreenOn.collectAsState()
val uiController = rememberSystemUiController()
DisposableEffect(uiController) {
uiController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
uiController.showTransientSystemBarsBySwipe = true
onDispose {
uiController.isSystemBarsVisible = true
uiController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_DEFAULT
uiController.showTransientSystemBarsBySwipe = false
}
}
val lazyListState = rememberLazyListState(LazyLayoutCacheWindow(SCROLL_FRACTION, SCROLL_FRACTION), pageLoader.startPage)
@@ -1,8 +1,8 @@
package com.hippo.ehviewer.ui.screen
import com.ehviewer.core.util.containsIgnoreCase
import com.hippo.ehviewer.dao.DownloadInfo
import com.hippo.ehviewer.download.DownloadsFilterMode
import com.hippo.ehviewer.util.containsIgnoreCase
import kotlinx.serialization.Serializable
@Serializable
@@ -92,11 +92,16 @@ import com.ehviewer.core.ui.component.ProvideSideSheetContent
import com.ehviewer.core.ui.icons.EhIcons
import com.ehviewer.core.ui.icons.big.Download
import com.ehviewer.core.ui.util.Await
import com.ehviewer.core.ui.util.HapticFeedbackType
import com.ehviewer.core.ui.util.asyncState
import com.ehviewer.core.ui.util.ifTrueThen
import com.ehviewer.core.ui.util.rememberHapticFeedback
import com.ehviewer.core.ui.util.rememberInVM
import com.ehviewer.core.ui.util.takeAndClear
import com.ehviewer.core.ui.util.thenIf
import com.ehviewer.core.util.launch
import com.ehviewer.core.util.launchIO
import com.ehviewer.core.util.mapToLongArray
import com.ehviewer.core.util.onEachLatest
import com.ehviewer.core.util.withNonCancellableContext
import com.ehviewer.core.util.withUIContext
@@ -121,16 +126,11 @@ import com.hippo.ehviewer.ui.main.plus
import com.hippo.ehviewer.ui.navToReader
import com.hippo.ehviewer.ui.showMoveDownloadLabelList
import com.hippo.ehviewer.ui.tools.DialogState
import com.hippo.ehviewer.ui.tools.HapticFeedbackType
import com.hippo.ehviewer.ui.tools.awaitConfirmationOrCancel
import com.hippo.ehviewer.ui.tools.awaitInputText
import com.hippo.ehviewer.ui.tools.awaitSelectAction
import com.hippo.ehviewer.ui.tools.awaitSelectItemWithCheckBox
import com.hippo.ehviewer.ui.tools.awaitSingleChoice
import com.hippo.ehviewer.ui.tools.rememberHapticFeedback
import com.hippo.ehviewer.util.mapToLongArray
import com.hippo.ehviewer.util.takeAndClear
import com.jamal.composeprefs3.ui.ifTrueThen
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@@ -61,8 +61,10 @@ import com.ehviewer.core.ui.component.ProvideSideSheetContent
import com.ehviewer.core.ui.icons.EhIcons
import com.ehviewer.core.ui.icons.filled.GoTo
import com.ehviewer.core.ui.util.asyncState
import com.ehviewer.core.ui.util.takeAndClear
import com.ehviewer.core.ui.util.thenIf
import com.ehviewer.core.util.launch
import com.ehviewer.core.util.mapToLongArray
import com.ehviewer.core.util.onEachLatest
import com.ehviewer.core.util.withUIContext
import com.hippo.ehviewer.EhDB
@@ -81,8 +83,6 @@ import com.hippo.ehviewer.ui.main.GalleryList
import com.hippo.ehviewer.ui.startDownload
import com.hippo.ehviewer.ui.tools.awaitConfirmationOrCancel
import com.hippo.ehviewer.ui.tools.awaitSelectItem
import com.hippo.ehviewer.util.mapToLongArray
import com.hippo.ehviewer.util.takeAndClear
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@@ -88,6 +88,7 @@ import com.ehviewer.core.ui.util.snackBarPadding
import com.ehviewer.core.ui.util.thenIf
import com.ehviewer.core.util.launch
import com.ehviewer.core.util.launchIO
import com.ehviewer.core.util.logcat
import com.ehviewer.core.util.withUIContext
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.EhEngine
@@ -116,7 +117,6 @@ import com.hippo.ehviewer.util.displayString
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import eu.kanade.tachiyomi.util.system.logcat
import kotlin.math.roundToInt
import moe.tarsin.coroutines.runSuspendCatching
import moe.tarsin.navigate
@@ -73,16 +73,20 @@ import com.ehviewer.core.ui.component.CrystalCard
import com.ehviewer.core.ui.component.FastScrollLazyVerticalGrid
import com.ehviewer.core.ui.component.FilledTertiaryIconButton
import com.ehviewer.core.ui.component.FilledTertiaryIconToggleButton
import com.ehviewer.core.ui.component.GalleryDetailRating
import com.ehviewer.core.ui.component.GalleryRatingBar
import com.ehviewer.core.ui.icons.EhIcons
import com.ehviewer.core.ui.icons.filled.Magnet
import com.ehviewer.core.ui.util.LocalWindowSizeClass
import com.ehviewer.core.ui.util.TransitionsVisibilityScope
import com.ehviewer.core.ui.util.flattenForEach
import com.ehviewer.core.ui.util.isExpanded
import com.ehviewer.core.ui.util.rememberInVM
import com.ehviewer.core.util.async
import com.ehviewer.core.util.launch
import com.ehviewer.core.util.launchIO
import com.ehviewer.core.util.launchUI
import com.ehviewer.core.util.logcat
import com.ehviewer.core.util.withIOContext
import com.ehviewer.core.util.withUIContext
import com.hippo.ehviewer.EhDB
@@ -132,8 +136,6 @@ import com.hippo.ehviewer.ui.navToReader
import com.hippo.ehviewer.ui.openBrowser
import com.hippo.ehviewer.ui.startDownload
import com.hippo.ehviewer.ui.tools.DialogState
import com.hippo.ehviewer.ui.tools.GalleryDetailRating
import com.hippo.ehviewer.ui.tools.GalleryRatingBar
import com.hippo.ehviewer.ui.tools.awaitConfirmationOrCancel
import com.hippo.ehviewer.ui.tools.awaitResult
import com.hippo.ehviewer.ui.tools.awaitSelectAction
@@ -148,9 +150,7 @@ import com.hippo.ehviewer.util.FavouriteStatusRouter
import com.hippo.ehviewer.util.addTextToClipboard
import com.hippo.ehviewer.util.bgWork
import com.hippo.ehviewer.util.displayString
import com.hippo.ehviewer.util.flattenForEach
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import eu.kanade.tachiyomi.util.system.logcat
import io.ktor.http.encodeURLParameter
import kotlin.coroutines.resume
import kotlin.math.roundToInt
@@ -34,12 +34,15 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.util.fastJoinToString
import androidx.lifecycle.viewModelScope
import com.ehviewer.core.files.delete
import com.ehviewer.core.files.toOkioPath
import com.ehviewer.core.i18n.R
import com.ehviewer.core.ui.util.LocalWindowSizeClass
import com.ehviewer.core.ui.util.isExpanded
import com.ehviewer.core.ui.util.launchInVM
import com.ehviewer.core.ui.util.rememberInVM
import com.ehviewer.core.util.launchIO
import com.ehviewer.core.util.logcat
import com.ehviewer.core.util.withIOContext
import com.hippo.ehviewer.EhApplication.Companion.imageCache
import com.hippo.ehviewer.EhDB
@@ -70,12 +73,9 @@ import com.hippo.ehviewer.util.AppHelper
import com.hippo.ehviewer.util.awaitActivityResult
import com.hippo.ehviewer.util.bgWork
import com.hippo.ehviewer.util.displayString
import com.hippo.files.delete
import com.hippo.files.toOkioPath
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.serialization.Serializable
import moe.tarsin.coroutines.runSuspendCatching
import moe.tarsin.snackbar
@@ -78,7 +78,9 @@ import com.ehviewer.core.ui.component.ProvideSideSheetContent
import com.ehviewer.core.ui.icons.EhIcons
import com.ehviewer.core.ui.icons.filled.GoTo
import com.ehviewer.core.ui.util.Await
import com.ehviewer.core.ui.util.HapticFeedbackType
import com.ehviewer.core.ui.util.asyncState
import com.ehviewer.core.ui.util.rememberHapticFeedback
import com.ehviewer.core.ui.util.thenIf
import com.ehviewer.core.util.launch
import com.ehviewer.core.util.launchIO
@@ -113,11 +115,9 @@ import com.hippo.ehviewer.ui.main.GalleryInfoListItem
import com.hippo.ehviewer.ui.main.GalleryList
import com.hippo.ehviewer.ui.main.SearchFilter
import com.hippo.ehviewer.ui.tools.DialogState
import com.hippo.ehviewer.ui.tools.HapticFeedbackType
import com.hippo.ehviewer.ui.tools.awaitConfirmationOrCancel
import com.hippo.ehviewer.ui.tools.awaitInputText
import com.hippo.ehviewer.ui.tools.awaitInputTextWithCheckBox
import com.hippo.ehviewer.ui.tools.rememberHapticFeedback
import com.hippo.ehviewer.ui.tools.rememberMutableStateInDataStore
import com.hippo.ehviewer.util.FavouriteStatusRouter
import com.ramcosta.composedestinations.annotation.Destination
@@ -27,6 +27,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import com.ehviewer.core.files.toOkioPath
import com.ehviewer.core.i18n.R
import com.ehviewer.core.ui.util.snackBarPadding
import com.ehviewer.core.util.launch
@@ -39,7 +40,6 @@ import com.hippo.ehviewer.ui.main.ImageSearch
import com.hippo.ehviewer.ui.main.plus
import com.hippo.ehviewer.util.pickVisualMedia
import com.hippo.ehviewer.util.sha1
import com.hippo.files.toOkioPath
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@@ -66,6 +66,8 @@ import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.coerceAtMost
import androidx.compose.ui.unit.dp
import com.ehviewer.core.i18n.R
import com.ehviewer.core.ui.util.ifNotNullThen
import com.ehviewer.core.ui.util.ifTrueThen
import com.ehviewer.core.ui.util.thenIf
import com.hippo.ehviewer.EhApplication.Companion.searchDatabase
import com.hippo.ehviewer.Settings
@@ -80,8 +82,6 @@ import com.hippo.ehviewer.ui.theme.scrim
import com.hippo.ehviewer.ui.tools.DialogState
import com.hippo.ehviewer.ui.tools.awaitConfirmationOrCancel
import com.hippo.ehviewer.ui.tools.rememberCompositionActiveState
import com.jamal.composeprefs3.ui.ifNotNullThen
import com.jamal.composeprefs3.ui.ifTrueThen
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
@@ -21,6 +21,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.fromHtml
import androidx.compose.ui.unit.dp
import com.ehviewer.core.files.delete
import com.ehviewer.core.i18n.R
import com.ehviewer.core.util.launch
import com.ehviewer.core.util.withUIContext
@@ -40,7 +41,6 @@ import com.hippo.ehviewer.util.AppConfig
import com.hippo.ehviewer.util.ReadableTime
import com.hippo.ehviewer.util.displayString
import com.hippo.ehviewer.util.installPackage
import com.hippo.files.delete
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@@ -30,8 +30,14 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.core.net.toUri
import com.ehviewer.core.files.delete
import com.ehviewer.core.files.sendTo
import com.ehviewer.core.files.toOkioPath
import com.ehviewer.core.i18n.R
import com.ehviewer.core.util.isAtLeastO
import com.ehviewer.core.util.isAtLeastSExtension7
import com.ehviewer.core.util.launch
import com.ehviewer.core.util.logcat
import com.ehviewer.core.util.withIOContext
import com.hippo.ehviewer.BuildConfig
import com.hippo.ehviewer.EhDB
@@ -50,16 +56,10 @@ import com.hippo.ehviewer.util.ReadableTime
import com.hippo.ehviewer.util.displayPath
import com.hippo.ehviewer.util.getAppLanguage
import com.hippo.ehviewer.util.getLanguages
import com.hippo.ehviewer.util.isAtLeastO
import com.hippo.ehviewer.util.isAtLeastSExtension7
import com.hippo.ehviewer.util.sendTo
import com.hippo.ehviewer.util.setAppLanguage
import com.hippo.files.delete
import com.hippo.files.toOkioPath
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import eu.kanade.tachiyomi.util.system.logcat
import java.io.File
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
@@ -29,9 +29,19 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import arrow.fx.coroutines.parMap
import arrow.fx.coroutines.parMapNotNull
import com.ehviewer.core.files.delete
import com.ehviewer.core.files.find
import com.ehviewer.core.files.isDirectory
import com.ehviewer.core.files.list
import com.ehviewer.core.files.metadataOrNull
import com.ehviewer.core.files.mkdirs
import com.ehviewer.core.files.toOkioPath
import com.ehviewer.core.files.toUri
import com.ehviewer.core.i18n.R
import com.ehviewer.core.util.isAtLeastQ
import com.ehviewer.core.util.launch
import com.ehviewer.core.util.launchIO
import com.ehviewer.core.util.logcat
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
@@ -60,20 +70,10 @@ import com.hippo.ehviewer.ui.tools.observed
import com.hippo.ehviewer.util.AppConfig
import com.hippo.ehviewer.util.displayPath
import com.hippo.ehviewer.util.displayString
import com.hippo.ehviewer.util.isAtLeastQ
import com.hippo.ehviewer.util.requestPermission
import com.hippo.files.delete
import com.hippo.files.find
import com.hippo.files.isDirectory
import com.hippo.files.list
import com.hippo.files.metadataOrNull
import com.hippo.files.mkdirs
import com.hippo.files.toOkioPath
import com.hippo.files.toUri
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import eu.kanade.tachiyomi.util.system.logcat
import moe.tarsin.coroutines.runSuspendCatching
import moe.tarsin.snackbar
import moe.tarsin.string
@@ -29,6 +29,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.fromHtml
import com.ehviewer.core.i18n.R
import com.ehviewer.core.util.isAtLeastT
import com.ehviewer.core.util.launch
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
@@ -45,7 +46,6 @@ import com.hippo.ehviewer.ui.tools.awaitConfirmationOrCancel
import com.hippo.ehviewer.ui.tools.awaitSelectItem
import com.hippo.ehviewer.ui.tools.awaitSelectTime
import com.hippo.ehviewer.util.copyTextToClipboard
import com.hippo.ehviewer.util.isAtLeastT
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@@ -19,10 +19,10 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import com.ehviewer.core.ui.component.scrollbarStyle
import com.ehviewer.core.util.isAtLeastOMR1
import com.ehviewer.core.util.isAtLeastS
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.collectAsState
import com.hippo.ehviewer.util.isAtLeastOMR1
import com.hippo.ehviewer.util.isAtLeastS
import com.materialkolor.dynamicColorScheme
fun ColorScheme.amoled(amoled: Boolean) = if (amoled) {
@@ -25,15 +25,13 @@ import androidx.compose.ui.text.input.getTextBeforeSelection
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.withStyle
import com.ehviewer.core.i18n.R
import com.ehviewer.core.util.unreachable
import com.hippo.ehviewer.util.toRangeSet
import io.github.petertrr.diffutils.diffInline
import io.github.petertrr.diffutils.patch.ChangeDelta
import io.github.petertrr.diffutils.patch.DeleteDelta
import io.github.petertrr.diffutils.patch.EqualDelta
import io.github.petertrr.diffutils.patch.InsertDelta
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import moe.tarsin.kt.unreachable
import moe.tarsin.string
fun TextFieldValue.updateSpan(origin: TextFieldValue): TextFieldValue {
@@ -58,8 +56,6 @@ fun TextFieldValue.updateSpan(origin: TextFieldValue): TextFieldValue {
append(annoStr.subSequence(end, len))
}
}
is ChangeDelta -> unreachable()
is EqualDelta -> unreachable()
is InsertDelta -> {
val pos = delta.source.position
val toIns = delta.target.lines.first()
@@ -69,6 +65,7 @@ fun TextFieldValue.updateSpan(origin: TextFieldValue): TextFieldValue {
append(annoStr.subSequence(pos, len))
}
}
else -> unreachable()
}
// Update span range for updated comment
return copy(annotatedString = str)
@@ -96,10 +96,10 @@ import arrow.core.right
import com.ehviewer.core.i18n.R
import com.ehviewer.core.ui.component.FastScrollLazyColumn
import com.ehviewer.core.ui.component.LabeledCheckbox
import com.ehviewer.core.ui.util.ifNotNullThen
import com.ehviewer.core.ui.util.ifTrueThen
import com.hippo.ehviewer.client.EhTagDatabase
import com.hippo.ehviewer.client.EhTagDatabase.suggestion
import com.jamal.composeprefs3.ui.ifNotNullThen
import com.jamal.composeprefs3.ui.ifTrueThen
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlinx.coroutines.CancellableContinuation
@@ -34,13 +34,13 @@ import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.round
import androidx.compose.ui.unit.toSize
import androidx.compose.ui.util.lerp
import com.ehviewer.core.util.unreachable
import kotlinx.coroutines.launch
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import moe.tarsin.kt.unreachable
fun lerp(start: IntOffset, stop: IntOffset, fraction: Float) = IntOffset(
lerp(start.x, stop.x, fraction),
@@ -1,12 +1,12 @@
package com.hippo.ehviewer.updater
import com.ehviewer.core.files.write
import com.hippo.ehviewer.BuildConfig
import com.hippo.ehviewer.EhApplication.Companion.ktorClient
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.executeAndParseAs
import com.hippo.ehviewer.spider.timeoutBySpeed
import com.hippo.ehviewer.util.copyTo
import com.hippo.files.write
import io.ktor.client.request.HttpRequestBuilder
import io.ktor.client.request.accept
import io.ktor.client.request.bearerAuth
@@ -17,11 +17,11 @@ package com.hippo.ehviewer.util
import android.os.Build
import android.os.Environment
import com.ehviewer.core.files.exists
import com.ehviewer.core.files.isDirectory
import com.ehviewer.core.files.mkdirs
import com.hippo.ehviewer.BuildConfig
import com.hippo.ehviewer.client.parser.ParserUtils
import com.hippo.files.exists
import com.hippo.files.isDirectory
import com.hippo.files.mkdirs
import java.io.File
import okio.Path
import okio.Path.Companion.toOkioPath
@@ -1,17 +1,8 @@
package com.hippo.ehviewer.util
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.util.fastForEach
fun <T> MutableList<T>.insertWith(element: T, comparator: Comparator<T>) {
val index = binarySearch(element, comparator).let {
if (it < 0) -it - 1 else it
}
add(index, element)
}
inline fun <T> List<List<T>>.flattenForEach(action: (T) -> Unit) = fastForEach { list ->
list.fastForEach { item -> action(item) }
}
fun <K, V> SnapshotStateMap<K, V>.takeAndClear() = toMap().values.also { clear() }
@@ -2,9 +2,9 @@ package com.hippo.ehviewer.util
import android.os.Build
import android.os.Debug
import com.ehviewer.core.util.logcat
import com.hippo.ehviewer.BuildConfig
import com.hippo.ehviewer.Settings
import eu.kanade.tachiyomi.util.system.logcat
import java.io.File
import java.io.PrintWriter
import java.io.Writer
@@ -16,7 +16,7 @@
package com.hippo.ehviewer.util
import com.ehviewer.core.i18n.R
import eu.kanade.tachiyomi.util.system.logcat
import com.ehviewer.core.util.logcat
import io.ktor.client.network.sockets.ConnectTimeoutException
import io.ktor.client.network.sockets.SocketTimeoutException
import io.ktor.client.plugins.HttpRequestTimeoutException
@@ -1,6 +0,0 @@
package com.hippo.ehviewer.util
import com.hippo.files.SystemFileSystem
import okio.Path
infix fun Path.sendTo(file: Path) = SystemFileSystem.copy(this, file)
@@ -15,7 +15,7 @@
*/
package com.hippo.ehviewer.util
import com.hippo.files.write
import com.ehviewer.core.files.write
import io.ktor.utils.io.ByteReadChannel
import io.ktor.utils.io.InternalAPI
import io.ktor.utils.io.rethrowCloseCauseIfNeeded
@@ -22,6 +22,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.ehviewer.core.i18n.R
import com.ehviewer.core.util.isAtLeastO
import com.ehviewer.core.util.withIOContext
import com.ehviewer.core.util.withUIContext
import java.io.File
@@ -16,7 +16,7 @@
package com.hippo.ehviewer.util
import com.ehviewer.core.mainthread.checkNotMainThread
import eu.kanade.tachiyomi.util.system.logcat
import com.ehviewer.core.util.logcat
import java.io.File
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.runBlocking
@@ -6,10 +6,10 @@ import android.os.Environment
import android.provider.DocumentsContract
import androidx.core.provider.DocumentsContractCompat
import arrow.core.Either
import com.ehviewer.core.files.openFileDescriptor
import com.ehviewer.core.files.read
import com.ehviewer.core.files.toUri
import com.hippo.ehviewer.jni.sha1 as nativeSha1
import com.hippo.files.openFileDescriptor
import com.hippo.files.read
import com.hippo.files.toUri
import kotlinx.io.readString
import okio.Path
import splitties.init.appCtx
@@ -19,6 +19,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import com.ehviewer.core.i18n.R
import com.ehviewer.core.util.toLocalDateTime
import java.util.Locale
import kotlin.time.Clock
import kotlin.time.Instant
@@ -21,10 +21,10 @@ import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import com.ehviewer.core.ui.component.Slider
import com.ehviewer.core.ui.component.defaultMaxTickCount
import com.ehviewer.core.ui.util.HapticFeedbackType
import com.ehviewer.core.ui.util.LocalWindowSizeClass
import com.ehviewer.core.ui.util.isExpanded
import com.hippo.ehviewer.ui.tools.HapticFeedbackType
import com.hippo.ehviewer.ui.tools.rememberHapticFeedback
import com.ehviewer.core.ui.util.rememberHapticFeedback
@Composable
fun ChapterNavigator(
-4
View File
@@ -24,10 +24,6 @@
<dimen name="strip_item_padding">8dp</dimen>
<!-- RatingView -->
<dimen name="rating_size">16dp</dimen>
<dimen name="rating_interval">1dp</dimen>
<dimen name="gallery_list_interval">12dp</dimen>
<dimen name="gallery_list_margin_h">12dp</dimen>
<dimen name="gallery_list_margin_v">4dp</dimen>
+5
View File
@@ -7,6 +7,9 @@ kotlin {
commonMain {
dependencies {
api(libs.kotlinx.coroutines.core)
api(libs.kotlinx.datetime)
api(libs.kotlinx.io)
api(libs.okio)
api(libs.logcat)
api(project.dependencies.platform(libs.arrow.stack))
api(libs.bundles.arrow)
@@ -15,6 +18,8 @@ kotlin {
androidMain {
dependencies {
api(libs.kotlinx.coroutines.android)
api(libs.splitties.appctx)
implementation(libs.androidx.core)
}
}
}
@@ -1,4 +1,4 @@
package com.hippo.files
package com.ehviewer.core.files
import android.content.Context
import android.net.Uri
@@ -22,7 +22,6 @@ import okio.IOException
import okio.Path
import okio.Sink
import okio.Source
import splitties.init.appCtx
class AndroidFileSystem(context: Context) : FileSystem() {
private val contentResolver = context.contentResolver
@@ -237,5 +236,3 @@ class AndroidFileSystem(context: Context) : FileSystem() {
private fun Path.isPhysicalFile() = toString().startsWith('/')
private fun Uri.isCifsDocument() = authority == "com.wa2c.android.cifsdocumentsprovider.documents"
val SystemFileSystem = AndroidFileSystem(appCtx)
@@ -0,0 +1,10 @@
package com.ehviewer.core.files
import okio.FileSystem
import splitties.init.appCtx
actual val SystemFileSystem: FileSystem
get() = PlatformSystemFileSystem
@PublishedApi
internal val PlatformSystemFileSystem = AndroidFileSystem(appCtx)
@@ -1,4 +1,4 @@
package com.hippo.files
package com.ehviewer.core.files
import android.content.ContentResolver
import android.net.Uri
@@ -9,31 +9,11 @@ import kotlinx.io.buffered
import okio.Path
import okio.Path.Companion.toPath
val Path.isDirectory get() = SystemFileSystem.metadataOrNull(this)?.isDirectory == true
fun Path.openFileDescriptor(mode: String) = PlatformSystemFileSystem.openFileDescriptor(this, mode)
val Path.isFile get() = SystemFileSystem.metadataOrNull(this)?.isRegularFile == true
actual inline fun <T> Path.read(f: Source.() -> T) = PlatformSystemFileSystem.rawSource(this).buffered().use(f)
fun Path.metadataOrNull() = SystemFileSystem.metadataOrNull(this)
fun Path.find(name: String) = resolve(name).takeIf { it.exists() }
fun Path.exists() = SystemFileSystem.exists(this)
fun Path.delete() = SystemFileSystem.deleteRecursively(this)
fun Path.deleteContent() = SystemFileSystem.listOrNull(this)?.forEach(Path::delete)
fun Path.list() = SystemFileSystem.listOrNull(this).orEmpty()
fun Path.mkdirs() = SystemFileSystem.createDirectories(this)
infix fun Path.moveTo(target: Path) = SystemFileSystem.atomicMove(this, target)
fun Path.openFileDescriptor(mode: String) = SystemFileSystem.openFileDescriptor(this, mode)
inline fun <T> Path.read(f: Source.() -> T) = SystemFileSystem.rawSource(this).buffered().use(f)
inline fun <T> Path.write(f: Sink.() -> T) = SystemFileSystem.rawSink(this).buffered().use(f)
actual inline fun <T> Path.write(f: Sink.() -> T) = PlatformSystemFileSystem.rawSink(this).buffered().use(f)
fun Path.toUri(): Uri {
val str = toString()
@@ -1,15 +1,35 @@
package com.hippo.ehviewer.util
package com.ehviewer.core.util
import android.os.Build
import android.os.ext.SdkExtensions
import androidx.annotation.ChecksSdkIntAtLeast
@ChecksSdkIntAtLeast(Build.VERSION_CODES.N)
val isAtLeastN = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
@ChecksSdkIntAtLeast(Build.VERSION_CODES.O)
val isAtLeastO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
@ChecksSdkIntAtLeast(Build.VERSION_CODES.O_MR1)
val isAtLeastOMR1 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1
@ChecksSdkIntAtLeast(Build.VERSION_CODES.P)
val isAtLeastP = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
@ChecksSdkIntAtLeast(Build.VERSION_CODES.Q)
val isAtLeastQ = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
@ChecksSdkIntAtLeast(Build.VERSION_CODES.R)
val isAtLeastR = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
@ChecksSdkIntAtLeast(Build.VERSION_CODES.S)
val isAtLeastS = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
@ChecksSdkIntAtLeast(Build.VERSION_CODES.TIRAMISU)
val isAtLeastT = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
@ChecksSdkIntAtLeast(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
val isAtLeastU = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
@ChecksSdkIntAtLeast(api = 7, extension = Build.VERSION_CODES.S)
val isAtLeastSExtension7 = isAtLeastR && SdkExtensions.getExtensionVersion(Build.VERSION_CODES.S) >= 7
@@ -0,0 +1,5 @@
package com.ehviewer.core.files
import okio.FileSystem
expect val SystemFileSystem: FileSystem
@@ -0,0 +1,31 @@
package com.ehviewer.core.files
import kotlinx.io.Sink
import kotlinx.io.Source
import okio.Path
val Path.isDirectory get() = SystemFileSystem.metadataOrNull(this)?.isDirectory == true
val Path.isFile get() = SystemFileSystem.metadataOrNull(this)?.isRegularFile == true
fun Path.metadataOrNull() = SystemFileSystem.metadataOrNull(this)
fun Path.find(name: String) = resolve(name).takeIf { it.exists() }
fun Path.exists() = SystemFileSystem.exists(this)
fun Path.delete() = SystemFileSystem.deleteRecursively(this)
fun Path.deleteContent() = SystemFileSystem.listOrNull(this)?.forEach(Path::delete)
fun Path.list() = SystemFileSystem.listOrNull(this).orEmpty()
fun Path.mkdirs() = SystemFileSystem.createDirectories(this)
infix fun Path.moveTo(target: Path) = SystemFileSystem.atomicMove(this, target)
infix fun Path.sendTo(target: Path) = SystemFileSystem.copy(this, target)
expect inline fun <T> Path.read(f: Source.() -> T): T
expect inline fun <T> Path.write(f: Sink.() -> T): T
@@ -1,4 +1,4 @@
package com.hippo.ehviewer.util
package com.ehviewer.core.util
inline fun <R : Any, C : MutableCollection<in R>> LongArray.mapNotNullTo(destination: C, transform: (Long) -> R?): C {
forEach { element -> transform(element)?.let { destination.add(it) } }
@@ -1,4 +1,4 @@
package com.hippo.ehviewer.util
package com.ehviewer.core.util
import kotlin.time.Instant
import kotlinx.datetime.LocalDate
@@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.util.system
package com.ehviewer.core.util
import logcat.LogPriority
import logcat.asLog
@@ -1,3 +1,3 @@
package moe.tarsin.kt
package com.ehviewer.core.util
fun unreachable(): Nothing = error("Unreachable!!!")
@@ -1,4 +1,4 @@
package com.hippo.ehviewer.util
package com.ehviewer.core.util
private val EntityRegex = "&(?:amp|lt|gt|quot|#039);".toRegex()
private val EntityMap = mapOf(
-2
View File
@@ -7,13 +7,11 @@ kotlin {
commonMain {
dependencies {
api(projects.core.common)
api(project.dependencies.platform(libs.okio.bom))
api(libs.androidx.datastore)
}
}
androidMain {
dependencies {
api(libs.splitties.appctx)
}
}
}
@@ -1,26 +1,16 @@
package com.hippo.ehviewer.ui.tools
package com.ehviewer.core.ui.util
import android.view.HapticFeedbackConstants
import android.view.View
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalView
import com.hippo.ehviewer.util.isAtLeastOMR1
import com.hippo.ehviewer.util.isAtLeastR
import com.hippo.ehviewer.util.isAtLeastU
enum class HapticFeedbackType {
START,
MOVE,
END,
}
interface HapticFeedback {
fun performHapticFeedback(hapticFeedbackType: HapticFeedbackType)
}
import com.ehviewer.core.util.isAtLeastOMR1
import com.ehviewer.core.util.isAtLeastR
import com.ehviewer.core.util.isAtLeastU
@Composable
fun rememberHapticFeedback(): HapticFeedback {
actual fun rememberHapticFeedback(): HapticFeedback {
val view = LocalView.current
return remember(view) { AndroidHapticFeedback(view) }
}
@@ -0,0 +1,77 @@
package com.ehviewer.core.ui.util
import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.view.View
import android.view.Window
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.window.DialogWindowProvider
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
@Composable
actual fun rememberSystemUiController(): SystemUiController {
val view = LocalView.current
val window = findWindow()
return remember(view, window) { AndroidSystemUiController(view, window) }
}
@Composable
private fun findWindow(): Window? = (LocalView.current.parent as? DialogWindowProvider)?.window
?: LocalView.current.context.findWindow()
private tailrec fun Context.findWindow(): Window? = when (this) {
is Activity -> window
is ContextWrapper -> baseContext.findWindow()
else -> null
}
internal class AndroidSystemUiController(
private val view: View,
window: Window?,
) : SystemUiController {
private val windowInsetsController = window?.let {
WindowCompat.getInsetsController(it, view)
}
override var showTransientSystemBarsBySwipe: Boolean
get() = windowInsetsController?.systemBarsBehavior == WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
set(value) {
windowInsetsController?.systemBarsBehavior = if (value) {
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
} else {
WindowInsetsControllerCompat.BEHAVIOR_DEFAULT
}
}
override var isStatusBarVisible: Boolean
get() = ViewCompat.getRootWindowInsets(view)?.isVisible(WindowInsetsCompat.Type.statusBars()) == true
set(value) {
if (value) {
windowInsetsController?.show(WindowInsetsCompat.Type.statusBars())
} else {
windowInsetsController?.hide(WindowInsetsCompat.Type.statusBars())
}
}
override var isNavigationBarVisible: Boolean
get() = ViewCompat.getRootWindowInsets(view)?.isVisible(WindowInsetsCompat.Type.navigationBars()) == true
set(value) {
if (value) {
windowInsetsController?.show(WindowInsetsCompat.Type.navigationBars())
} else {
windowInsetsController?.hide(WindowInsetsCompat.Type.navigationBars())
}
}
override var statusBarDarkContentEnabled: Boolean
get() = windowInsetsController?.isAppearanceLightStatusBars == true
set(value) {
windowInsetsController?.isAppearanceLightStatusBars = value
}
}
@@ -1,4 +1,4 @@
package com.hippo.ehviewer.ui.tools
package com.ehviewer.core.ui.component
import androidx.compose.foundation.gestures.detectHorizontalDragGestures
import androidx.compose.foundation.gestures.detectTapGestures
@@ -18,10 +18,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.hippo.ehviewer.R
import com.ehviewer.core.ui.util.IconCached
import kotlin.math.roundToInt
private val colorYellow800 = Color(0xfff9a825)
@@ -34,7 +33,7 @@ private fun getImageVector(index: Int, rating: Int) = when {
}
@Composable
fun MetaRatingWidgetReuse(rating: Float, ratingSize: Dp, ratingInterval: Dp, modifier: Modifier = Modifier) {
fun RatingWidgetReuse(rating: Float, ratingSize: Dp, ratingInterval: Dp, modifier: Modifier = Modifier) {
val r = (rating * 2).roundToInt().coerceIn(0, 10)
Row(modifier = modifier) {
repeat(5) {
@@ -50,7 +49,7 @@ fun MetaRatingWidgetReuse(rating: Float, ratingSize: Dp, ratingInterval: Dp, mod
}
@Composable
fun MetaRatingWidget(rating: Float, ratingSize: Dp, ratingInterval: Dp, modifier: Modifier = Modifier, onRatingChange: ((Float) -> Unit)? = null) {
fun RatingWidget(rating: Float, ratingSize: Dp, ratingInterval: Dp, modifier: Modifier = Modifier, onRatingChange: ((Float) -> Unit)? = null) {
val r = (rating * 2).roundToInt().coerceIn(0, 10)
val density = LocalDensity.current
val ratingSizePx = remember { with(density) { ratingSize.toPx() } }
@@ -89,22 +88,22 @@ fun MetaRatingWidget(rating: Float, ratingSize: Dp, ratingInterval: Dp, modifier
@Composable
fun GalleryListCardRating(rating: Float, modifier: Modifier = Modifier) {
MetaRatingWidgetReuse(
RatingWidgetReuse(
rating = rating,
ratingSize = dimensionResource(id = R.dimen.rating_size),
ratingInterval = dimensionResource(id = R.dimen.rating_interval),
ratingSize = 16.dp,
ratingInterval = 1.dp,
modifier = modifier,
)
}
@Composable
fun GalleryDetailRating(rating: Float) {
MetaRatingWidget(rating = rating, ratingSize = 48.dp, ratingInterval = 12.dp)
RatingWidget(rating = rating, ratingSize = 48.dp, ratingInterval = 12.dp)
}
@Composable
fun GalleryRatingBar(rating: Float, onRatingChange: (Float) -> Unit, modifier: Modifier = Modifier) {
MetaRatingWidget(
RatingWidget(
rating = rating,
ratingSize = 48.dp,
ratingInterval = 0.dp,
@@ -0,0 +1,10 @@
package com.ehviewer.core.ui.util
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.util.fastForEach
inline fun <T> List<List<T>>.flattenForEach(action: (T) -> Unit) = fastForEach { list ->
list.fastForEach { item -> action(item) }
}
fun <K, V> SnapshotStateMap<K, V>.takeAndClear() = toMap().values.also { clear() }
@@ -1,4 +1,4 @@
package com.jamal.composeprefs3.ui
package com.ehviewer.core.ui.util
import androidx.compose.runtime.Composable
@@ -0,0 +1,16 @@
package com.ehviewer.core.ui.util
import androidx.compose.runtime.Composable
enum class HapticFeedbackType {
START,
MOVE,
END,
}
interface HapticFeedback {
fun performHapticFeedback(hapticFeedbackType: HapticFeedbackType)
}
@Composable
expect fun rememberHapticFeedback(): HapticFeedback
@@ -0,0 +1,61 @@
/*
* Copyright 2022 The Android 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ehviewer.core.ui.util
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
/**
* A class which provides easy-to-use utilities for updating the System UI bar
* colors within Jetpack Compose.
*/
@Stable
interface SystemUiController {
var showTransientSystemBarsBySwipe: Boolean
/**
* Property which holds the status bar visibility. If set to true, show the status bar,
* otherwise hide the status bar.
*/
var isStatusBarVisible: Boolean
/**
* Property which holds the navigation bar visibility. If set to true, show the navigation bar,
* otherwise hide the navigation bar.
*/
var isNavigationBarVisible: Boolean
/**
* Property which holds the status & navigation bar visibility. If set to true, show both bars,
* otherwise hide both bars.
*/
var isSystemBarsVisible: Boolean
get() = isNavigationBarVisible && isStatusBarVisible
set(value) {
isStatusBarVisible = value
isNavigationBarVisible = value
}
/**
* Property which holds whether the status bar icons + content are 'dark' or not.
*/
var statusBarDarkContentEnabled: Boolean
}
@Composable
expect fun rememberSystemUiController(): SystemUiController
@@ -1,4 +1,4 @@
package com.hippo.ehviewer.ui.tools
package com.ehviewer.core.ui.util
import androidx.collection.MutableScatterMap
import androidx.collection.mutableScatterMapOf
+3 -1
View File
@@ -22,6 +22,7 @@ compose-preference = "2.1.0"
kotlin = "2.2.20"
kotlinx-coroutines = "1.10.2"
kotlinx-datetime = "0.7.1"
kotlinx-io = "0.8.0"
kotlinx-serialization = "1.9.0"
ksp = "2.2.20-2.0.3"
ktor = "3.3.0"
@@ -94,6 +95,7 @@ diff = "io.github.petertrr:kotlin-multiplatform-diff:1.1.0"
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" }
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" }
kotlinx-io = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kotlinx-io" }
ktlint = "com.pinterest.ktlint:ktlint-cli:1.7.1"
@@ -104,7 +106,7 @@ logcat = "com.squareup.logcat:logcat:0.4"
moko-resources = { module = "dev.icerock.moko:resources", version.ref = "moko-resources" }
okio-bom = { module = "com.squareup.okio:okio-bom", version.ref = "okio" }
okio = { module = "com.squareup.okio:okio", version.ref = "okio" }
reorderable = "sh.calvin.reorderable:reorderable:3.0.0"