Updated on 2026-08-14
This commit is contained in:
parent
2de92a1101
commit
e513b24234
15 changed files with 57 additions and 68 deletions
|
|
@ -10,7 +10,6 @@ import androidx.compose.material3.ButtonColors
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.tangem.core.ui.R
|
||||
|
|
@ -190,7 +189,6 @@ fun PrimaryButtonIconStart(
|
|||
enabled: Boolean = true,
|
||||
tint: Color? = null,
|
||||
size: TangemButtonSize = TangemButtonSize.Default,
|
||||
shape: Shape = size.toShape(),
|
||||
) {
|
||||
TangemButton(
|
||||
modifier = modifier,
|
||||
|
|
@ -205,7 +203,6 @@ fun PrimaryButtonIconStart(
|
|||
showProgress = showProgress,
|
||||
textStyle = TangemTheme.typography.subtitle1,
|
||||
size = size,
|
||||
shape = shape,
|
||||
)
|
||||
}
|
||||
// endregion PrimaryButton
|
||||
|
|
@ -219,7 +216,6 @@ fun SecondaryButton(
|
|||
showProgress: Boolean = false,
|
||||
enabled: Boolean = true,
|
||||
size: TangemButtonSize = TangemButtonSize.Default,
|
||||
shape: Shape = size.toShape(),
|
||||
) {
|
||||
TangemButton(
|
||||
modifier = modifier,
|
||||
|
|
@ -230,7 +226,6 @@ fun SecondaryButton(
|
|||
enabled = enabled,
|
||||
showProgress = showProgress,
|
||||
size = size,
|
||||
shape = shape,
|
||||
textStyle = TangemTheme.typography.subtitle1,
|
||||
)
|
||||
}
|
||||
|
|
@ -248,7 +243,6 @@ fun SecondaryButtonIconEnd(
|
|||
enabled: Boolean = true,
|
||||
tint: Color? = null,
|
||||
size: TangemButtonSize = TangemButtonSize.Default,
|
||||
shape: Shape = size.toShape(),
|
||||
) {
|
||||
TangemButton(
|
||||
modifier = modifier,
|
||||
|
|
@ -263,7 +257,6 @@ fun SecondaryButtonIconEnd(
|
|||
showProgress = showProgress,
|
||||
textStyle = TangemTheme.typography.subtitle1,
|
||||
size = size,
|
||||
shape = shape,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -280,7 +273,6 @@ fun SecondaryButtonIconStart(
|
|||
enabled: Boolean = true,
|
||||
iconTint: Color? = null,
|
||||
size: TangemButtonSize = TangemButtonSize.Default,
|
||||
shape: Shape = size.toShape(),
|
||||
) {
|
||||
TangemButton(
|
||||
modifier = modifier,
|
||||
|
|
@ -295,7 +287,6 @@ fun SecondaryButtonIconStart(
|
|||
showProgress = showProgress,
|
||||
textStyle = TangemTheme.typography.subtitle1,
|
||||
size = size,
|
||||
shape = shape,
|
||||
)
|
||||
}
|
||||
// endregion SecondaryButton
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import androidx.compose.animation.fadeIn
|
|||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.text.TextAutoSize
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -14,7 +15,6 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
|
|
@ -42,7 +42,6 @@ fun TangemButton(
|
|||
size: TangemButtonSize = TangemButtonSize.Default,
|
||||
elevation: ButtonElevation = TangemButtonsDefaults.elevation,
|
||||
textStyle: TextStyle = TangemTheme.typography.button,
|
||||
shape: Shape = size.toShape(),
|
||||
iconPadding: Dp = size.toIconPadding(),
|
||||
animateContentChange: Boolean = false,
|
||||
) {
|
||||
|
|
@ -57,7 +56,7 @@ fun TangemButton(
|
|||
},
|
||||
enabled = enabled,
|
||||
elevation = elevation,
|
||||
shape = shape,
|
||||
shape = CircleShape,
|
||||
colors = colors,
|
||||
contentPadding = size.toContentPadding(icon = icon),
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.tangem.core.ui.components.buttons.common
|
|||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
|
@ -32,19 +31,6 @@ internal fun TangemButtonSize.toHeightDp(): Dp = when (this) {
|
|||
TangemButtonSize.Small -> 24.dp
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
internal fun TangemButtonSize.toShape(): Shape = when (this) {
|
||||
TangemButtonSize.Default -> TangemTheme.shapes.roundedCornersXMedium
|
||||
TangemButtonSize.WideAction -> TangemTheme.shapes.roundedCornersMedium
|
||||
TangemButtonSize.Text -> TangemTheme.shapes.roundedCornersSmall
|
||||
TangemButtonSize.Selector -> TangemTheme.shapes.roundedCornersSmall
|
||||
TangemButtonSize.Action -> TangemTheme.shapes.roundedCornersMedium
|
||||
TangemButtonSize.TwoLines -> TangemTheme.shapes.roundedCornersXMedium
|
||||
TangemButtonSize.RoundedAction -> TangemTheme.shapes.roundedCornersLarge
|
||||
TangemButtonSize.Small -> TangemTheme.shapes.roundedCornersXMedium
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
internal fun TangemButtonSize.toIconPadding(): Dp = when (this) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.height
|
|||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.ButtonColors
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Surface
|
||||
|
|
@ -43,7 +44,6 @@ import androidx.compose.ui.draw.drawBehind
|
|||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
|
|
@ -104,7 +104,6 @@ internal fun TangemHoldToConfirmButton(
|
|||
colors: ButtonColors = TangemButtonsDefaults.primaryButtonColors,
|
||||
size: TangemButtonSize = TangemButtonSize.Default,
|
||||
textStyle: TextStyle = TangemTheme.typography.button,
|
||||
shape: Shape = size.toShape(),
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val state = rememberHoldToConfirmState()
|
||||
|
|
@ -162,14 +161,14 @@ internal fun TangemHoldToConfirmButton(
|
|||
onConfirm = onConfirm,
|
||||
),
|
||||
),
|
||||
shape = shape,
|
||||
shape = CircleShape,
|
||||
color = containerColor,
|
||||
) {
|
||||
HoldToConfirmButtonContent(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = buttonHeight)
|
||||
.clip(shape),
|
||||
.clip(CircleShape),
|
||||
contentPadding = contentPadding,
|
||||
state = state,
|
||||
shouldShowProgress = shouldShowProgress,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import androidx.compose.animation.core.tween
|
|||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.text.TextAutoSize
|
||||
import androidx.compose.material.ripple.RippleAlpha
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
|
|
@ -229,19 +229,14 @@ private fun TangemButtonIcon(tangemIconUM: TangemIconUM?, isVisible: Boolean, si
|
|||
/**
|
||||
* Defines the shape of the Tangem button.
|
||||
*/
|
||||
@Deprecated("All buttons are rounded by design")
|
||||
enum class TangemButtonShape {
|
||||
Default,
|
||||
Rounded,
|
||||
;
|
||||
|
||||
@ReadOnlyComposable
|
||||
@Composable
|
||||
internal fun toShape(size: TangemButtonSize) = RoundedCornerShape(
|
||||
when (this) {
|
||||
Default -> size.toShapeRadius()
|
||||
Rounded -> 100.dp
|
||||
},
|
||||
)
|
||||
@Suppress("UnusedParameter")
|
||||
internal fun toShape(size: TangemButtonSize) = CircleShape
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -309,18 +304,6 @@ enum class TangemButtonSize {
|
|||
-> TangemTheme.dimens2.x7
|
||||
}
|
||||
|
||||
@ReadOnlyComposable
|
||||
@Composable
|
||||
internal fun toShapeRadius() = when (this) {
|
||||
X7,
|
||||
X8,
|
||||
X9,
|
||||
X10,
|
||||
-> TangemTheme.dimens2.x2
|
||||
X12 -> TangemTheme.dimens2.x3
|
||||
X15 -> TangemTheme.dimens2.x4
|
||||
}
|
||||
|
||||
@ReadOnlyComposable
|
||||
@Composable
|
||||
internal fun toTextStyle(): TextStyle = when (this) {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import com.tangem.core.ui.extensions.TextReference
|
|||
* @param isEnabled Boolean indicating whether the button is enabled.
|
||||
* @param isLoading Boolean indicating whether the button is in a loading state.
|
||||
* @param size TangemButtonSize defining the size of the button.
|
||||
* @param shape TangemButtonShape defining the shape of the button.
|
||||
* @param shape TangemButtonShape defining the shape of the button. UPD all buttons are rounded.
|
||||
* @param type TangemButtonType defining the style type of the button.
|
||||
* @param onClick Lambda to be invoked when the button is clicked.
|
||||
* @param onLongClick Lambda to be invoked when the button is long-clicked.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import androidx.compose.runtime.LaunchedEffect
|
|||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.LifecycleStartEffect
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
|
|
@ -17,6 +18,7 @@ import com.tangem.core.decompose.context.childByContext
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.components.bottomsheets.state.BottomSheetState
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.core.ui.decompose.ComposableModularBottomSheetContentComponent
|
||||
import com.tangem.core.ui.decompose.EmptyComposableBottomSheetComponent
|
||||
import com.tangem.features.commonfeatures.api.addtoportfolio.AddToPortfolioComponent
|
||||
|
|
@ -84,7 +86,9 @@ internal class DefaultFeedComponent(
|
|||
FeedList(
|
||||
modifier = modifier,
|
||||
state = state,
|
||||
promoBannersBlockComponent = promoBannersBlockComponent,
|
||||
promoBannersBlockComponent = ComposableContentComponent { promoModifier ->
|
||||
promoBannersBlockComponent.ContentWithPadding(modifier = promoModifier, horizontalItemPadding = 16.dp)
|
||||
},
|
||||
contentPadding = contentPadding,
|
||||
)
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
|
|
|
|||
|
|
@ -114,9 +114,8 @@ private fun FeedListContent(
|
|||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
promoBannersBlockComponent?.Content(
|
||||
modifier = Modifier.padding(top = 12.dp, start = 16.dp, end = 16.dp),
|
||||
)
|
||||
promoBannersBlockComponent?.Content(modifier = Modifier.padding(top = 12.dp))
|
||||
|
||||
SpacerH(32.dp)
|
||||
|
||||
NewsBlock(
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ internal fun StoriesButton(
|
|||
colors = if (useDarkerColors) DarkerButtonColors else LighterButtonColors,
|
||||
showProgress = showProgress,
|
||||
enabled = true,
|
||||
shape = TangemTheme.shapes.roundedCornersXMedium,
|
||||
textStyle = TangemTheme.typography.subtitle1,
|
||||
iconPadding = when (icon) {
|
||||
is TangemButtonIconPosition.Start -> TangemTheme.dimens.spacing4
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
package com.tangem.features.promobanners.api
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
|
||||
interface PromoBannersBlockComponent : ComposableContentComponent {
|
||||
interface PromoBannersBlockComponent {
|
||||
|
||||
@Composable
|
||||
fun ContentWithPadding(horizontalItemPadding: Dp, modifier: Modifier)
|
||||
|
||||
fun setVisibleOnScreen(isVisible: Boolean)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.features.promobanners.impl
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
|
|
@ -25,11 +26,12 @@ internal class DefaultPromoBannersBlockComponent @AssistedInject constructor(
|
|||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
override fun ContentWithPadding(horizontalItemPadding: Dp, modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
PromoBannersBlock(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
horizontalItemPadding = horizontalItemPadding,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.SubcomposeLayout
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.lerp
|
||||
import com.tangem.core.ui.components.SpacerH8
|
||||
|
|
@ -36,7 +37,7 @@ import kotlin.math.ceil
|
|||
import kotlin.math.floor
|
||||
|
||||
@Composable
|
||||
internal fun PromoBannersBlock(state: PromoBannersBlockUM, modifier: Modifier = Modifier) {
|
||||
internal fun PromoBannersBlock(state: PromoBannersBlockUM, horizontalItemPadding: Dp, modifier: Modifier = Modifier) {
|
||||
if (state.banners.isEmpty()) return
|
||||
|
||||
val containerColor = bannerContainerColor(state.placeholder)
|
||||
|
|
@ -51,13 +52,14 @@ internal fun PromoBannersBlock(state: PromoBannersBlockUM, modifier: Modifier =
|
|||
SingleBanner(
|
||||
banner = banner,
|
||||
containerColor = containerColor,
|
||||
modifier = modifier,
|
||||
modifier = modifier.padding(horizontal = horizontalItemPadding),
|
||||
)
|
||||
} else {
|
||||
key(state.userWalletId) {
|
||||
BannersCarousel(
|
||||
state = state,
|
||||
containerColor = containerColor,
|
||||
horizontalPadding = horizontalItemPadding,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
|
@ -109,7 +111,12 @@ private fun SingleBanner(banner: PromoBannerNotificationUM, containerColor: Colo
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun BannersCarousel(state: PromoBannersBlockUM, containerColor: Color, modifier: Modifier = Modifier) {
|
||||
private fun BannersCarousel(
|
||||
state: PromoBannersBlockUM,
|
||||
containerColor: Color,
|
||||
horizontalPadding: Dp,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val pagerState = rememberPagerState(
|
||||
initialPage = state.initialPage,
|
||||
pageCount = { state.banners.size },
|
||||
|
|
@ -139,6 +146,7 @@ private fun BannersCarousel(state: PromoBannersBlockUM, containerColor: Color, m
|
|||
banners = state.banners,
|
||||
pagerState = pagerState,
|
||||
containerColor = containerColor,
|
||||
horizontalPadding = horizontalPadding,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
|
||||
|
|
@ -163,6 +171,7 @@ private fun SmoothHeightPager(
|
|||
banners: List<PromoBannerNotificationUM>,
|
||||
pagerState: PagerState,
|
||||
containerColor: Color,
|
||||
horizontalPadding: Dp,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
SubcomposeLayout(modifier = modifier) { constraints ->
|
||||
|
|
@ -206,6 +215,7 @@ private fun SmoothHeightPager(
|
|||
) { page ->
|
||||
val banner = banners.getOrNull(page) ?: return@HorizontalPager
|
||||
BannerNotification(
|
||||
modifier = Modifier.padding(horizontal = horizontalPadding),
|
||||
config = banner.config,
|
||||
containerColor = containerColor,
|
||||
)
|
||||
|
|
@ -253,7 +263,11 @@ private fun previewState(bannerCount: Int) = PromoBannersBlockUM(
|
|||
@Composable
|
||||
private fun Preview_PromoBannersBlock_Legacy() {
|
||||
TangemThemePreview {
|
||||
PromoBannersBlock(state = previewState(bannerCount = 2), modifier = Modifier.padding(16.dp))
|
||||
PromoBannersBlock(
|
||||
state = previewState(bannerCount = 2),
|
||||
horizontalItemPadding = 12.dp,
|
||||
modifier = Modifier.padding(vertical = 16.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -262,7 +276,11 @@ private fun Preview_PromoBannersBlock_Legacy() {
|
|||
@Composable
|
||||
private fun Preview_PromoBannersBlock_Redesign() {
|
||||
TangemThemePreviewRedesign {
|
||||
PromoBannersBlock(state = previewState(bannerCount = 2), modifier = Modifier.padding(16.dp))
|
||||
PromoBannersBlock(
|
||||
state = previewState(bannerCount = 2),
|
||||
modifier = Modifier.padding(vertical = 16.dp),
|
||||
horizontalItemPadding = 12.dp,
|
||||
)
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -295,11 +295,14 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
var headerSize by remember { mutableStateOf(0.dp) }
|
||||
val dialog by dialog.subscribeAsState()
|
||||
val uiState by model.uiState.collectAsStateWithLifecycle()
|
||||
val promoBannersBlockComponentContentComponent = ComposableContentComponent { promoModifier ->
|
||||
promoBannersBlockComponent.ContentWithPadding(modifier = promoModifier, horizontalItemPadding = 12.dp)
|
||||
}
|
||||
|
||||
if (designFeatureToggles.isRedesignEnabled) {
|
||||
WalletScreen2(
|
||||
state = uiState,
|
||||
promoBannersBlockComponent = promoBannersBlockComponent,
|
||||
promoBannersBlockComponent = promoBannersBlockComponentContentComponent,
|
||||
tangemPayComponent = tangemPayMainBlockComponent,
|
||||
virtualAccountComponent = virtualAccountMainBlockComponent,
|
||||
bottomSheetContent = { onExpandSheet ->
|
||||
|
|
@ -316,7 +319,7 @@ internal class WalletComponent @AssistedInject constructor(
|
|||
} else {
|
||||
WalletScreen(
|
||||
state = uiState,
|
||||
promoBannersBlockComponent = promoBannersBlockComponent,
|
||||
promoBannersBlockComponent = promoBannersBlockComponentContentComponent,
|
||||
tangemPayComponent = tangemPayMainBlockComponent,
|
||||
virtualAccountComponent = virtualAccountMainBlockComponent,
|
||||
bottomSheetContent = { onExpandSheet ->
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ internal fun WalletListContent(
|
|||
|
||||
promoBannersBlockComponent?.let { component ->
|
||||
item(key = "PromoBannersBlock") {
|
||||
component.Content(modifier = itemModifier)
|
||||
component.Content(modifier = Modifier.padding(top = TangemTheme.dimens2.x3))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ internal fun BaseExtension.configureCompose(project: Project) {
|
|||
contains(Regex(pattern = ":features:feed:api\$")) || // provides Composable function
|
||||
contains(Regex(pattern = ":features:manage-tokens:api\$")) || // provides Composable function
|
||||
contains(Regex(pattern = ":features:txhistory:api\$")) || // provides Composable function
|
||||
contains(Regex(pattern = ":features:promo-banners:api\$")) || // provides Composable function
|
||||
contains(Regex(pattern = ":impl\$"))
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue