feat: full md3 redesign and few tweaks

fully redesigned android and wearos app

auto sync with wearos

enabled minify
This commit is contained in:
Fimkov
2026-06-19 12:06:49 +07:00
parent 1c76705551
commit e62b7f4741
43 changed files with 4013 additions and 1199 deletions
+6 -1
View File
@@ -27,8 +27,12 @@ android {
}
buildTypes {
debug {
applicationIdSuffix = ".debug"
}
release {
isMinifyEnabled = false
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
@@ -52,6 +56,7 @@ dependencies {
implementation(libs.androidx.appcompat)
implementation(libs.androidx.compose.foundation)
implementation(libs.androidx.compose.material3)
implementation("androidx.compose.material:material-icons-extended")
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview)
+11 -1
View File
@@ -18,4 +18,14 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile
-keepattributes *Annotation*, InnerClasses
-dontnote kotlinx.serialization.**
-keepclassmembers @kotlinx.serialization.Serializable class ** {
*** Companion;
*** serializer(...);
}
-keepclasseswithmembers class **$$serializer { *; }
-keepclassmembers enum com.google.zxing.BarcodeFormat { *; }
@@ -4,10 +4,14 @@ import com.google.zxing.BarcodeFormat
import kotlinx.serialization.Serializable
@Serializable
class CardInfo (
class CardInfo(
val id: Int,
val name: String,
val codeType: BarcodeFormat,
val codeValue: String,
val color: String?
)
val color: String?,
val position: Int = 0,
val iconPath: String? = null,
val monochrome: Boolean = false,
val iconData: String? = null,
)
@@ -6,40 +6,40 @@ import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import com.google.zxing.BarcodeFormat
class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?) : SQLiteOpenHelper(context, "omni_cards", factory, 2) {
class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?) : SQLiteOpenHelper(context, "omni_cards", factory, 3) {
override fun onCreate(db: SQLiteDatabase?) {
db!!.execSQL("CREATE TABLE IF NOT EXISTS cards (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, codeType TEXT, codeValue TEXT, color TEXT)")
db!!.execSQL("CREATE TABLE IF NOT EXISTS cards (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, codeType TEXT, codeValue TEXT, color TEXT, position INTEGER DEFAULT 0, iconPath TEXT)")
}
override fun onUpgrade(
db: SQLiteDatabase?,
oldVersion: Int,
p2: Int
) {
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, p2: Int) {
if (oldVersion < 2) {
db!!.execSQL("ALTER TABLE cards ADD COLUMN color TEXT")
}
if (oldVersion < 3) {
db!!.execSQL("ALTER TABLE cards ADD COLUMN position INTEGER DEFAULT 0")
db.execSQL("ALTER TABLE cards ADD COLUMN iconPath TEXT")
db.execSQL("UPDATE cards SET position = id")
}
}
fun clearDatabase() {
val db = this.writableDatabase
db.execSQL("DELETE FROM cards")
db.close()
}
fun addCards(cards: List<CardInfo>) {
val db = this.writableDatabase
for (card in cards) {
cards.forEachIndexed { index, card ->
val values = ContentValues()
values.put("id", card.id)
values.put("name", card.name)
values.put("codeValue", card.codeValue)
values.put("codeType", card.codeType.name)
values.put("color", card.color)
values.put("iconPath", card.iconPath)
values.put("position", index)
db.insert("cards", null, values)
}
@@ -47,20 +47,25 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
db.close()
}
private fun readCard(cursor: android.database.Cursor): CardInfo {
return CardInfo(
id = cursor.getInt(cursor.getColumnIndexOrThrow("id")),
name = cursor.getString(cursor.getColumnIndexOrThrow("name")),
codeType = BarcodeFormat.valueOf(cursor.getString(cursor.getColumnIndexOrThrow("codeType"))),
codeValue = cursor.getString(cursor.getColumnIndexOrThrow("codeValue")),
color = cursor.getString(cursor.getColumnIndexOrThrow("color")),
position = cursor.getInt(cursor.getColumnIndexOrThrow("position")),
iconPath = cursor.getString(cursor.getColumnIndexOrThrow("iconPath")),
)
}
fun getCards(): List<CardInfo> {
val db = this.readableDatabase
val cursor = db.rawQuery("SELECT * FROM cards", null)
val cursor = db.rawQuery("SELECT * FROM cards ORDER BY position ASC, id ASC", null)
val cards = mutableListOf<CardInfo>()
while (cursor.moveToNext()) {
cards.add(CardInfo(
id = cursor.getInt(cursor.getColumnIndexOrThrow("id")),
name = cursor.getString(cursor.getColumnIndexOrThrow("name")),
codeType = BarcodeFormat.valueOf(cursor.getString(cursor.getColumnIndexOrThrow("codeType"))),
codeValue = cursor.getString(cursor.getColumnIndexOrThrow("codeValue")),
color = cursor.getString(cursor.getColumnIndexOrThrow("color"))
))
cards.add(readCard(cursor))
}
cursor.close()
@@ -71,7 +76,6 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
fun getCard(id: Int): CardInfo? {
val db = this.readableDatabase
val cursor = db.rawQuery("SELECT * FROM cards WHERE id = ?", arrayOf(id.toString()))
if (!cursor.moveToFirst()) {
@@ -81,17 +85,10 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
return null
}
val cardInfo = CardInfo(
id = cursor.getInt(cursor.getColumnIndexOrThrow("id")),
name = cursor.getString(cursor.getColumnIndexOrThrow("name")),
codeType = BarcodeFormat.valueOf(cursor.getString(cursor.getColumnIndexOrThrow("codeType"))),
codeValue = cursor.getString(cursor.getColumnIndexOrThrow("codeValue")),
color = cursor.getString(cursor.getColumnIndexOrThrow("color"))
)
val cardInfo = readCard(cursor)
cursor.close()
db.close()
return cardInfo
}
}
}
@@ -1,77 +1,127 @@
package ru.omni_devel.cards.presentation
import android.content.Intent
import android.graphics.BitmapFactory
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.QrCode2
import androidx.compose.material.icons.filled.QrCodeScanner
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.ColorMatrix
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.graphics.luminance
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.graphics.toColorInt
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.Text
import com.google.zxing.BarcodeFormat
private fun autoGlyph(codeType: BarcodeFormat): ImageVector {
return when (codeType) {
BarcodeFormat.QR_CODE, BarcodeFormat.DATA_MATRIX, BarcodeFormat.AZTEC, BarcodeFormat.PDF_417 -> Icons.Filled.QrCode2
else -> Icons.Filled.QrCodeScanner
}
}
@Composable
private fun rememberIconBitmap(path: String?): ImageBitmap? {
return remember(path) {
if (path == null) return@remember null
runCatching { BitmapFactory.decodeFile(path)?.asImageBitmap() }.getOrNull()
}
}
@Composable
fun CardButton(cardInfo: CardInfo) {
val context = LocalContext.current
Box(modifier = Modifier.fillMaxWidth()) {
Button(
val accent = cardInfo.color?.let { runCatching { Color(it.toColorInt()) }.getOrNull() }
val bitmap = rememberIconBitmap(cardInfo.iconPath)
val base = MaterialTheme.colorScheme.surfaceContainer
val container = if (accent != null) accent.copy(alpha = 0.18f).compositeOver(base) else base
val tile = accent ?: MaterialTheme.colorScheme.secondaryContainer
val onTile = if (accent != null) {
if (accent.luminance() > 0.5f) Color.Black.copy(alpha = 0.8f) else Color.White
} else {
MaterialTheme.colorScheme.onSecondaryContainer
}
Button(
modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.buttonColors(
containerColor = container
),
onClick = {
val intent = Intent(context, ShowCardActivity::class.java)
intent.putExtra("cardId", cardInfo.id)
context.startActivity(intent)
}
) {
Row(
modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.primaryContainer
),
contentPadding = PaddingValues(0.dp),
onClick = {
val intent = Intent(context, ShowCardActivity::class.java)
intent.putExtra("cardId", cardInfo.id)
context.startActivity(intent)
}
verticalAlignment = Alignment.CenterVertically
) {
Row(
Box(
modifier = Modifier
.fillMaxWidth()
.height(IntrinsicSize.Min)
.clip(ButtonDefaults.shape)
.size(30.dp)
.clip(RoundedCornerShape(9.dp))
.background(if (bitmap != null) Color.White else tile),
contentAlignment = Alignment.Center
) {
Box(
modifier = Modifier
.fillMaxHeight()
.width(32.dp)
.background(
if (cardInfo.color == null)
MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.625f)
else
Color(cardInfo.color.toColorInt()).copy(alpha = 0.625f)
)
)
Text(
cardInfo.name,
fontSize = 16.sp,
color = MaterialTheme.colorScheme.onPrimaryContainer,
modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
.weight(1f),
textAlign = TextAlign.Start
)
if (bitmap != null) {
Image(
bitmap = bitmap,
contentDescription = null,
modifier = Modifier.size(24.dp),
contentScale = ContentScale.Fit,
colorFilter = if (cardInfo.monochrome) {
ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0f) })
} else {
null
}
)
} else {
Icon(
imageVector = autoGlyph(cardInfo.codeType),
contentDescription = null,
tint = onTile,
modifier = Modifier.size(18.dp)
)
}
}
Text(
cardInfo.name,
modifier = Modifier
.padding(start = 10.dp)
.fillMaxWidth(),
color = MaterialTheme.colorScheme.onSurface,
textAlign = TextAlign.Start,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
}
}
}
@@ -1,22 +1,25 @@
package ru.omni_devel.cards.presentation
import android.annotation.SuppressLint
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.lazy.TransformingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState
import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text
import ru.omni_devel.cards.R
import ru.omni_devel.cards.presentation.theme.OmniCardsTheme
class MainActivity : ComponentActivity() {
private lateinit var db: DbHelper
@@ -27,36 +30,39 @@ class MainActivity : ComponentActivity() {
db = DbHelper(this, null)
setContent {
App(db.getCards())
OmniCardsTheme {
App(db.getCards())
}
}
}
}
@SuppressLint("UnusedBoxWithConstraintsScope")
@Composable
fun App(cards: List<CardInfo>) {
BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
val topBottomPadding = maxHeight * 0.4f
AppScaffold {
if (cards.isEmpty()) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(stringResource(R.string.sync_with_mobile_app_to_get_started))
Text(
stringResource(R.string.sync_with_mobile_app_to_get_started),
color = MaterialTheme.colorScheme.onSurface,
textAlign = TextAlign.Center
)
}
} else {
TransformingLazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(
top = topBottomPadding,
bottom = topBottomPadding
),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
for (card in cards) {
item {
CardButton(card)
val listState = rememberTransformingLazyColumnState()
ScreenScaffold(scrollState = listState) { contentPadding ->
TransformingLazyColumn(
state = listState,
contentPadding = contentPadding,
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
for (card in cards) {
item {
CardButton(card)
}
}
}
}
@@ -1,16 +1,14 @@
package ru.omni_devel.cards.presentation
import android.content.Intent
import android.os.Handler
import android.os.Looper
import android.widget.Toast
import android.util.Base64
import com.google.android.gms.wearable.MessageEvent
import com.google.android.gms.wearable.WearableListenerService
import kotlinx.serialization.json.Json
import ru.omni_devel.cards.R
import java.io.File
class MessagesReceiver : WearableListenerService() {
private lateinit var db: DbHelper
private val json = Json { ignoreUnknownKeys = true }
override fun onCreate() {
super.onCreate()
@@ -21,22 +19,29 @@ class MessagesReceiver : WearableListenerService() {
override fun onMessageReceived(event: MessageEvent) {
when (event.path) {
"/updateCards" -> {
val json = String(event.data, Charsets.UTF_8)
val jsonText = String(event.data, Charsets.UTF_8)
val cards = Json.decodeFromString<List<CardInfo>>(json)
val cards = json.decodeFromString<List<CardInfo>>(jsonText)
val iconsDir = File(filesDir, "icons")
iconsDir.deleteRecursively()
iconsDir.mkdirs()
val processed = cards.map { c ->
val localPath = c.iconData?.let { data ->
runCatching {
val bytes = Base64.decode(data, Base64.NO_WRAP)
val file = File(iconsDir, "${c.id}.png")
file.writeBytes(bytes)
file.absolutePath
}.getOrNull()
}
CardInfo(c.id, c.name, c.codeType, c.codeValue, c.color, c.position, localPath, c.monochrome)
}
db.clearDatabase()
db.addCards(cards)
Handler(Looper.getMainLooper()).post {
Toast.makeText(this, this.getString(R.string.sync_is_successful), Toast.LENGTH_SHORT).show()
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
}
startActivity(intent)
}
db.addCards(processed)
}
}
}
}
}
@@ -8,22 +8,37 @@ import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.FilterQuality
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.graphics.lerp
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.core.graphics.toColorInt
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.Text
import com.google.zxing.BarcodeFormat
import ru.omni_devel.cards.R
import ru.omni_devel.cards.presentation.theme.OmniCardsTheme
class ShowCardActivity : ComponentActivity() {
private lateinit var db: DbHelper
@@ -39,72 +54,103 @@ class ShowCardActivity : ComponentActivity() {
db = DbHelper(this, null)
val cardId = intent.getIntExtra("cardId", 0)
val cardInfo = db.getCard(cardId)
if (cardInfo == null) {
Toast.makeText(this, "cardInfo is null", Toast.LENGTH_LONG).show()
finish()
return
}
setContent {
ShowCardPage(cardInfo)
OmniCardsTheme {
ShowCardPage(cardInfo)
}
}
}
override fun onResume() {
super.onResume()
setBrightness(1.0f)
}
override fun onPause() {
super.onPause()
setBrightness(WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE)
finish()
}
private fun setBrightness(level: Float) {
val params = window.attributes
params.screenBrightness = level
window.attributes = params
}
}
@Composable
fun ShowCardPage(cardInfo: CardInfo) {
val seed = cardInfo.color?.let { runCatching { Color(it.toColorInt()) }.getOrNull() } ?: Color(0xFFC7BFFF)
val codeBg = lerp(seed, Color.White, 0.80f)
val codeModule = lerp(seed, Color.Black, 0.55f)
BoxWithConstraints(
modifier = Modifier.fillMaxSize(),
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background),
contentAlignment = Alignment.Center
) {
val screenSize = minOf(maxWidth, maxHeight)
val safeSize = (screenSize * 0.65f)
val sizePx = with(LocalDensity.current) { safeSize.roundToPx() }
val bitmap = remember(cardInfo, sizePx) {
try {
generateCode(cardInfo.codeValue, cardInfo.codeType, sizePx, sizePx).asImageBitmap()
} catch (_: Exception) {
null
}
val bitmap = remember(cardInfo, codeModule, codeBg) {
styledCodeBitmap(cardInfo.codeValue, cardInfo.codeType, codeModule.toArgb(), codeBg.toArgb())?.asImageBitmap()
}
val aspect = bitmap?.let { it.width.toFloat() / it.height.toFloat() } ?: 1f
val is1d = cardInfo.codeType != BarcodeFormat.QR_CODE &&
cardInfo.codeType != BarcodeFormat.DATA_MATRIX &&
cardInfo.codeType != BarcodeFormat.AZTEC &&
cardInfo.codeType != BarcodeFormat.PDF_417
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
verticalArrangement = Arrangement.Center,
modifier = Modifier.padding(horizontal = screenSize * 0.06f)
) {
if (bitmap != null) {
Image(
bitmap = bitmap,
contentDescription = cardInfo.codeValue,
modifier = Modifier.size(safeSize)
Box(
modifier = Modifier
.background(MaterialTheme.colorScheme.surfaceContainer, RoundedCornerShape(14.dp))
.padding(horizontal = 14.dp, vertical = 6.dp)
) {
Text(
cardInfo.name,
color = MaterialTheme.colorScheme.onSurface,
style = MaterialTheme.typography.titleSmall,
textAlign = TextAlign.Center,
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
}
Spacer(Modifier.height(10.dp))
if (bitmap != null) {
val codeModifier = when {
is1d -> Modifier.size(screenSize * 0.74f, screenSize * 0.30f)
cardInfo.codeType == BarcodeFormat.PDF_417 -> Modifier.size(screenSize * 0.74f, screenSize * 0.74f / aspect)
else -> Modifier.size(screenSize * 0.56f)
}
Box(
modifier = Modifier
.background(codeBg, RoundedCornerShape(16.dp))
.padding(12.dp)
) {
Image(
bitmap = bitmap,
contentDescription = cardInfo.codeValue,
modifier = codeModifier,
contentScale = ContentScale.FillBounds,
filterQuality = FilterQuality.None
)
}
} else {
Text(
stringResource(R.string.failed_to_generate_card_code),
@@ -2,12 +2,41 @@ package ru.omni_devel.cards.presentation
import android.graphics.Bitmap
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.MultiFormatWriter
import com.journeyapps.barcodescanner.BarcodeEncoder
import com.google.zxing.datamatrix.encoder.SymbolShapeHint
fun generateCode(value: String, format: BarcodeFormat, width: Int, height: Int): Bitmap {
val writer = MultiFormatWriter()
val matrix = writer.encode(value, format, width, height)
fun styledCodeBitmap(value: String, format: BarcodeFormat, onArgb: Int, bgArgb: Int): Bitmap? {
val is2d = format == BarcodeFormat.QR_CODE || format == BarcodeFormat.DATA_MATRIX ||
format == BarcodeFormat.AZTEC || format == BarcodeFormat.PDF_417
return BarcodeEncoder().createBitmap(matrix)
val matrix = runCatching {
if (!is2d) {
MultiFormatWriter().encode(value, format, 0, 1)
} else {
val hints: Map<EncodeHintType, Any>? = if (format == BarcodeFormat.DATA_MATRIX) {
mapOf(EncodeHintType.DATA_MATRIX_SHAPE to SymbolShapeHint.FORCE_SQUARE)
} else {
null
}
MultiFormatWriter().encode(value, format, 0, 0, hints)
}
}.getOrNull() ?: return null
val rect = matrix.enclosingRectangle ?: intArrayOf(0, 0, matrix.width, matrix.height)
val left = rect[0]
val top = rect[1]
val w = rect[2]
val h = rect[3]
if (w <= 0 || h <= 0) return null
val pixels = IntArray(w * h)
for (y in 0 until h) {
for (x in 0 until w) {
pixels[y * w + x] = if (matrix.get(left + x, top + y)) onArgb else bgArgb
}
}
val bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
bmp.setPixels(pixels, 0, w, 0, 0, w, h)
return bmp
}
@@ -1,17 +1,31 @@
package ru.omni_devel.cards.presentation.theme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.wear.compose.material3.ColorScheme
import androidx.wear.compose.material3.MaterialTheme
private val OmniColorScheme = ColorScheme(
primary = Color(0xFFC7BFFF),
onPrimary = Color(0xFF2A1A8F),
primaryContainer = Color(0xFF4236B6),
onPrimaryContainer = Color(0xFFE4DFFF),
secondary = Color(0xFFC8C3DD),
onSecondary = Color(0xFF302E42),
secondaryContainer = Color(0xFF474459),
onSecondaryContainer = Color(0xFFE5DFF9),
surfaceContainer = Color(0xFF1F1F25),
surfaceContainerHigh = Color(0xFF2A2930),
onSurface = Color(0xFFE4E1E9),
onSurfaceVariant = Color(0xFFC8C5D0),
)
@Composable
fun OmniCardsTheme(
content: @Composable () -> Unit
) {
/**
* Empty theme to customize for your app.
* See: https://developer.android.com/jetpack/compose/designsystems/custom
*/
MaterialTheme(
colorScheme = OmniColorScheme,
content = content
)
}
}
+5
View File
@@ -0,0 +1,5 @@
<resources>
<string-array name="android_wear_capabilities">
<item>omnicards_wear_app</item>
</string-array>
</resources>