Skip to content

Commit

Permalink
Merge branch 'trunk' into update-notificaiton-icon-to-w
Browse files Browse the repository at this point in the history
  • Loading branch information
irfano authored Feb 11, 2025
2 parents ecc67c4 + 81619ae commit a5067ed
Show file tree
Hide file tree
Showing 21 changed files with 153 additions and 161 deletions.
1 change: 1 addition & 0 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- [**] Improved accessibility support (handling of increased text size) in in-person payment flows [https://github.com/woocommerce/woocommerce-android/pull/13414]
- [*] Updated the notification icon for better readability [https://github.com/woocommerce/woocommerce-android/pull/13516]
- [*] Automatically select the first available order when filtering is active in the two-pane layout.[https://github.com/woocommerce/woocommerce-android/pull/13491]
- [*] [Internal] Removal animation of the items from the cart [https://github.com/woocommerce/woocommerce-android/pull/13442]

21.7
-----
Expand Down
3 changes: 2 additions & 1 deletion WooCommerce/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@
<service
android:name=".media.ProductImagesJobService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" />
android:permission="android.permission.BIND_JOB_SERVICE"
tools:ignore="NewApi" />

<!-- Provider for exposing file URIs on Android 7+ (required for camera) -->
<provider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,8 @@ object AppUrls {

const val BLAZE_CAMPAIGN_CREATION_SURVEY_URL_I1 =
"https://wordpressdotcom.survey.fm/blaze-on-woo-mobile-survey-sept-2024-i1"

// POS
const val WOO_POS_DOCUMENTATION_URL =
"https://woocommerce.com/document/woo-mobile-app-point-of-sale-mode/"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.woocommerce.android.ui.barcodescanner

import androidx.activity.compose.ManagedActivityResultLauncher
import androidx.annotation.StringRes
import androidx.camera.core.ExperimentalGetImage
import androidx.camera.core.ImageProxy
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
Expand Down Expand Up @@ -39,6 +40,7 @@ class BarcodeScanningViewModel @Inject constructor(
fun startCodesRecognition() {
frameChannel = createChannel()
processingJob = launch {
@ExperimentalGetImage
for (frame in frameChannel) {
codeScanner.recogniseCode(frame).let { status ->
when (status) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.woocommerce.android.ui.orders.creation

import android.os.Parcelable
import androidx.camera.core.ExperimentalGetImage
import androidx.camera.core.ImageProxy
import com.woocommerce.android.ui.orders.creation.GoogleBarcodeFormatMapper.BarcodeFormat
import kotlinx.parcelize.Parcelize

interface CodeScanner {
@ExperimentalGetImage
suspend fun recogniseCode(imageProxy: ImageProxy): CodeScannerStatus
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.woocommerce.android.ui.orders.creation

import androidx.camera.core.ExperimentalGetImage
import androidx.camera.core.ImageProxy
import com.google.mlkit.vision.barcode.BarcodeScanner
import com.google.mlkit.vision.barcode.common.Barcode
Expand All @@ -14,8 +15,8 @@ class GoogleMLKitCodeScanner @Inject constructor(
private val barcodeFormatMapper: GoogleBarcodeFormatMapper,
private val inputImageProvider: MediaImageProvider,
) : CodeScanner {
@ExperimentalGetImage
override suspend fun recogniseCode(imageProxy: ImageProxy): CodeScannerStatus = suspendCoroutine { cont ->
@androidx.camera.core.ExperimentalGetImage
val image = inputImageProvider.provideImage(imageProxy)

val barcodeTask = barcodeScanner.process(image)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandHorizontally
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkHorizontally
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
Expand Down Expand Up @@ -37,9 +35,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.ColorPainter
Expand Down Expand Up @@ -258,7 +254,7 @@ private fun CartBodyWithItems(
key = { item -> item.id.itemNumber }
) { item ->
ProductItem(
modifier = Modifier,
modifier = Modifier.animateItem(),
item = item,
canRemoveItems = areItemsRemovable,
onUIEvent = onUIEvent,
Expand Down Expand Up @@ -402,117 +398,91 @@ private fun ProductItem(
canRemoveItems: Boolean,
onUIEvent: (WooPosCartUIEvent) -> Unit,
) {
var hasAnimationStarted by remember { mutableStateOf(item.isAppearanceAnimationPlayed) }
LaunchedEffect(Unit) {
hasAnimationStarted = true
}

val cardElevation = 6.dp
val elevation by animateDpAsState(
targetValue = if (hasAnimationStarted) cardElevation else 0.dp,
animationSpec = tween(durationMillis = 150, delayMillis = 250),
label = "elevation"
)

val itemContentDescription = stringResource(
id = R.string.woopos_cart_item_content_description,
item.name,
item.price
)

LaunchedEffect(elevation) {
if (elevation == cardElevation) {
onUIEvent(WooPosCartUIEvent.OnCartItemAppearanceAnimationPlayed(item))
}
}

AnimatedVisibility(
visible = hasAnimationStarted,
enter = expandVertically(
animationSpec = tween(durationMillis = 200)
),
exit = shrinkVertically()
WooPosCard(
modifier = modifier
.height(96.dp)
.semantics { contentDescription = itemContentDescription },
elevation = 6.dp,
shadowType = ShadowType.Soft,
shape = RoundedCornerShape(8.dp),
) {
WooPosCard(
modifier = modifier
.height(96.dp)
.semantics { contentDescription = itemContentDescription },
elevation = elevation,
shadowType = ShadowType.Soft,
shape = RoundedCornerShape(8.dp),
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(item.imageUrl)
.crossfade(true)
.build(),
fallback = ColorPainter(WooPosTheme.colors.loadingSkeleton),
error = ColorPainter(WooPosTheme.colors.loadingSkeleton),
placeholder = ColorPainter(WooPosTheme.colors.loadingSkeleton),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.size(96.dp)
)
AsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(item.imageUrl)
.crossfade(true)
.build(),
fallback = ColorPainter(WooPosTheme.colors.loadingSkeleton),
error = ColorPainter(WooPosTheme.colors.loadingSkeleton),
placeholder = ColorPainter(WooPosTheme.colors.loadingSkeleton),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.size(96.dp)
)

Spacer(modifier = Modifier.width(16.dp.toAdaptivePadding()))
Spacer(modifier = Modifier.width(16.dp.toAdaptivePadding()))

Column(
modifier = Modifier.weight(1f)
) {
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = item.name,
style = MaterialTheme.typography.body1,
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.clearAndSetSemantics { }
)
Spacer(modifier = Modifier.height(4.dp.toAdaptivePadding()))
if (item.description.isNotNullOrEmpty()) {
Text(
text = item.name,
text = item.description!!,
style = MaterialTheme.typography.body1,
fontWeight = FontWeight.Bold,
maxLines = 1,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.clearAndSetSemantics { }
)
Spacer(modifier = Modifier.height(4.dp.toAdaptivePadding()))
if (item.description.isNotNullOrEmpty()) {
Text(
text = item.description!!,
style = MaterialTheme.typography.body1,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
color = MaterialTheme.colors.secondaryVariant,
modifier = Modifier.clearAndSetSemantics { }
)
Spacer(modifier = Modifier.height(4.dp.toAdaptivePadding()))
}
Text(
text = item.price,
style = MaterialTheme.typography.body1,
color = MaterialTheme.colors.secondaryVariant,
modifier = Modifier.clearAndSetSemantics { }
)
Spacer(modifier = Modifier.height(4.dp.toAdaptivePadding()))
}
Text(
text = item.price,
style = MaterialTheme.typography.body1,
color = MaterialTheme.colors.secondaryVariant,
modifier = Modifier.clearAndSetSemantics { }
)
}

if (canRemoveItems) {
Spacer(modifier = Modifier.width(8.dp.toAdaptivePadding()))
if (canRemoveItems) {
Spacer(modifier = Modifier.width(8.dp.toAdaptivePadding()))

val removeButtonContentDescription = stringResource(
id = R.string.woopos_remove_item_button_from_cart_content_description,
item.name
val removeButtonContentDescription = stringResource(
id = R.string.woopos_remove_item_button_from_cart_content_description,
item.name
)
IconButton(
onClick = { onUIEvent(WooPosCartUIEvent.ItemRemovedFromCart(item)) },
modifier = Modifier
.size(32.dp)
.semantics { contentDescription = removeButtonContentDescription }
) {
Icon(
painter = painterResource(id = R.drawable.ic_pos_remove_cart_item),
tint = MaterialTheme.colors.onBackground,
contentDescription = null,
)
IconButton(
onClick = { onUIEvent(WooPosCartUIEvent.ItemRemovedFromCart(item)) },
modifier = Modifier
.size(32.dp)
.semantics { contentDescription = removeButtonContentDescription }
) {
Icon(
painter = painterResource(id = R.drawable.ic_pos_remove_cart_item),
tint = MaterialTheme.colors.onBackground,
contentDescription = null,
)
}
}
Spacer(modifier = Modifier.width(16.dp.toAdaptivePadding()))
}
Spacer(modifier = Modifier.width(16.dp.toAdaptivePadding()))
}
}
}
Expand Down Expand Up @@ -542,7 +512,6 @@ fun WooPosCartScreenProductsPreview(modifier: Modifier = Modifier) {
"VW California VW California, VW California,VW California",
description = "test description",
price = "€50,000",
isAppearanceAnimationPlayed = true,
productType = ProductType.Simple,
),
WooPosCartState.Body.WithItems.Item(
Expand All @@ -556,7 +525,6 @@ fun WooPosCartScreenProductsPreview(modifier: Modifier = Modifier) {
description = "test description test description test description test description" +
" test description test description test description test description test description",
price = "$150,000",
isAppearanceAnimationPlayed = true,
productType = ProductType.Simple,
),
WooPosCartState.Body.WithItems.Item(
Expand All @@ -569,7 +537,6 @@ fun WooPosCartScreenProductsPreview(modifier: Modifier = Modifier) {
name = "VW California",
description = "",
price = "€250,000",
isAppearanceAnimationPlayed = true,
productType = ProductType.Simple,
)
)
Expand Down Expand Up @@ -605,7 +572,6 @@ fun WooPosCartScreenCheckoutPreview(modifier: Modifier = Modifier) {
name = "VW California",
description = null,
price = "€50,000",
isAppearanceAnimationPlayed = true,
productType = ProductType.Simple,
),
WooPosCartState.Body.WithItems.Item(
Expand All @@ -618,7 +584,6 @@ fun WooPosCartScreenCheckoutPreview(modifier: Modifier = Modifier) {
name = "VW California",
description = null,
price = "$150,000",
isAppearanceAnimationPlayed = true,
productType = ProductType.Simple,
),
WooPosCartState.Body.WithItems.Item(
Expand All @@ -631,7 +596,6 @@ fun WooPosCartScreenCheckoutPreview(modifier: Modifier = Modifier) {
name = "VW California",
description = null,
price = "€250,000",
isAppearanceAnimationPlayed = true,
productType = ProductType.Simple,
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ data class WooPosCartState(
val price: String,
val description: String?,
val imageUrl: String?,
val isAppearanceAnimationPlayed: Boolean,
val productType: ProductType,
) : Parcelable {
@Parcelize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@ sealed class WooPosCartUIEvent {
data class ItemRemovedFromCart(val item: WooPosCartState.Body.WithItems.Item) : WooPosCartUIEvent()
data object ClearAllClicked : WooPosCartUIEvent()
data object BackClicked : WooPosCartUIEvent()
data class OnCartItemAppearanceAnimationPlayed(val item: WooPosCartState.Body.WithItems.Item) : WooPosCartUIEvent()
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,18 +93,6 @@ class WooPosCartViewModel @Inject constructor(
body = WooPosCartState.Body.Empty
)
}

is WooPosCartUIEvent.OnCartItemAppearanceAnimationPlayed -> {
val currentState = _state.value
val currentStateBody = currentState.body as? WooPosCartState.Body.WithItems ?: return
_state.value = currentState.copy(
body = currentStateBody.copy(
itemsInCart = currentState.body.itemsInCart.map {
if (it.id == event.item.id) it.copy(isAppearanceAnimationPlayed = true) else it
}
)
)
}
}
}

Expand Down Expand Up @@ -268,7 +256,6 @@ class WooPosCartViewModel @Inject constructor(
description = null,
price = formatPrice(price),
imageUrl = firstImageUrl,
isAppearanceAnimationPlayed = false,
productType = ProductType.Simple,
)

Expand All @@ -286,7 +273,6 @@ class WooPosCartViewModel @Inject constructor(
description = getNameForPOS(product, resourceProvider),
price = formatPrice(price),
imageUrl = image?.source,
isAppearanceAnimationPlayed = false,
productType = ProductType.Variation,
)
}
Expand Down
Loading

0 comments on commit a5067ed

Please sign in to comment.