Refactoring
This commit is contained in:
@@ -11,9 +11,9 @@ import org.koitharu.kotatsu.utils.ext.getParcelableCompat
|
||||
import org.koitharu.kotatsu.utils.ext.getParcelableExtraCompat
|
||||
|
||||
class MangaIntent private constructor(
|
||||
val manga: Manga?,
|
||||
val mangaId: Long,
|
||||
val uri: Uri?,
|
||||
@JvmField val manga: Manga?,
|
||||
@JvmField val mangaId: Long,
|
||||
@JvmField val uri: Uri?,
|
||||
) {
|
||||
|
||||
constructor(intent: Intent?) : this(
|
||||
|
||||
@@ -26,34 +26,33 @@ import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.util.ActionModeDelegate
|
||||
import org.koitharu.kotatsu.base.ui.util.BaseActivityEntryPoint
|
||||
import org.koitharu.kotatsu.base.ui.util.WindowInsetsDelegate
|
||||
import org.koitharu.kotatsu.base.ui.util.inject
|
||||
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.utils.ext.getThemeColor
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LeakingThis")
|
||||
abstract class BaseActivity<B : ViewBinding> :
|
||||
AppCompatActivity(),
|
||||
WindowInsetsDelegate.WindowInsetsListener {
|
||||
|
||||
@Inject
|
||||
lateinit var settings: AppSettings
|
||||
private var isAmoledTheme = false
|
||||
|
||||
protected lateinit var binding: B
|
||||
private set
|
||||
|
||||
@Suppress("LeakingThis")
|
||||
@JvmField
|
||||
protected val exceptionResolver = ExceptionResolver(this)
|
||||
|
||||
@Suppress("LeakingThis")
|
||||
@JvmField
|
||||
protected val insetsDelegate = WindowInsetsDelegate(this)
|
||||
|
||||
@JvmField
|
||||
val actionModeDelegate = ActionModeDelegate()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
EntryPointAccessors.fromApplication(this, BaseActivityEntryPoint::class.java).inject(this)
|
||||
val settings = EntryPointAccessors.fromApplication(this, BaseActivityEntryPoint::class.java).settings
|
||||
isAmoledTheme = settings.isAmoledTheme
|
||||
setTheme(settings.colorScheme.styleResId)
|
||||
if (settings.isAmoledTheme) {
|
||||
if (isAmoledTheme) {
|
||||
setTheme(R.style.ThemeOverlay_Kotatsu_Amoled)
|
||||
}
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -108,7 +107,7 @@ abstract class BaseActivity<B : ViewBinding> :
|
||||
protected fun isDarkAmoledTheme(): Boolean {
|
||||
val uiMode = resources.configuration.uiMode
|
||||
val isNight = uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
|
||||
return isNight && settings.isAmoledTheme
|
||||
return isNight && isAmoledTheme
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.koitharu.kotatsu.base.ui.util.ActionModeDelegate
|
||||
import org.koitharu.kotatsu.base.ui.util.WindowInsetsDelegate
|
||||
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
|
||||
|
||||
@Suppress("LeakingThis")
|
||||
abstract class BaseFragment<B : ViewBinding> :
|
||||
Fragment(),
|
||||
WindowInsetsDelegate.WindowInsetsListener {
|
||||
@@ -19,10 +20,10 @@ abstract class BaseFragment<B : ViewBinding> :
|
||||
protected val binding: B
|
||||
get() = checkNotNull(viewBinding)
|
||||
|
||||
@Suppress("LeakingThis")
|
||||
@JvmField
|
||||
protected val exceptionResolver = ExceptionResolver(this)
|
||||
|
||||
@Suppress("LeakingThis")
|
||||
@JvmField
|
||||
protected val insetsDelegate = WindowInsetsDelegate(this)
|
||||
|
||||
protected val actionModeDelegate: ActionModeDelegate
|
||||
|
||||
@@ -9,12 +9,13 @@ import androidx.core.view.updatePadding
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner
|
||||
import org.koitharu.kotatsu.base.ui.util.WindowInsetsDelegate
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.settings.SettingsHeadersFragment
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LeakingThis")
|
||||
@AndroidEntryPoint
|
||||
abstract class BasePreferenceFragment(@StringRes private val titleId: Int) :
|
||||
PreferenceFragmentCompat(),
|
||||
@@ -24,7 +25,7 @@ abstract class BasePreferenceFragment(@StringRes private val titleId: Int) :
|
||||
@Inject
|
||||
lateinit var settings: AppSettings
|
||||
|
||||
@Suppress("LeakingThis")
|
||||
@JvmField
|
||||
protected val insetsDelegate = WindowInsetsDelegate(this)
|
||||
|
||||
override val recyclerView: RecyclerView
|
||||
@@ -55,7 +56,6 @@ abstract class BasePreferenceFragment(@StringRes private val titleId: Int) :
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("UsePropertyAccessSyntax")
|
||||
protected fun setTitle(title: CharSequence) {
|
||||
(parentFragment as? SettingsHeadersFragment)?.setTitle(title)
|
||||
?: activity?.setTitle(title)
|
||||
|
||||
@@ -3,16 +3,24 @@ package org.koitharu.kotatsu.base.ui
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.CoroutineStart
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koitharu.kotatsu.base.ui.util.CountedBooleanLiveData
|
||||
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
abstract class BaseViewModel : ViewModel() {
|
||||
|
||||
@JvmField
|
||||
protected val loadingCounter = CountedBooleanLiveData()
|
||||
|
||||
@JvmField
|
||||
protected val errorEvent = SingleLiveEvent<Throwable>()
|
||||
|
||||
val onError: LiveData<Throwable>
|
||||
@@ -46,4 +54,4 @@ abstract class BaseViewModel : ViewModel() {
|
||||
errorEvent.postCall(throwable)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.koitharu.kotatsu.base.ui
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
@@ -20,7 +19,7 @@ abstract class CoroutineIntentService : BaseService() {
|
||||
final override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
super.onStartCommand(intent, flags, startId)
|
||||
launchCoroutine(intent, startId)
|
||||
return Service.START_REDELIVER_INTENT
|
||||
return START_REDELIVER_INTENT
|
||||
}
|
||||
|
||||
private fun launchCoroutine(intent: Intent?, startId: Int) = lifecycleScope.launch(errorHandler(startId)) {
|
||||
|
||||
@@ -6,8 +6,6 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
abstract class BoundsScrollListener(private val offsetTop: Int, private val offsetBottom: Int) :
|
||||
RecyclerView.OnScrollListener() {
|
||||
|
||||
constructor(offset: Int = 0) : this(offset, offset)
|
||||
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
val layoutManager = (recyclerView.layoutManager as? LinearLayoutManager) ?: return
|
||||
@@ -28,4 +26,4 @@ abstract class BoundsScrollListener(private val offsetTop: Int, private val offs
|
||||
abstract fun onScrolledToStart(recyclerView: RecyclerView)
|
||||
|
||||
abstract fun onScrolledToEnd(recyclerView: RecyclerView)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.base.ui.util
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import androidx.core.app.ActivityCompat
|
||||
import org.koitharu.kotatsu.base.ui.DefaultActivityLifecycleCallbacks
|
||||
import java.util.WeakHashMap
|
||||
import javax.inject.Inject
|
||||
@@ -22,6 +23,6 @@ class ActivityRecreationHandle @Inject constructor() : DefaultActivityLifecycleC
|
||||
|
||||
fun recreateAll() {
|
||||
val snapshot = activities.keys.toList()
|
||||
snapshot.forEach { it.recreate() }
|
||||
snapshot.forEach { ActivityCompat.recreate(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package org.koitharu.kotatsu.base.ui.util
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
|
||||
@EntryPoint
|
||||
@@ -11,8 +10,3 @@ import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
interface BaseActivityEntryPoint {
|
||||
val settings: AppSettings
|
||||
}
|
||||
|
||||
// Hilt cannot inject into parametrized classes
|
||||
fun BaseActivityEntryPoint.inject(activity: BaseActivity<*>) {
|
||||
activity.settings = settings
|
||||
}
|
||||
|
||||
@@ -10,8 +10,10 @@ class WindowInsetsDelegate(
|
||||
private val listener: WindowInsetsListener,
|
||||
) : OnApplyWindowInsetsListener, View.OnLayoutChangeListener {
|
||||
|
||||
@JvmField
|
||||
var handleImeInsets: Boolean = false
|
||||
|
||||
@JvmField
|
||||
var interceptingWindowInsetsListener: OnApplyWindowInsetsListener? = null
|
||||
|
||||
private var lastInsets: Insets? = null
|
||||
@@ -63,4 +65,4 @@ class WindowInsetsDelegate(
|
||||
|
||||
fun onWindowInsetsChanged(insets: Insets)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.utils.ext.toList
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@@ -28,10 +29,14 @@ class MangaLoaderContextImpl @Inject constructor(
|
||||
@ApplicationContext private val androidContext: Context,
|
||||
) : MangaLoaderContext() {
|
||||
|
||||
private var webViewCached: WeakReference<WebView>? = null
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
override suspend fun evaluateJs(script: String): String? = withContext(Dispatchers.Main) {
|
||||
val webView = WebView(androidContext)
|
||||
webView.settings.javaScriptEnabled = true
|
||||
val webView = webViewCached?.get() ?: WebView(androidContext).also {
|
||||
it.settings.javaScriptEnabled = true
|
||||
webViewCached = WeakReference(it)
|
||||
}
|
||||
suspendCoroutine { cont ->
|
||||
webView.evaluateJavascript(script) { result ->
|
||||
cont.resume(result?.takeUnless { it == "null" })
|
||||
|
||||
@@ -12,13 +12,12 @@ import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.prefs.observeAsFlow
|
||||
import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner
|
||||
|
||||
class ExitCallback(
|
||||
private val activity: BaseActivity<*>,
|
||||
private val activity: MainActivity,
|
||||
private val snackbarHost: View,
|
||||
) : OnBackPressedCallback(false) {
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.base.ui.widgets.SlidingBottomNavigationView
|
||||
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.databinding.ActivityMainBinding
|
||||
import org.koitharu.kotatsu.details.service.MangaPrefetchService
|
||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
||||
@@ -68,6 +69,7 @@ import org.koitharu.kotatsu.utils.ext.resolve
|
||||
import org.koitharu.kotatsu.utils.ext.scaleUpActivityOptionsOf
|
||||
import org.koitharu.kotatsu.utils.ext.setNavigationBarTransparentCompat
|
||||
import org.koitharu.kotatsu.utils.ext.tryLaunch
|
||||
import javax.inject.Inject
|
||||
import com.google.android.material.R as materialR
|
||||
|
||||
private const val TAG_SEARCH = "search"
|
||||
@@ -82,6 +84,9 @@ class MainActivity :
|
||||
SearchSuggestionListener,
|
||||
MainNavigationDelegate.OnFragmentChangedListener {
|
||||
|
||||
@Inject
|
||||
lateinit var settings: AppSettings
|
||||
|
||||
private val viewModel by viewModels<MainViewModel>()
|
||||
private val searchSuggestionViewModel by viewModels<SearchSuggestionViewModel>()
|
||||
private val voiceInputLauncher = registerForActivityResult(VoiceInputContract(), VoiceInputCallback())
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.koitharu.kotatsu.base.ui.BaseFullscreenActivity
|
||||
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
|
||||
import org.koitharu.kotatsu.core.exceptions.resolve.DialogErrorObserver
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.prefs.ReaderMode
|
||||
import org.koitharu.kotatsu.databinding.ActivityReaderBinding
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
@@ -66,6 +67,9 @@ class ReaderActivity :
|
||||
OnApplyWindowInsetsListener,
|
||||
IdlingDetector.Callback {
|
||||
|
||||
@Inject
|
||||
lateinit var settings: AppSettings
|
||||
|
||||
private val idlingDetector = IdlingDetector(TimeUnit.SECONDS.toMillis(10), this)
|
||||
|
||||
private val viewModel: ReaderViewModel by viewModels()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.koitharu.kotatsu.scrobbling.mal.data
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Base64
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
@@ -20,7 +21,7 @@ import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
|
||||
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerMangaInfo
|
||||
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
|
||||
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerUser
|
||||
import org.koitharu.kotatsu.utils.PKCEGenerator
|
||||
import java.security.SecureRandom
|
||||
|
||||
private const val REDIRECT_URI = "kotatsu://mal-auth"
|
||||
private const val BASE_WEB_URL = "https://myanimelist.net"
|
||||
@@ -35,7 +36,7 @@ class MALRepository(
|
||||
) : ScrobblerRepository {
|
||||
|
||||
private val clientId = context.getString(R.string.mal_clientId)
|
||||
private var codeVerifier: String = getPKCEChallengeCode()
|
||||
private val codeVerifier: String by lazy(::generateCodeVerifier)
|
||||
|
||||
override val oauthUrl: String
|
||||
get() = "$BASE_WEB_URL/v1/oauth2/authorize?" +
|
||||
@@ -177,11 +178,6 @@ class MALRepository(
|
||||
storage.clear()
|
||||
}
|
||||
|
||||
private fun getPKCEChallengeCode(): String {
|
||||
codeVerifier = PKCEGenerator.generateCodeVerifier()
|
||||
return codeVerifier
|
||||
}
|
||||
|
||||
private fun jsonToManga(json: JSONObject): ScrobblerManga? {
|
||||
for (i in 0 until json.length()) {
|
||||
val node = json.getJSONObject("node")
|
||||
@@ -210,4 +206,10 @@ class MALRepository(
|
||||
avatar = json.getString("picture") ?: AVATAR_STUB,
|
||||
service = ScrobblerService.MAL,
|
||||
)
|
||||
|
||||
private fun generateCodeVerifier(): String {
|
||||
val codeVerifier = ByteArray(50)
|
||||
SecureRandom().nextBytes(codeVerifier)
|
||||
return Base64.encodeToString(codeVerifier, Base64.NO_WRAP or Base64.NO_PADDING or Base64.URL_SAFE)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.base.ui.list.ListSelectionController
|
||||
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.databinding.ActivitySearchMultiBinding
|
||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
||||
import org.koitharu.kotatsu.download.ui.service.DownloadService
|
||||
@@ -45,6 +46,9 @@ class MultiSearchActivity :
|
||||
@Inject
|
||||
lateinit var coil: ImageLoader
|
||||
|
||||
@Inject
|
||||
lateinit var settings: AppSettings
|
||||
|
||||
private val viewModel by viewModels<MultiSearchViewModel>()
|
||||
private lateinit var adapter: MultiSearchAdapter
|
||||
private lateinit var selectionController: ListSelectionController
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
package org.koitharu.kotatsu.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
|
||||
object InternalResourceHelper {
|
||||
|
||||
fun getBoolean(context: Context, resName: String, defaultValue: Boolean): Boolean {
|
||||
val id = getResourceId(resName, "bool")
|
||||
return if (id != 0) {
|
||||
context.createPackageContext("android", 0).resources.getBoolean(id)
|
||||
} else {
|
||||
defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get resource id from system resources
|
||||
* @param resName resource name to get
|
||||
* @param type resource type of [resName] to get
|
||||
* @return 0 if not available
|
||||
*/
|
||||
private fun getResourceId(resName: String, type: String): Int {
|
||||
return Resources.getSystem().getIdentifier(resName, type, "android")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package org.koitharu.kotatsu.utils
|
||||
|
||||
import android.util.Base64
|
||||
import java.security.SecureRandom
|
||||
|
||||
object PKCEGenerator {
|
||||
|
||||
private const val PKCE_BASE64_ENCODE_SETTINGS = Base64.NO_WRAP or Base64.NO_PADDING or Base64.URL_SAFE
|
||||
|
||||
fun generateCodeVerifier(): String {
|
||||
val codeVerifier = ByteArray(50)
|
||||
SecureRandom().nextBytes(codeVerifier)
|
||||
return Base64.encodeToString(codeVerifier, PKCE_BASE64_ENCODE_SETTINGS)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
package org.koitharu.kotatsu.utils
|
||||
|
||||
import android.view.View
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.google.android.material.badge.BadgeDrawable
|
||||
import com.google.android.material.badge.BadgeUtils
|
||||
import com.google.android.material.badge.ExperimentalBadgeUtils
|
||||
|
||||
@OptIn(ExperimentalBadgeUtils::class)
|
||||
class ViewBadge(
|
||||
private val anchor: View,
|
||||
lifecycleOwner: LifecycleOwner,
|
||||
|
||||
@@ -40,7 +40,6 @@ import org.json.JSONException
|
||||
import org.jsoup.internal.StringUtil.StringJoiner
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.utils.InternalResourceHelper
|
||||
import org.xmlpull.v1.XmlPullParser
|
||||
import org.xmlpull.v1.XmlPullParserException
|
||||
import kotlin.math.roundToLong
|
||||
@@ -108,7 +107,7 @@ fun SyncResult.onError(error: Throwable) {
|
||||
|
||||
fun Window.setNavigationBarTransparentCompat(context: Context, elevation: Float, alphaFactor: Float = 0.7f) {
|
||||
navigationBarColor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
|
||||
!InternalResourceHelper.getBoolean(context, "config_navBarNeedsScrim", true)
|
||||
!context.getSystemBoolean("config_navBarNeedsScrim", true)
|
||||
) {
|
||||
Color.TRANSPARENT
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.koitharu.kotatsu.utils.ext
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import androidx.annotation.Px
|
||||
import kotlin.math.roundToInt
|
||||
@@ -9,3 +11,13 @@ fun Resources.resolveDp(dp: Int) = (dp * displayMetrics.density).roundToInt()
|
||||
|
||||
@Px
|
||||
fun Resources.resolveDp(dp: Float) = dp * displayMetrics.density
|
||||
|
||||
@SuppressLint("DiscouragedApi")
|
||||
fun Context.getSystemBoolean(resName: String, fallback: Boolean): Boolean {
|
||||
val id = Resources.getSystem().getIdentifier(resName, "bool", "android")
|
||||
return if (id != 0) {
|
||||
createPackageContext("android", 0).resources.getBoolean(id)
|
||||
} else {
|
||||
fallback
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user