diff --git a/app/src/main/java/protect/card_locker/ListWidget.kt b/app/src/main/java/protect/card_locker/ListWidget.kt index f8245aeb4..4f42b746d 100644 --- a/app/src/main/java/protect/card_locker/ListWidget.kt +++ b/app/src/main/java/protect/card_locker/ListWidget.kt @@ -14,6 +14,7 @@ import android.widget.RemoteViews import androidx.core.widget.RemoteViewsCompat import protect.card_locker.DBHelper.LoyaltyCardArchiveFilter import protect.card_locker.cardview.LoyaltyCardViewActivity +import protect.card_locker.shared.ForegroundColorHelper class ListWidget : AppWidgetProvider() { fun updateAll(context: Context) { @@ -100,7 +101,7 @@ class ListWidget : AppWidgetProvider() { // Note: Android 5 will not use bitmaps val remoteViews = RemoteViews(context.packageName, R.layout.list_widget_item).apply { val headerColor = Utils.getHeaderColor(context, loyaltyCard) - val foreground = if (Utils.needsDarkForeground(headerColor)) Color.BLACK else Color.WHITE + val foreground = if (ForegroundColorHelper.needsDarkForeground(headerColor)) Color.BLACK else Color.WHITE setInt(R.id.item_container_foreground, "setBackgroundColor", headerColor) val icon = loyaltyCard.getImageThumbnail(context) // FIXME: The icon flow causes a crash up to Android 12L, so force anything below 33 down this path diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java b/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java index efcdee670..5d2574db7 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardEditActivity.java @@ -91,6 +91,7 @@ import java.util.concurrent.Callable; import protect.card_locker.async.TaskHandler; import protect.card_locker.databinding.LayoutChipChoiceBinding; import protect.card_locker.databinding.LoyaltyCardEditActivityBinding; +import protect.card_locker.shared.ForegroundColorHelper; import protect.card_locker.viewmodels.LoyaltyCardEditActivityViewModel; public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements BarcodeImageWriterResultCallback, ColorPickerDialogListener { @@ -896,8 +897,8 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements Integer headerColor = viewModel.getLoyaltyCard().headerColor; if (headerColor != null) { thumbnail.setOnClickListener(new ChooseCardImage()); - thumbnailEditIcon.setBackgroundColor(Utils.needsDarkForeground(headerColor) ? Color.BLACK : Color.WHITE); - thumbnailEditIcon.setColorFilter(Utils.needsDarkForeground(headerColor) ? Color.WHITE : Color.BLACK); + thumbnailEditIcon.setBackgroundColor(ForegroundColorHelper.Companion.needsDarkForeground(headerColor) ? Color.BLACK : Color.WHITE); + thumbnailEditIcon.setColorFilter(ForegroundColorHelper.Companion.needsDarkForeground(headerColor) ? Color.WHITE : Color.BLACK); } onResuming = false; @@ -919,18 +920,18 @@ public class LoyaltyCardEditActivity extends CatimaAppCompatActivity implements setLoyaltyCardHeaderColor(headerColor); - thumbnail.setBackgroundColor(Utils.needsDarkForeground(headerColor) ? Color.BLACK : Color.WHITE); + thumbnail.setBackgroundColor(ForegroundColorHelper.Companion.needsDarkForeground(headerColor) ? Color.BLACK : Color.WHITE); - thumbnailEditIcon.setBackgroundColor(Utils.needsDarkForeground(headerColor) ? Color.BLACK : Color.WHITE); - thumbnailEditIcon.setColorFilter(Utils.needsDarkForeground(headerColor) ? Color.WHITE : Color.BLACK); + thumbnailEditIcon.setBackgroundColor(ForegroundColorHelper.Companion.needsDarkForeground(headerColor) ? Color.BLACK : Color.WHITE); + thumbnailEditIcon.setColorFilter(ForegroundColorHelper.Companion.needsDarkForeground(headerColor) ? Color.WHITE : Color.BLACK); } else { generateIcon(storeFieldEdit.getText().toString().trim()); Integer headerColor = viewModel.getLoyaltyCard().headerColor; if (headerColor != null) { - thumbnailEditIcon.setBackgroundColor(Utils.needsDarkForeground(headerColor) ? Color.BLACK : Color.WHITE); - thumbnailEditIcon.setColorFilter(Utils.needsDarkForeground(headerColor) ? Color.WHITE : Color.BLACK); + thumbnailEditIcon.setBackgroundColor(ForegroundColorHelper.Companion.needsDarkForeground(headerColor) ? Color.BLACK : Color.WHITE); + thumbnailEditIcon.setColorFilter(ForegroundColorHelper.Companion.needsDarkForeground(headerColor) ? Color.WHITE : Color.BLACK); } } } diff --git a/app/src/main/java/protect/card_locker/ShortcutHelper.java b/app/src/main/java/protect/card_locker/ShortcutHelper.java index f9085bb56..605f006d5 100644 --- a/app/src/main/java/protect/card_locker/ShortcutHelper.java +++ b/app/src/main/java/protect/card_locker/ShortcutHelper.java @@ -18,6 +18,7 @@ import org.jetbrains.annotations.NotNull; import java.util.LinkedList; import protect.card_locker.cardview.LoyaltyCardViewActivity; +import protect.card_locker.shared.ForegroundColorHelper; public class ShortcutHelper { /** @@ -102,7 +103,7 @@ public class ShortcutHelper { if (iconBitmap == null) { iconBitmap = Utils.generateIcon(context, loyaltyCard, true).getLetterTile(); } else { - iconBitmap = createAdaptiveBitmap(iconBitmap, Utils.needsDarkForeground(Utils.getHeaderColor(context, loyaltyCard)) ? Color.BLACK : Color.WHITE); + iconBitmap = createAdaptiveBitmap(iconBitmap, ForegroundColorHelper.Companion.needsDarkForeground(Utils.getHeaderColor(context, loyaltyCard)) ? Color.BLACK : Color.WHITE); } IconCompat icon = IconCompat.createWithAdaptiveBitmap(iconBitmap); diff --git a/app/src/main/java/protect/card_locker/Utils.java b/app/src/main/java/protect/card_locker/Utils.java index 2aa3b45e4..8519f22db 100644 --- a/app/src/main/java/protect/card_locker/Utils.java +++ b/app/src/main/java/protect/card_locker/Utils.java @@ -39,7 +39,6 @@ import androidx.annotation.Nullable; import androidx.annotation.RawRes; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatDelegate; -import androidx.core.graphics.ColorUtils; import androidx.core.graphics.Insets; import androidx.core.os.LocaleListCompat; import androidx.core.view.ViewCompat; @@ -95,6 +94,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import protect.card_locker.preferences.Settings; +import protect.card_locker.shared.ForegroundColorHelper; public class Utils { private static final String TAG = "Catima"; @@ -115,8 +115,6 @@ public class Utils { public static final String CARD_IMAGE_FILENAME_REGEX = "^(card_)(\\d+)(_(?:front|back|icon)\\.png)$"; - static final double LUMINANCE_MIDPOINT = 0.5; - static final int BITMAP_SIZE_SMALL = 512; static final int BITMAP_SIZE_BIG = 1600; @@ -147,11 +145,7 @@ public class Utils { } return new LetterBitmap(context, store, store, - tileLetterFontSize, pixelSize, pixelSize, backgroundColor, needsDarkForeground(backgroundColor) ? Color.BLACK : Color.WHITE); - } - - static public boolean needsDarkForeground(Integer backgroundColor) { - return ColorUtils.calculateLuminance(backgroundColor) > LUMINANCE_MIDPOINT; + tileLetterFontSize, pixelSize, pixelSize, backgroundColor, ForegroundColorHelper.Companion.needsDarkForeground(backgroundColor) ? Color.BLACK : Color.WHITE); } static public List retrieveBarcodesFromImage(Context context, Uri uri) { @@ -1070,7 +1064,7 @@ public class Utils { if (icon != null) { // Use header colour to decide if this image will need a white or black background - backgroundOrIcon.setBackgroundColor(needsDarkForeground(headerColor) ? Color.BLACK : Color.WHITE); + backgroundOrIcon.setBackgroundColor(ForegroundColorHelper.Companion.needsDarkForeground(headerColor) ? Color.BLACK : Color.WHITE); // Ensure correct cropping style backgroundOrIcon.setScaleType(Utils.getRecommendedScaleTypeForThumbnailImage(icon)); @@ -1100,7 +1094,7 @@ public class Utils { // Actually set the text and colour textWhenNoImage.setVisibility(View.VISIBLE); textWhenNoImage.setText(loyaltyCard.store); - textWhenNoImage.setTextColor(Utils.needsDarkForeground(headerColor) ? Color.BLACK : Color.WHITE); + textWhenNoImage.setTextColor(ForegroundColorHelper.Companion.needsDarkForeground(headerColor) ? Color.BLACK : Color.WHITE); } return headerColor; diff --git a/app/src/main/java/protect/card_locker/cardview/LoyaltyCardViewActivity.java b/app/src/main/java/protect/card_locker/cardview/LoyaltyCardViewActivity.java index b4f7a6a20..662414e64 100644 --- a/app/src/main/java/protect/card_locker/cardview/LoyaltyCardViewActivity.java +++ b/app/src/main/java/protect/card_locker/cardview/LoyaltyCardViewActivity.java @@ -54,6 +54,7 @@ import protect.card_locker.cardimageview.LoyaltyCardImageViewActivity; import protect.card_locker.databinding.LoyaltyCardViewLayoutBinding; import protect.card_locker.preferences.Settings; import protect.card_locker.preferences.SettingsActivity; +import protect.card_locker.shared.ForegroundColorHelper; public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements BarcodeImageWriterResultCallback { private LoyaltyCardViewLayoutBinding binding; @@ -598,20 +599,20 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements // Set bottomAppBar and system navigation bar color binding.bottomAppBar.setBackgroundColor(darkenedColor); - Utils.setNavigationBarColor(null, window, darkenedColor, Utils.needsDarkForeground(darkenedColor)); + Utils.setNavigationBarColor(null, window, darkenedColor, ForegroundColorHelper.Companion.needsDarkForeground(darkenedColor)); int complementaryColor = Utils.getComplementaryColor(darkenedColor); binding.fabEdit.setBackgroundTintList(ColorStateList.valueOf(complementaryColor)); Drawable editButtonIcon = binding.fabEdit.getDrawable(); editButtonIcon.mutate(); - editButtonIcon.setTint(Utils.needsDarkForeground(complementaryColor) ? Color.BLACK : Color.WHITE); + editButtonIcon.setTint(ForegroundColorHelper.Companion.needsDarkForeground(complementaryColor) ? Color.BLACK : Color.WHITE); binding.fabEdit.setImageDrawable(editButtonIcon); Bitmap icon = loyaltyCard.getImageThumbnail(this); Utils.setIconOrTextWithBackground(this, loyaltyCard, icon, binding.iconImage, binding.iconText, 1); // If the background is very bright, we should use dark icons - backgroundNeedsDarkIcons = Utils.needsDarkForeground(backgroundHeaderColor); + backgroundNeedsDarkIcons = ForegroundColorHelper.Companion.needsDarkForeground(backgroundHeaderColor); fixBottomAppBarImageButtonColor(binding.bottomAppBarInfoButton); fixBottomAppBarImageButtonColor(binding.bottomAppBarPreviousButton); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ce5aff56f..88bcc8aca 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -47,8 +47,8 @@ ch-acra-acra-mail = { group = "ch.acra", name = "acra-mail", version.ref = "acra ch-acra-acra-dialog = { group = "ch.acra", name = "acra-dialog", version.ref = "acra" } # Wear OS -androidx-wear-compose-material = { group = "androidx.wear.compose", name = "compose-material", version.ref = "wearCompose" } androidx-wear-compose-foundation = { group = "androidx.wear.compose", name = "compose-foundation", version.ref = "wearCompose" } +androidx-wear-compose-material3 = { group = "androidx.wear.compose", name = "compose-material3", version.ref = "wearCompose" } androidx-wear-compose-navigation = { group = "androidx.wear.compose", name = "compose-navigation", version.ref = "wearCompose" } # Testing diff --git a/shared/src/main/java/protect/card_locker/shared/ForegroundColorHelper.kt b/shared/src/main/java/protect/card_locker/shared/ForegroundColorHelper.kt new file mode 100644 index 000000000..810ef490b --- /dev/null +++ b/shared/src/main/java/protect/card_locker/shared/ForegroundColorHelper.kt @@ -0,0 +1,13 @@ +package protect.card_locker.shared + +import androidx.core.graphics.ColorUtils + +class ForegroundColorHelper { + companion object { + const val LUMINANCE_MIDPOINT: Double = 0.5 + + fun needsDarkForeground(backgroundColor: Int): Boolean { + return ColorUtils.calculateLuminance(backgroundColor) > LUMINANCE_MIDPOINT + } + } +} \ No newline at end of file diff --git a/wear/build.gradle.kts b/wear/build.gradle.kts index 4b6d29c83..a10fd76eb 100644 --- a/wear/build.gradle.kts +++ b/wear/build.gradle.kts @@ -46,7 +46,7 @@ dependencies { implementation(libs.androidx.activity.activity.compose) // Wear OS Compose - implementation(libs.androidx.wear.compose.material) + implementation(libs.androidx.wear.compose.material3) implementation(libs.androidx.wear.compose.foundation) implementation(libs.androidx.wear.compose.navigation) diff --git a/wear/src/main/java/me/hackerchick/catima/wear/ui/CardListScreen.kt b/wear/src/main/java/me/hackerchick/catima/wear/ui/CardListScreen.kt index 42d2dfaeb..3ea02793d 100644 --- a/wear/src/main/java/me/hackerchick/catima/wear/ui/CardListScreen.kt +++ b/wear/src/main/java/me/hackerchick/catima/wear/ui/CardListScreen.kt @@ -15,15 +15,19 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.wear.compose.foundation.lazy.ScalingLazyColumn +import androidx.wear.compose.foundation.lazy.TransformingLazyColumn import androidx.wear.compose.foundation.lazy.items -import androidx.wear.compose.material.Chip -import androidx.wear.compose.material.ChipDefaults -import androidx.wear.compose.material.CircularProgressIndicator -import androidx.wear.compose.material.Text +import androidx.wear.compose.material3.CircularProgressIndicator +import androidx.wear.compose.material3.Text +import androidx.wear.compose.material3.Button +import androidx.wear.compose.material3.ButtonDefaults +import androidx.wear.compose.material3.SurfaceTransformation +import androidx.wear.compose.material3.lazy.rememberTransformationSpec +import androidx.wear.compose.material3.lazy.transformedHeight import me.hackerchick.catima.wear.R import me.hackerchick.catima.wear.SyncStatus import me.hackerchick.catima.wear.WearCard +import protect.card_locker.shared.ForegroundColorHelper @Composable fun CardListScreen( @@ -63,14 +67,16 @@ fun CardListScreen( ) } else -> { - ScalingLazyColumn( + val transformationSpec = rememberTransformationSpec() + TransformingLazyColumn( modifier = Modifier.fillMaxSize(), contentPadding = PaddingValues(horizontal = 8.dp, vertical = 32.dp), verticalArrangement = Arrangement.spacedBy(4.dp), ) { items(cards, key = { it.id }) { card -> - Chip( - modifier = Modifier.fillMaxWidth(), + Button( + modifier = Modifier.fillMaxWidth().transformedHeight(this, transformationSpec), + transformation = SurfaceTransformation(transformationSpec), label = { Text( text = card.store, @@ -79,23 +85,33 @@ fun CardListScreen( }, onClick = { onCardClick(card) }, colors = if (card.headerColor != null) { - ChipDefaults.chipColors(backgroundColor = Color(card.headerColor)) + ButtonDefaults.buttonColors( + containerColor = Color(card.headerColor), + contentColor = if (ForegroundColorHelper.needsDarkForeground(card.headerColor)) Color.Black else Color.White + ) } else { - ChipDefaults.primaryChipColors() + ButtonDefaults.buttonColors() }, ) } - val footerLabel = syncStatus.labelRes - if (footerLabel != null) { - item { - Text( - text = stringResource(footerLabel), - textAlign = TextAlign.Center, - fontSize = 11.sp, - color = Color.Gray, - modifier = Modifier.fillMaxWidth().padding(top = 4.dp), - ) - } + } + val footerLabel = syncStatus.labelRes + if (footerLabel != null) { + Box( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.BottomCenter) + .background(Color.Black.copy(alpha = 0.75f)) + ) { + Text( + text = stringResource(footerLabel), + textAlign = TextAlign.Center, + fontSize = 11.sp, + color = Color.LightGray, + modifier = Modifier + .padding(40.dp, 4.dp, 40.dp, 20.dp) + .align(Alignment.Center) + ) } } } diff --git a/wear/src/main/java/me/hackerchick/catima/wear/ui/CardViewScreen.kt b/wear/src/main/java/me/hackerchick/catima/wear/ui/CardViewScreen.kt index e066f3ce4..c6dca323d 100644 --- a/wear/src/main/java/me/hackerchick/catima/wear/ui/CardViewScreen.kt +++ b/wear/src/main/java/me/hackerchick/catima/wear/ui/CardViewScreen.kt @@ -26,9 +26,9 @@ import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.wear.compose.material.CircularProgressIndicator -import androidx.wear.compose.material.MaterialTheme -import androidx.wear.compose.material.Text +import androidx.wear.compose.material3.CircularProgressIndicator +import androidx.wear.compose.material3.MaterialTheme +import androidx.wear.compose.material3.Text import com.google.zxing.BarcodeFormat import com.google.zxing.EncodeHintType import com.google.zxing.MultiFormatWriter @@ -40,7 +40,7 @@ fun CardViewScreen(card: WearCard?) { Box( modifier = Modifier .fillMaxSize() - .background(MaterialTheme.colors.background), + .background(MaterialTheme.colorScheme.background), contentAlignment = Alignment.Center, ) { if (card == null) {