Theme Compose SwipeRefresh indicator like XML version
Also rename some screens/controllers to better represent that they're the list views.
This commit is contained in:
parent
cbc114608b
commit
01e04e31bf
7 changed files with 63 additions and 65 deletions
|
@ -40,6 +40,7 @@ import com.google.accompanist.swiperefresh.SwipeRefresh
|
|||
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
|
||||
import eu.kanade.presentation.browse.components.BaseBrowseItem
|
||||
import eu.kanade.presentation.browse.components.ExtensionIcon
|
||||
import eu.kanade.presentation.components.SwipeRefreshIndicator
|
||||
import eu.kanade.presentation.theme.header
|
||||
import eu.kanade.presentation.util.horizontalPadding
|
||||
import eu.kanade.presentation.util.plus
|
||||
|
@ -73,12 +74,12 @@ fun ExtensionScreen(
|
|||
SwipeRefresh(
|
||||
modifier = Modifier.nestedScroll(nestedScrollInterop),
|
||||
state = rememberSwipeRefreshState(isRefreshing),
|
||||
indicator = { s, trigger -> SwipeRefreshIndicator(s, trigger) },
|
||||
onRefresh = onRefresh,
|
||||
) {
|
||||
when (state) {
|
||||
is ExtensionState.Initialized -> {
|
||||
ExtensionContent(
|
||||
nestedScrollInterop = nestedScrollInterop,
|
||||
items = (state as ExtensionState.Initialized).list,
|
||||
onLongClickItem = onLongClickItem,
|
||||
onClickItemCancel = onClickItemCancel,
|
||||
|
@ -98,7 +99,6 @@ fun ExtensionScreen(
|
|||
|
||||
@Composable
|
||||
fun ExtensionContent(
|
||||
nestedScrollInterop: NestedScrollConnection,
|
||||
items: List<ExtensionUiModel>,
|
||||
onLongClickItem: (Extension) -> Unit,
|
||||
onClickItemCancel: (Extension) -> Unit,
|
||||
|
@ -112,7 +112,6 @@ fun ExtensionContent(
|
|||
) {
|
||||
val (trustState, setTrustState) = remember { mutableStateOf<Extension.Untrusted?>(null) }
|
||||
LazyColumn(
|
||||
modifier = Modifier.nestedScroll(nestedScrollInterop),
|
||||
contentPadding = WindowInsets.navigationBars.asPaddingValues() + topPaddingValues,
|
||||
) {
|
||||
items(
|
||||
|
|
|
@ -22,14 +22,14 @@ import eu.kanade.presentation.components.LoadingScreen
|
|||
import eu.kanade.presentation.components.PreferenceRow
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.source.FilterUiModel
|
||||
import eu.kanade.tachiyomi.ui.browse.source.SourceFilterPresenter
|
||||
import eu.kanade.tachiyomi.ui.browse.source.SourceFilterState
|
||||
import eu.kanade.tachiyomi.ui.browse.source.SourcesFilterPresenter
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
|
||||
@Composable
|
||||
fun SourceFilterScreen(
|
||||
fun SourcesFilterScreen(
|
||||
nestedScrollInterop: NestedScrollConnection,
|
||||
presenter: SourceFilterPresenter,
|
||||
presenter: SourcesFilterPresenter,
|
||||
onClickLang: (String) -> Unit,
|
||||
onClickSource: (Source) -> Unit,
|
||||
) {
|
||||
|
@ -39,7 +39,7 @@ fun SourceFilterScreen(
|
|||
is SourceFilterState.Loading -> LoadingScreen()
|
||||
is SourceFilterState.Error -> Text(text = (state as SourceFilterState.Error).error.message!!)
|
||||
is SourceFilterState.Success ->
|
||||
SourceFilterContent(
|
||||
SourcesFilterContent(
|
||||
nestedScrollInterop = nestedScrollInterop,
|
||||
items = (state as SourceFilterState.Success).models,
|
||||
onClickLang = onClickLang,
|
||||
|
@ -49,7 +49,7 @@ fun SourceFilterScreen(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun SourceFilterContent(
|
||||
fun SourcesFilterContent(
|
||||
nestedScrollInterop: NestedScrollConnection,
|
||||
items: List<FilterUiModel>,
|
||||
onClickLang: (String) -> Unit,
|
||||
|
@ -81,14 +81,14 @@ fun SourceFilterContent(
|
|||
) { model ->
|
||||
when (model) {
|
||||
is FilterUiModel.Header -> {
|
||||
SourceFilterHeader(
|
||||
SourcesFilterHeader(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
language = model.language,
|
||||
isEnabled = model.isEnabled,
|
||||
onClickItem = onClickLang,
|
||||
)
|
||||
}
|
||||
is FilterUiModel.Item -> SourceFilterItem(
|
||||
is FilterUiModel.Item -> SourcesFilterItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
source = model.source,
|
||||
isEnabled = model.isEnabled,
|
||||
|
@ -100,7 +100,7 @@ fun SourceFilterContent(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun SourceFilterHeader(
|
||||
fun SourcesFilterHeader(
|
||||
modifier: Modifier,
|
||||
language: String,
|
||||
isEnabled: Boolean,
|
||||
|
@ -117,7 +117,7 @@ fun SourceFilterHeader(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun SourceFilterItem(
|
||||
fun SourcesFilterItem(
|
||||
modifier: Modifier,
|
||||
source: Source,
|
||||
isEnabled: Boolean,
|
|
@ -6,22 +6,26 @@ import androidx.compose.foundation.layout.aspectRatio
|
|||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.graphics.painter.ColorPainter
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.imageResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import coil.compose.AsyncImage
|
||||
import eu.kanade.domain.source.model.Source
|
||||
import eu.kanade.presentation.util.bitmapPainterResource
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.ui.browse.extension.Result
|
||||
import eu.kanade.tachiyomi.ui.browse.extension.getIcon
|
||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||
|
||||
private val defaultModifier = Modifier
|
||||
.height(40.dp)
|
||||
|
@ -89,3 +93,27 @@ fun ExtensionIcon(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Extension.getIcon(): State<Result<ImageBitmap>> {
|
||||
val context = LocalContext.current
|
||||
return produceState<Result<ImageBitmap>>(initialValue = Result.Loading, this) {
|
||||
withIOContext {
|
||||
value = try {
|
||||
Result.Success(
|
||||
context.packageManager.getApplicationIcon(pkgName)
|
||||
.toBitmap()
|
||||
.asImageBitmap(),
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Result.Error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class Result<out T> {
|
||||
object Loading : Result<Nothing>()
|
||||
object Error : Result<Nothing>()
|
||||
data class Success<out T>(val value: T) : Result<T>()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package eu.kanade.presentation.components
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import com.google.accompanist.swiperefresh.SwipeRefreshState
|
||||
import com.google.accompanist.swiperefresh.SwipeRefreshIndicator as AccompanistSwipeRefreshIndicator
|
||||
|
||||
@Composable
|
||||
fun SwipeRefreshIndicator(state: SwipeRefreshState, refreshTrigger: Dp) {
|
||||
AccompanistSwipeRefreshIndicator(
|
||||
state = state,
|
||||
refreshTriggerDistance = refreshTrigger,
|
||||
backgroundColor = MaterialTheme.colorScheme.primary,
|
||||
contentColor = MaterialTheme.colorScheme.onPrimary,
|
||||
)
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package eu.kanade.tachiyomi.ui.browse.extension
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||
|
||||
fun Extension.getApplicationIcon(context: Context): Drawable? {
|
||||
return try {
|
||||
context.packageManager.getApplicationIcon(pkgName)
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Extension.getIcon(): State<Result<ImageBitmap>> {
|
||||
val context = LocalContext.current
|
||||
return produceState<Result<ImageBitmap>>(initialValue = Result.Loading, this) {
|
||||
withIOContext {
|
||||
value = try {
|
||||
Result.Success(
|
||||
context.packageManager.getApplicationIcon(pkgName)
|
||||
.toBitmap()
|
||||
.asImageBitmap(),
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Result.Error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class Result<out T> {
|
||||
object Loading : Result<Nothing>()
|
||||
object Error : Result<Nothing>()
|
||||
data class Success<out T>(val value: T) : Result<T>()
|
||||
}
|
|
@ -3,19 +3,19 @@ package eu.kanade.tachiyomi.ui.browse.source
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import eu.kanade.domain.source.model.Source
|
||||
import eu.kanade.presentation.browse.SourceFilterScreen
|
||||
import eu.kanade.presentation.browse.SourcesFilterScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.ComposeController
|
||||
|
||||
class SourceFilterController : ComposeController<SourceFilterPresenter>() {
|
||||
class SourceFilterController : ComposeController<SourcesFilterPresenter>() {
|
||||
|
||||
override fun getTitle() = resources?.getString(R.string.label_sources)
|
||||
|
||||
override fun createPresenter(): SourceFilterPresenter = SourceFilterPresenter()
|
||||
override fun createPresenter(): SourcesFilterPresenter = SourcesFilterPresenter()
|
||||
|
||||
@Composable
|
||||
override fun ComposeContent(nestedScrollInterop: NestedScrollConnection) {
|
||||
SourceFilterScreen(
|
||||
SourcesFilterScreen(
|
||||
nestedScrollInterop = nestedScrollInterop,
|
||||
presenter = presenter,
|
||||
onClickLang = { language ->
|
|
@ -16,7 +16,7 @@ import kotlinx.coroutines.flow.collectLatest
|
|||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class SourceFilterPresenter(
|
||||
class SourcesFilterPresenter(
|
||||
private val getLanguagesWithSources: GetLanguagesWithSources = Injekt.get(),
|
||||
private val toggleSource: ToggleSource = Injekt.get(),
|
||||
private val toggleLanguage: ToggleLanguage = Injekt.get(),
|
Reference in a new issue