Remove dead code
This commit is contained in:
parent
fe6aa4358f
commit
4f2a794fba
10 changed files with 11 additions and 447 deletions
|
@ -277,7 +277,7 @@ dependencies {
|
||||||
implementation(libs.bundles.conductor)
|
implementation(libs.bundles.conductor)
|
||||||
|
|
||||||
// FlowBinding
|
// FlowBinding
|
||||||
implementation(libs.bundles.flowbinding)
|
implementation(libs.flowbinding.android)
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
implementation(libs.logcat)
|
implementation(libs.logcat)
|
||||||
|
|
|
@ -1,216 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.ui.base.controller
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.text.style.CharacterStyle
|
|
||||||
import android.view.Menu
|
|
||||||
import android.view.MenuInflater
|
|
||||||
import android.view.MenuItem
|
|
||||||
import androidx.appcompat.widget.SearchView
|
|
||||||
import androidx.core.text.getSpans
|
|
||||||
import androidx.core.widget.doAfterTextChanged
|
|
||||||
import androidx.viewbinding.ViewBinding
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import reactivecircus.flowbinding.appcompat.QueryTextEvent
|
|
||||||
import reactivecircus.flowbinding.appcompat.queryTextEvents
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of the NucleusController that has a built-in ViewSearch
|
|
||||||
*/
|
|
||||||
abstract class SearchableNucleusController<VB : ViewBinding, P : BasePresenter<*>>(bundle: Bundle? = null) : NucleusController<VB, P>(bundle) {
|
|
||||||
|
|
||||||
enum class SearchViewState { LOADING, LOADED, COLLAPSING, FOCUSED }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to bypass the initial searchView being set to empty string after an onResume
|
|
||||||
*/
|
|
||||||
private var currentSearchViewState: SearchViewState = SearchViewState.LOADING
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store the query text that has not been submitted to reassign it after an onResume, UI-only
|
|
||||||
*/
|
|
||||||
protected var nonSubmittedQuery: String = ""
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To be called by classes that extend this subclass in onCreateOptionsMenu
|
|
||||||
*/
|
|
||||||
protected fun createOptionsMenu(
|
|
||||||
menu: Menu,
|
|
||||||
inflater: MenuInflater,
|
|
||||||
menuId: Int,
|
|
||||||
searchItemId: Int,
|
|
||||||
) {
|
|
||||||
inflater.inflate(menuId, menu)
|
|
||||||
|
|
||||||
// Initialize search option.
|
|
||||||
val searchItem = menu.findItem(searchItemId)
|
|
||||||
val searchView = searchItem.actionView as SearchView
|
|
||||||
searchItem.fixExpand(onExpand = { invalidateMenuOnExpand() })
|
|
||||||
searchView.maxWidth = Int.MAX_VALUE
|
|
||||||
|
|
||||||
// Remove formatting from pasted text
|
|
||||||
val searchAutoComplete: SearchView.SearchAutoComplete = searchView.findViewById(
|
|
||||||
R.id.search_src_text,
|
|
||||||
)
|
|
||||||
searchAutoComplete.doAfterTextChanged { editable ->
|
|
||||||
editable?.getSpans<CharacterStyle>()?.forEach { editable.removeSpan(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
searchView.queryTextEvents()
|
|
||||||
.onEach {
|
|
||||||
val newText = it.queryText.toString()
|
|
||||||
|
|
||||||
if (newText.isNotBlank() or acceptEmptyQuery()) {
|
|
||||||
if (it is QueryTextEvent.QuerySubmitted) {
|
|
||||||
// Abstract function for implementation
|
|
||||||
// Run it first in case the old query data is needed (like BrowseSourceController)
|
|
||||||
onSearchViewQueryTextSubmit(newText)
|
|
||||||
presenter.query = newText
|
|
||||||
nonSubmittedQuery = ""
|
|
||||||
} else if ((it is QueryTextEvent.QueryChanged) && (presenter.query != newText)) {
|
|
||||||
nonSubmittedQuery = newText
|
|
||||||
|
|
||||||
// Abstract function for implementation
|
|
||||||
onSearchViewQueryTextChange(newText)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// clear the collapsing flag
|
|
||||||
setCurrentSearchViewState(SearchViewState.LOADED, SearchViewState.COLLAPSING)
|
|
||||||
}
|
|
||||||
.launchIn(viewScope)
|
|
||||||
|
|
||||||
val query = presenter.query
|
|
||||||
|
|
||||||
// Restoring a query the user had not submitted
|
|
||||||
if (nonSubmittedQuery.isNotBlank() and (nonSubmittedQuery != query)) {
|
|
||||||
searchItem.expandActionView()
|
|
||||||
searchView.setQuery(nonSubmittedQuery, false)
|
|
||||||
onSearchViewQueryTextChange(nonSubmittedQuery)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workaround for weird behavior where searchView gets empty text change despite
|
|
||||||
// query being set already, prevents the query from being cleared
|
|
||||||
binding.root.post {
|
|
||||||
setCurrentSearchViewState(SearchViewState.LOADED, SearchViewState.LOADING)
|
|
||||||
}
|
|
||||||
|
|
||||||
searchView.setOnQueryTextFocusChangeListener { _, hasFocus ->
|
|
||||||
if (hasFocus) {
|
|
||||||
setCurrentSearchViewState(SearchViewState.FOCUSED)
|
|
||||||
} else {
|
|
||||||
setCurrentSearchViewState(SearchViewState.LOADED, SearchViewState.FOCUSED)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
searchItem.setOnActionExpandListener(
|
|
||||||
object : MenuItem.OnActionExpandListener {
|
|
||||||
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
|
||||||
onSearchMenuItemActionExpand(item)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
|
||||||
val localSearchView = searchItem.actionView as SearchView
|
|
||||||
|
|
||||||
// if it is blank the flow event won't trigger so we would stay in a COLLAPSING state
|
|
||||||
if (localSearchView.toString().isNotBlank()) {
|
|
||||||
setCurrentSearchViewState(SearchViewState.COLLAPSING)
|
|
||||||
}
|
|
||||||
|
|
||||||
onSearchMenuItemActionCollapse(item)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityResumed(activity: Activity) {
|
|
||||||
super.onActivityResumed(activity)
|
|
||||||
// Until everything is up and running don't accept empty queries
|
|
||||||
setCurrentSearchViewState(SearchViewState.LOADING)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun acceptEmptyQuery(): Boolean {
|
|
||||||
return when (currentSearchViewState) {
|
|
||||||
SearchViewState.COLLAPSING, SearchViewState.FOCUSED -> true
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setCurrentSearchViewState(to: SearchViewState, from: SearchViewState? = null) {
|
|
||||||
// When loading ignore all requests other than loaded
|
|
||||||
if ((currentSearchViewState == SearchViewState.LOADING) && (to != SearchViewState.LOADED)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prevent changing back to an unwanted state when using async flows (ie onFocus event doing
|
|
||||||
// COLLAPSING -> LOADED)
|
|
||||||
if ((from != null) && (currentSearchViewState != from)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
currentSearchViewState = to
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by the SearchView since since the implementation of these can vary in subclasses
|
|
||||||
* Not abstract as they are optional
|
|
||||||
*/
|
|
||||||
protected open fun onSearchViewQueryTextChange(newText: String?) {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected open fun onSearchViewQueryTextSubmit(query: String?) {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected open fun onSearchMenuItemActionExpand(item: MenuItem?) {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected open fun onSearchMenuItemActionCollapse(item: MenuItem?) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Workaround for buggy menu item layout after expanding/collapsing an expandable item like a SearchView.
|
|
||||||
* This method should be removed when fixed upstream.
|
|
||||||
* Issue link: https://issuetracker.google.com/issues/37657375
|
|
||||||
*/
|
|
||||||
private var expandActionViewFromInteraction = false
|
|
||||||
|
|
||||||
private fun MenuItem.fixExpand(onExpand: ((MenuItem) -> Boolean)? = null, onCollapse: ((MenuItem) -> Boolean)? = null) {
|
|
||||||
setOnActionExpandListener(
|
|
||||||
object : MenuItem.OnActionExpandListener {
|
|
||||||
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
|
||||||
return onExpand?.invoke(item) ?: true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
|
||||||
activity?.invalidateOptionsMenu()
|
|
||||||
|
|
||||||
return onCollapse?.invoke(item) ?: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
if (expandActionViewFromInteraction) {
|
|
||||||
expandActionViewFromInteraction = false
|
|
||||||
expandActionView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* During the conversion to SearchableNucleusController (after which I plan to merge its code
|
|
||||||
* into BaseController) this addresses an issue where the searchView.onTextFocus event is not
|
|
||||||
* triggered
|
|
||||||
*/
|
|
||||||
private fun invalidateMenuOnExpand(): Boolean {
|
|
||||||
return if (expandActionViewFromInteraction) {
|
|
||||||
activity?.invalidateOptionsMenu()
|
|
||||||
setCurrentSearchViewState(SearchViewState.FOCUSED) // we are technically focused here
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,17 +7,11 @@ import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.MainScope
|
import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
import nucleus.presenter.RxPresenter
|
import nucleus.presenter.RxPresenter
|
||||||
import rx.Observable
|
|
||||||
|
|
||||||
open class BasePresenter<V> : RxPresenter<V>() {
|
open class BasePresenter<V> : RxPresenter<V>() {
|
||||||
|
|
||||||
var presenterScope: CoroutineScope = MainScope()
|
var presenterScope: CoroutineScope = MainScope()
|
||||||
|
|
||||||
/**
|
|
||||||
* Query from the view where applicable
|
|
||||||
*/
|
|
||||||
var query: String = ""
|
|
||||||
|
|
||||||
override fun onCreate(savedState: Bundle?) {
|
override fun onCreate(savedState: Bundle?) {
|
||||||
try {
|
try {
|
||||||
super.onCreate(savedState)
|
super.onCreate(savedState)
|
||||||
|
@ -39,13 +33,4 @@ open class BasePresenter<V> : RxPresenter<V>() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> Preference<T>.asState() = PreferenceMutableState(this, presenterScope)
|
fun <T> Preference<T>.asState() = PreferenceMutableState(this, presenterScope)
|
||||||
|
|
||||||
/**
|
|
||||||
* Subscribes an observable with [deliverLatestCache] and adds it to the presenter's lifecycle
|
|
||||||
* subscription list.
|
|
||||||
*
|
|
||||||
* @param onNext function to execute when the observable emits an item.
|
|
||||||
* @param onError function to execute when the observable throws an error.
|
|
||||||
*/
|
|
||||||
fun <T> Observable<T>.subscribeLatestCache(onNext: (V, T) -> Unit, onError: ((V, Throwable) -> Unit) = { _, _ -> }) = compose(deliverLatestCache<T>()).subscribe(split(onNext, onError)).apply { add(this) }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -898,6 +898,15 @@ class ReaderPresenter(
|
||||||
*/
|
*/
|
||||||
private fun <T> Observable<T>.subscribeFirst(onNext: (ReaderActivity, T) -> Unit, onError: ((ReaderActivity, Throwable) -> Unit) = { _, _ -> }) = compose(deliverFirst<T>()).subscribe(split(onNext, onError)).apply { add(this) }
|
private fun <T> Observable<T>.subscribeFirst(onNext: (ReaderActivity, T) -> Unit, onError: ((ReaderActivity, Throwable) -> Unit) = { _, _ -> }) = compose(deliverFirst<T>()).subscribe(split(onNext, onError)).apply { add(this) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribes an observable with [deliverLatestCache] and adds it to the presenter's lifecycle
|
||||||
|
* subscription list.
|
||||||
|
*
|
||||||
|
* @param onNext function to execute when the observable emits an item.
|
||||||
|
* @param onError function to execute when the observable throws an error.
|
||||||
|
*/
|
||||||
|
private fun <T> Observable<T>.subscribeLatestCache(onNext: (ReaderActivity, T) -> Unit, onError: ((ReaderActivity, Throwable) -> Unit) = { _, _ -> }) = compose(deliverLatestCache<T>()).subscribe(split(onNext, onError)).apply { add(this) }
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// Safe theoretical max filename size is 255 bytes and 1 char = 2-4 bytes (UTF-8)
|
// Safe theoretical max filename size is 255 bytes and 1 char = 2-4 bytes (UTF-8)
|
||||||
private const val MAX_FILE_NAME_BYTES = 250
|
private const val MAX_FILE_NAME_BYTES = 250
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.widget
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import androidx.core.content.withStyledAttributes
|
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import kotlin.math.max
|
|
||||||
|
|
||||||
class AutofitRecyclerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
|
||||||
RecyclerView(context, attrs) {
|
|
||||||
|
|
||||||
private val manager = GridLayoutManager(context, 1)
|
|
||||||
|
|
||||||
private var columnWidth = -1
|
|
||||||
|
|
||||||
var spanCount = 0
|
|
||||||
set(value) {
|
|
||||||
field = value
|
|
||||||
if (value > 0) {
|
|
||||||
manager.spanCount = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val itemWidth: Int
|
|
||||||
get() = measuredWidth / manager.spanCount
|
|
||||||
|
|
||||||
init {
|
|
||||||
if (attrs != null) {
|
|
||||||
val attrsArray = intArrayOf(android.R.attr.columnWidth)
|
|
||||||
context.withStyledAttributes(attrs, attrsArray) {
|
|
||||||
columnWidth = getDimensionPixelSize(0, -1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
layoutManager = manager
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMeasure(widthSpec: Int, heightSpec: Int) {
|
|
||||||
super.onMeasure(widthSpec, heightSpec)
|
|
||||||
if (spanCount == 0 && columnWidth > 0) {
|
|
||||||
val count = max(1, measuredWidth / columnWidth)
|
|
||||||
spanCount = count
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.widget
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import eu.kanade.tachiyomi.databinding.CommonDialogWithCheckboxBinding
|
|
||||||
|
|
||||||
class DialogCheckboxView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
|
||||||
LinearLayout(context, attrs) {
|
|
||||||
|
|
||||||
private val binding: CommonDialogWithCheckboxBinding
|
|
||||||
|
|
||||||
init {
|
|
||||||
binding = CommonDialogWithCheckboxBinding.inflate(LayoutInflater.from(context), this, false)
|
|
||||||
addView(binding.root)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setDescription(@StringRes id: Int) {
|
|
||||||
binding.description.text = context.getString(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setOptionDescription(@StringRes id: Int) {
|
|
||||||
binding.checkboxOption.text = context.getString(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isChecked(): Boolean {
|
|
||||||
return binding.checkboxOption.isChecked
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.widget
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.compose.material3.LocalContentColor
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.platform.AbstractComposeView
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import eu.kanade.presentation.components.EmptyScreen
|
|
||||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
|
||||||
|
|
||||||
class EmptyView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
|
||||||
AbstractComposeView(context, attrs) {
|
|
||||||
|
|
||||||
var message by mutableStateOf("")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hide the information view
|
|
||||||
*/
|
|
||||||
fun hide() {
|
|
||||||
this.isVisible = false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the information view
|
|
||||||
* @param textResource text of information view
|
|
||||||
*/
|
|
||||||
fun show(@StringRes textResource: Int) {
|
|
||||||
message = context.getString(textResource)
|
|
||||||
this.isVisible = true
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun Content() {
|
|
||||||
TachiyomiTheme {
|
|
||||||
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onBackground) {
|
|
||||||
EmptyScreen(message = message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.widget
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import android.view.inputmethod.EditorInfo
|
|
||||||
import androidx.appcompat.widget.SearchView
|
|
||||||
import androidx.core.view.inputmethod.EditorInfoCompat
|
|
||||||
import eu.kanade.domain.base.BasePreferences
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.util.preference.asHotFlow
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.SupervisorJob
|
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A custom [SearchView] that sets [EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING] to imeOptions
|
|
||||||
* if [BasePreferences.incognitoMode] is true. Some IMEs may not respect this flag.
|
|
||||||
*/
|
|
||||||
class TachiyomiSearchView @JvmOverloads constructor(
|
|
||||||
context: Context,
|
|
||||||
attrs: AttributeSet? = null,
|
|
||||||
defStyleAttr: Int = R.attr.searchViewStyle,
|
|
||||||
) : SearchView(context, attrs, defStyleAttr) {
|
|
||||||
|
|
||||||
private var scope: CoroutineScope? = null
|
|
||||||
|
|
||||||
override fun onAttachedToWindow() {
|
|
||||||
super.onAttachedToWindow()
|
|
||||||
scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
|
||||||
Injekt.get<BasePreferences>().incognitoMode()
|
|
||||||
.asHotFlow {
|
|
||||||
imeOptions = if (it) {
|
|
||||||
imeOptions or EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING
|
|
||||||
} else {
|
|
||||||
imeOptions and EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING.inv()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.launchIn(scope!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setOnQueryTextListener(listener: OnQueryTextListener?) {
|
|
||||||
super.setOnQueryTextListener(listener)
|
|
||||||
val searchAutoComplete: SearchAutoComplete = findViewById(R.id.search_src_text)
|
|
||||||
searchAutoComplete.setOnEditorActionListener { _, actionID, _ ->
|
|
||||||
if (actionID == EditorInfo.IME_ACTION_SEARCH || actionID == EditorInfo.IME_NULL) {
|
|
||||||
clearFocus()
|
|
||||||
listener?.onQueryTextSubmit(query.toString())
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDetachedFromWindow() {
|
|
||||||
super.onDetachedFromWindow()
|
|
||||||
scope?.cancel()
|
|
||||||
scope = null
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingHorizontal="24dp"
|
|
||||||
android:paddingTop="16dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/description"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?attr/textAppearanceBodyMedium" />
|
|
||||||
|
|
||||||
<CheckBox
|
|
||||||
android:id="@+id/checkbox_option"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="-5dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginEnd="0dp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
|
@ -4,7 +4,6 @@ okhttp_version = "5.0.0-alpha.10"
|
||||||
nucleus_version = "3.0.0"
|
nucleus_version = "3.0.0"
|
||||||
coil_version = "2.2.2"
|
coil_version = "2.2.2"
|
||||||
conductor_version = "3.1.8"
|
conductor_version = "3.1.8"
|
||||||
flowbinding_version = "1.2.0"
|
|
||||||
shizuku_version = "12.2.0"
|
shizuku_version = "12.2.0"
|
||||||
sqldelight = "1.5.4"
|
sqldelight = "1.5.4"
|
||||||
leakcanary = "2.10"
|
leakcanary = "2.10"
|
||||||
|
@ -68,8 +67,7 @@ wheelpicker = "com.github.commandiron:WheelPickerCompose:1.0.11"
|
||||||
conductor-core = { module = "com.bluelinelabs:conductor", version.ref = "conductor_version" }
|
conductor-core = { module = "com.bluelinelabs:conductor", version.ref = "conductor_version" }
|
||||||
conductor-support-preference = { module = "com.github.tachiyomiorg:conductor-support-preference", version.ref = "conductor_version" }
|
conductor-support-preference = { module = "com.github.tachiyomiorg:conductor-support-preference", version.ref = "conductor_version" }
|
||||||
|
|
||||||
flowbinding-android = { module = "io.github.reactivecircus.flowbinding:flowbinding-android", version.ref = "flowbinding_version" }
|
flowbinding-android = "io.github.reactivecircus.flowbinding:flowbinding-android:1.2.0"
|
||||||
flowbinding-appcompat = { module = "io.github.reactivecircus.flowbinding:flowbinding-appcompat", version.ref = "flowbinding_version" }
|
|
||||||
|
|
||||||
logcat = "com.squareup.logcat:logcat:0.1"
|
logcat = "com.squareup.logcat:logcat:0.1"
|
||||||
|
|
||||||
|
@ -102,7 +100,6 @@ js-engine = ["quickjs-android"]
|
||||||
sqlite = ["sqlitektx", "sqlite-android"]
|
sqlite = ["sqlitektx", "sqlite-android"]
|
||||||
nucleus = ["nucleus-core", "nucleus-supportv7"]
|
nucleus = ["nucleus-core", "nucleus-supportv7"]
|
||||||
coil = ["coil-core", "coil-gif", "coil-compose"]
|
coil = ["coil-core", "coil-gif", "coil-compose"]
|
||||||
flowbinding = ["flowbinding-android", "flowbinding-appcompat"]
|
|
||||||
conductor = ["conductor-core", "conductor-support-preference"]
|
conductor = ["conductor-core", "conductor-support-preference"]
|
||||||
shizuku = ["shizuku-api", "shizuku-provider"]
|
shizuku = ["shizuku-api", "shizuku-provider"]
|
||||||
voyager = ["voyager-navigator", "voyager-transitions"]
|
voyager = ["voyager-navigator", "voyager-transitions"]
|
||||||
|
|
Reference in a new issue