mirror of
https://github.com/amir1376/ab-download-manager.git
synced 2025-02-20 11:43:24 +08:00
upgrade compose version to v1.7.0
This commit is contained in:
parent
59e37b30f9
commit
81b81f9caf
@ -10,12 +10,6 @@ import com.abdownloadmanager.desktop.utils.div
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ripple.LocalRippleTheme
|
||||
import androidx.compose.material.ripple.RippleAlpha
|
||||
import androidx.compose.material.ripple.RippleTheme
|
||||
import androidx.compose.material.ripple.RippleTheme.Companion.defaultRippleAlpha
|
||||
import androidx.compose.material.ripple.RippleTheme.Companion.defaultRippleColor
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
@ -116,10 +110,7 @@ fun ABDownloaderTheme(
|
||||
CompositionLocalProvider(
|
||||
LocalContextMenuRepresentation provides myContextMenuRepresentation(),
|
||||
LocalScrollbarStyle provides myDefaultScrollBarStyle(),
|
||||
// there is a modification in newer version of compose that change line height
|
||||
// I want to remove material design for good but for now I override this
|
||||
LocalRippleTheme provides remember { MyRippleTheme() },
|
||||
LocalIndication provides rememberRipple(),
|
||||
LocalIndication provides ripple(),
|
||||
LocalContentColor provides myColors.onBackground,
|
||||
LocalContentAlpha provides 1f,
|
||||
LocalTextSizes provides textSizes,
|
||||
@ -133,24 +124,6 @@ fun ABDownloaderTheme(
|
||||
}
|
||||
}
|
||||
|
||||
private class MyRippleTheme:RippleTheme{
|
||||
@Composable
|
||||
override fun defaultColor():Color {
|
||||
return defaultRippleColor(
|
||||
contentColor = LocalContentColor.current,
|
||||
lightTheme = myColors.isLight
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun rippleAlpha(): RippleAlpha {
|
||||
return defaultRippleAlpha(
|
||||
contentColor = LocalContentColor.current,
|
||||
lightTheme = myColors.isLight
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class MyContextMenuRepresentation : ContextMenuRepresentation {
|
||||
@Composable
|
||||
override fun Representation(state: ContextMenuState, items: () -> List<ContextMenuItem>) {
|
||||
|
@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Copyright 2023 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
|
||||
*
|
||||
* http://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.abdownloadmanager.desktop.ui.theme
|
||||
|
||||
import androidx.compose.foundation.Indication
|
||||
import androidx.compose.foundation.IndicationNodeFactory
|
||||
import androidx.compose.foundation.interaction.Interaction
|
||||
import androidx.compose.foundation.interaction.InteractionSource
|
||||
import androidx.compose.foundation.interaction.PressInteraction
|
||||
import androidx.compose.material.ripple.RippleAlpha
|
||||
import androidx.compose.material.ripple.createRippleModifierNode
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.ProvidableCompositionLocal
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorProducer
|
||||
import androidx.compose.ui.graphics.isSpecified
|
||||
import androidx.compose.ui.graphics.luminance
|
||||
import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
|
||||
import androidx.compose.ui.node.DelegatableNode
|
||||
import androidx.compose.ui.node.DelegatingNode
|
||||
import androidx.compose.ui.node.ObserverModifierNode
|
||||
import androidx.compose.ui.node.currentValueOf
|
||||
import androidx.compose.ui.node.observeReads
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import com.abdownloadmanager.utils.compose.LocalContentColor
|
||||
|
||||
/**
|
||||
* Creates a Ripple using the provided values and values inferred from the theme.
|
||||
*
|
||||
* A Ripple is a Material implementation of [Indication] that expresses different [Interaction]s
|
||||
* by drawing ripple animations and state layers.
|
||||
*
|
||||
* A Ripple responds to [PressInteraction.Press] by starting a new animation, and
|
||||
* responds to other [Interaction]s by showing a fixed state layer with varying alpha values
|
||||
* depending on the [Interaction].
|
||||
*
|
||||
* [MaterialTheme] provides Ripples using [androidx.compose.foundation.LocalIndication], so a Ripple
|
||||
* will be used as the default [Indication] inside components such as
|
||||
* [androidx.compose.foundation.clickable] and [androidx.compose.foundation.indication], in
|
||||
* addition to Material provided components that use a Ripple as well.
|
||||
*
|
||||
* You can also explicitly create a Ripple and provide it to custom components in order to change
|
||||
* the parameters from the default, such as to create an unbounded ripple with a fixed size.
|
||||
*
|
||||
* To create a Ripple with a manually defined color that can change over time, see the other
|
||||
* [ripple] overload with a [ColorProducer] parameter. This will avoid unnecessary recompositions
|
||||
* when changing the color, and preserve existing ripple state when the color changes.
|
||||
*
|
||||
* @param bounded If true, ripples are clipped by the bounds of the target layout. Unbounded
|
||||
* ripples always animate from the target layout center, bounded ripples animate from the touch
|
||||
* position.
|
||||
* @param radius the radius for the ripple. If [Dp.Unspecified] is provided then the size will be
|
||||
* calculated based on the target layout size.
|
||||
* @param color the color of the ripple. This color is usually the same color used by the text or
|
||||
* iconography in the component. This color will then have [RippleDefaults.rippleAlpha]
|
||||
* applied to calculate the final color used to draw the ripple. If [Color.Unspecified] is
|
||||
* provided the color used will be [RippleDefaults.rippleColor] instead.
|
||||
*/
|
||||
@Stable
|
||||
fun ripple(
|
||||
bounded: Boolean = true,
|
||||
radius: Dp = Dp.Unspecified,
|
||||
color: Color = Color.Unspecified,
|
||||
): IndicationNodeFactory {
|
||||
return if (radius == Dp.Unspecified && color == Color.Unspecified) {
|
||||
if (bounded) return DefaultBoundedRipple else DefaultUnboundedRipple
|
||||
} else {
|
||||
RippleNodeFactory(bounded, radius, color)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Ripple using the provided values and values inferred from the theme.
|
||||
*
|
||||
* A Ripple is a Material implementation of [Indication] that expresses different [Interaction]s
|
||||
* by drawing ripple animations and state layers.
|
||||
*
|
||||
* A Ripple responds to [PressInteraction.Press] by starting a new ripple animation, and
|
||||
* responds to other [Interaction]s by showing a fixed state layer with varying alpha values
|
||||
* depending on the [Interaction].
|
||||
*
|
||||
* [MaterialTheme] provides Ripples using [androidx.compose.foundation.LocalIndication], so a Ripple
|
||||
* will be used as the default [Indication] inside components such as
|
||||
* [androidx.compose.foundation.clickable] and [androidx.compose.foundation.indication], in
|
||||
* addition to Material provided components that use a Ripple as well.
|
||||
*
|
||||
* You can also explicitly create a Ripple and provide it to custom components in order to change
|
||||
* the parameters from the default, such as to create an unbounded ripple with a fixed size.
|
||||
*
|
||||
* To create a Ripple with a static color, see the [ripple] overload with a [Color] parameter. This
|
||||
* overload is optimized for Ripples that have dynamic colors that change over time, to reduce
|
||||
* unnecessary recompositions.
|
||||
*
|
||||
* @param color the color of the ripple. This color is usually the same color used by the text or
|
||||
* iconography in the component. This color will then have [RippleDefaults.rippleAlpha]
|
||||
* applied to calculate the final color used to draw the ripple. If you are creating this
|
||||
* [ColorProducer] outside of composition (where it will be automatically remembered), make sure
|
||||
* that its instance is stable (such as by remembering the object that holds it), or remember the
|
||||
* returned [ripple] object to make sure that ripple nodes are not being created each recomposition.
|
||||
* @param bounded If true, ripples are clipped by the bounds of the target layout. Unbounded
|
||||
* ripples always animate from the target layout center, bounded ripples animate from the touch
|
||||
* position.
|
||||
* @param radius the radius for the ripple. If [Dp.Unspecified] is provided then the size will be
|
||||
* calculated based on the target layout size.
|
||||
*/
|
||||
@Stable
|
||||
fun ripple(
|
||||
color: ColorProducer,
|
||||
bounded: Boolean = true,
|
||||
radius: Dp = Dp.Unspecified,
|
||||
): IndicationNodeFactory {
|
||||
return RippleNodeFactory(bounded, radius, color)
|
||||
}
|
||||
|
||||
/**
|
||||
* Default values used by [ripple].
|
||||
*/
|
||||
object RippleDefaults {
|
||||
/**
|
||||
* Represents the default color that will be used for a ripple if a color has not been
|
||||
* explicitly set on the ripple instance.
|
||||
*
|
||||
* @param contentColor the color of content (text or iconography) in the component that
|
||||
* contains the ripple.
|
||||
* @param lightTheme whether the theme is light or not
|
||||
*/
|
||||
fun rippleColor(
|
||||
contentColor: Color,
|
||||
lightTheme: Boolean,
|
||||
): Color {
|
||||
val contentLuminance = contentColor.luminance()
|
||||
// If we are on a colored surface (typically indicated by low luminance content), the
|
||||
// ripple color should be white.
|
||||
return if (!lightTheme && contentLuminance < 0.5) {
|
||||
Color.White
|
||||
// Otherwise use contentColor
|
||||
} else {
|
||||
contentColor
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the default [RippleAlpha] that will be used for a ripple to indicate different
|
||||
* states.
|
||||
*
|
||||
* @param contentColor the color of content (text or iconography) in the component that
|
||||
* contains the ripple.
|
||||
* @param lightTheme whether the theme is light or not
|
||||
*/
|
||||
fun rippleAlpha(contentColor: Color, lightTheme: Boolean): RippleAlpha {
|
||||
return when {
|
||||
lightTheme -> {
|
||||
if (contentColor.luminance() > 0.5) {
|
||||
LightThemeHighContrastRippleAlpha
|
||||
} else {
|
||||
LightThemeLowContrastRippleAlpha
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
DarkThemeRippleAlpha
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CompositionLocal used for providing [RippleConfiguration] down the tree. This acts as a
|
||||
* tree-local 'override' for ripples used inside components that you cannot directly control, such
|
||||
* as to change the color of a specific component's ripple, or disable it entirely by providing
|
||||
* `null`.
|
||||
*
|
||||
* In most cases you should rely on the default theme behavior for consistency with other components
|
||||
* - this exists as an escape hatch for individual components and is not intended to be used for
|
||||
* full theme customization across an application. For this use case you should instead build your
|
||||
* own custom ripple that queries your design system theme values directly using
|
||||
* [createRippleModifierNode].
|
||||
*/
|
||||
@Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
|
||||
val LocalRippleConfiguration: ProvidableCompositionLocal<RippleConfiguration?> =
|
||||
compositionLocalOf { RippleConfiguration() }
|
||||
|
||||
/**
|
||||
* Configuration for [ripple] appearance, provided using [LocalRippleConfiguration]. In most cases
|
||||
* the default values should be used, for custom design system use cases you should instead
|
||||
* build your own custom ripple using [createRippleModifierNode]. To disable the ripple, provide
|
||||
* `null` using [LocalRippleConfiguration].
|
||||
*
|
||||
* @param color the color override for the ripple. If [Color.Unspecified], then the default color
|
||||
* from the theme will be used instead. Note that if the ripple has a color explicitly set with
|
||||
* the parameter on [ripple], that will always be used instead of this value.
|
||||
* @param rippleAlpha the [RippleAlpha] override for this ripple. If null, then the default alpha
|
||||
* will be used instead.
|
||||
*/
|
||||
@Immutable
|
||||
class RippleConfiguration(
|
||||
val color: Color = Color.Unspecified,
|
||||
val rippleAlpha: RippleAlpha? = null,
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is RippleConfiguration) return false
|
||||
|
||||
if (color != other.color) return false
|
||||
if (rippleAlpha != other.rippleAlpha) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = color.hashCode()
|
||||
result = 31 * result + (rippleAlpha?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "RippleConfiguration(color=$color, rippleAlpha=$rippleAlpha)"
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
private class RippleNodeFactory private constructor(
|
||||
private val bounded: Boolean,
|
||||
private val radius: Dp,
|
||||
private val colorProducer: ColorProducer?,
|
||||
private val color: Color,
|
||||
) : IndicationNodeFactory {
|
||||
constructor(
|
||||
bounded: Boolean,
|
||||
radius: Dp,
|
||||
colorProducer: ColorProducer,
|
||||
) : this(bounded, radius, colorProducer, Color.Unspecified)
|
||||
|
||||
constructor(
|
||||
bounded: Boolean,
|
||||
radius: Dp,
|
||||
color: Color,
|
||||
) : this(bounded, radius, null, color)
|
||||
|
||||
override fun create(interactionSource: InteractionSource): DelegatableNode {
|
||||
val colorProducer = colorProducer ?: ColorProducer { color }
|
||||
return DelegatingThemeAwareRippleNode(interactionSource, bounded, radius, colorProducer)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is RippleNodeFactory) return false
|
||||
|
||||
if (bounded != other.bounded) return false
|
||||
if (radius != other.radius) return false
|
||||
if (colorProducer != other.colorProducer) return false
|
||||
return color == other.color
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = bounded.hashCode()
|
||||
result = 31 * result + radius.hashCode()
|
||||
result = 31 * result + colorProducer.hashCode()
|
||||
result = 31 * result + color.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
private class DelegatingThemeAwareRippleNode(
|
||||
private val interactionSource: InteractionSource,
|
||||
private val bounded: Boolean,
|
||||
private val radius: Dp,
|
||||
private val color: ColorProducer,
|
||||
) : DelegatingNode(), CompositionLocalConsumerModifierNode, ObserverModifierNode {
|
||||
private var rippleNode: DelegatableNode? = null
|
||||
|
||||
override fun onAttach() {
|
||||
updateConfiguration()
|
||||
}
|
||||
|
||||
override fun onObservedReadsChanged() {
|
||||
updateConfiguration()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles [LocalRippleConfiguration] changing between null / non-null. Changes to
|
||||
* [RippleConfiguration.color] and [RippleConfiguration.rippleAlpha] are handled as part of
|
||||
* the ripple definition.
|
||||
*/
|
||||
private fun updateConfiguration() {
|
||||
observeReads {
|
||||
val configuration = currentValueOf(LocalRippleConfiguration)
|
||||
if (configuration == null) {
|
||||
removeRipple()
|
||||
} else {
|
||||
if (rippleNode == null) attachNewRipple()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun attachNewRipple() {
|
||||
val calculateColor = ColorProducer {
|
||||
val userDefinedColor = color()
|
||||
if (userDefinedColor.isSpecified) {
|
||||
userDefinedColor
|
||||
} else {
|
||||
// If this is null, the ripple will be removed, so this should always be non-null in
|
||||
// normal use
|
||||
val rippleConfiguration = currentValueOf(LocalRippleConfiguration)
|
||||
if (rippleConfiguration?.color?.isSpecified == true) {
|
||||
rippleConfiguration.color
|
||||
} else {
|
||||
RippleDefaults.rippleColor(
|
||||
contentColor = currentValueOf(LocalContentColor),
|
||||
lightTheme = currentValueOf(LocalMyColors).isLight
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
val calculateRippleAlpha = {
|
||||
// If this is null, the ripple will be removed, so this should always be non-null in
|
||||
// normal use
|
||||
val rippleConfiguration = currentValueOf(LocalRippleConfiguration)
|
||||
rippleConfiguration?.rippleAlpha ?: RippleDefaults.rippleAlpha(
|
||||
contentColor = currentValueOf(LocalContentColor),
|
||||
lightTheme = currentValueOf(LocalMyColors).isLight
|
||||
)
|
||||
}
|
||||
|
||||
rippleNode = delegate(
|
||||
createRippleModifierNode(
|
||||
interactionSource,
|
||||
bounded,
|
||||
radius,
|
||||
calculateColor,
|
||||
calculateRippleAlpha
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun removeRipple() {
|
||||
rippleNode?.let { undelegate(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private val DefaultBoundedRipple = RippleNodeFactory(
|
||||
bounded = true,
|
||||
radius = Dp.Unspecified,
|
||||
color = Color.Unspecified
|
||||
)
|
||||
|
||||
private val DefaultUnboundedRipple = RippleNodeFactory(
|
||||
bounded = false,
|
||||
radius = Dp.Unspecified,
|
||||
color = Color.Unspecified
|
||||
)
|
||||
|
||||
/**
|
||||
* Alpha values for high luminance content in a light theme.
|
||||
*
|
||||
* This content will typically be placed on colored surfaces, so it is important that the
|
||||
* contrast here is higher to meet accessibility standards, and increase legibility.
|
||||
*
|
||||
* These levels are typically used for text / iconography in primary colored tabs /
|
||||
* bottom navigation / etc.
|
||||
*/
|
||||
private val LightThemeHighContrastRippleAlpha = RippleAlpha(
|
||||
pressedAlpha = 0.24f,
|
||||
focusedAlpha = 0.24f,
|
||||
draggedAlpha = 0.16f,
|
||||
hoveredAlpha = 0.08f
|
||||
)
|
||||
|
||||
/**
|
||||
* Alpha levels for low luminance content in a light theme.
|
||||
*
|
||||
* This content will typically be placed on grayscale surfaces, so the contrast here can be lower
|
||||
* without sacrificing accessibility and legibility.
|
||||
*
|
||||
* These levels are typically used for body text on the main surface (white in light theme, grey
|
||||
* in dark theme) and text / iconography in surface colored tabs / bottom navigation / etc.
|
||||
*/
|
||||
private val LightThemeLowContrastRippleAlpha = RippleAlpha(
|
||||
pressedAlpha = 0.12f,
|
||||
focusedAlpha = 0.12f,
|
||||
draggedAlpha = 0.08f,
|
||||
hoveredAlpha = 0.04f
|
||||
)
|
||||
|
||||
/**
|
||||
* Alpha levels for all content in a dark theme.
|
||||
*/
|
||||
private val DarkThemeRippleAlpha = RippleAlpha(
|
||||
pressedAlpha = 0.10f,
|
||||
focusedAlpha = 0.12f,
|
||||
draggedAlpha = 0.08f,
|
||||
hoveredAlpha = 0.04f
|
||||
)
|
@ -52,7 +52,7 @@ fun ShowOptions(
|
||||
.then(itemPadding)
|
||||
.basicMarquee(
|
||||
iterations = Int.MAX_VALUE,
|
||||
delayMillis = 0
|
||||
initialDelayMillis = 0
|
||||
),
|
||||
fontSize = myTextSizes.base,
|
||||
maxLines = 1,
|
||||
|
@ -1,7 +1,7 @@
|
||||
[versions]
|
||||
kotlin = "2.0.20"
|
||||
ksp = "2.0.20-1.0.25"
|
||||
compose = "1.6.11"
|
||||
compose = "1.7.0"
|
||||
ktorVersion = "2.3.7"
|
||||
kotlin-serialization = "1.7.2"
|
||||
okhttp = "4.12.0"
|
||||
|
@ -5,7 +5,6 @@ import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.res.ClassLoaderResourceLoader
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import okio.FileSystem
|
||||
import okio.Path.Companion.toPath
|
||||
|
Loading…
x
Reference in New Issue
Block a user