feat: added icons support for WearOS

This commit is contained in:
2026-06-23 11:09:55 +03:00
parent bb57ab007c
commit 3cf6b876f9
6 changed files with 88 additions and 20 deletions
@@ -50,7 +50,6 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
+1
View File
@@ -71,4 +71,5 @@ dependencies {
implementation(libs.zxing.android) implementation(libs.zxing.android)
implementation(libs.material) implementation(libs.material)
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
implementation("androidx.compose.material:material-icons-extended")
} }
@@ -9,5 +9,6 @@ class CardInfo (
val name: String, val name: String,
val codeType: BarcodeFormat, val codeType: BarcodeFormat,
val codeValue: String, val codeValue: String,
val color: String? val color: String?,
val icon: String?
) )
@@ -4,11 +4,14 @@ import android.content.ContentValues
import android.content.Context import android.content.Context
import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper import android.database.sqlite.SQLiteOpenHelper
import androidx.core.database.getStringOrNull
import com.google.zxing.BarcodeFormat import com.google.zxing.BarcodeFormat
class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?) : SQLiteOpenHelper(context, "omni_cards", factory, 4) { class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?) : SQLiteOpenHelper(context, "omni_cards", factory, 5) {
override fun onCreate(db: SQLiteDatabase?) { 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, icon TEXT)"
)
} }
override fun onUpgrade( override fun onUpgrade(
@@ -30,6 +33,10 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
db!!.execSQL("ALTER TABLE cards DROP COLUMN position") db!!.execSQL("ALTER TABLE cards DROP COLUMN position")
db.execSQL("ALTER TABLE cards DROP COLUMN iconPath") db.execSQL("ALTER TABLE cards DROP COLUMN iconPath")
} }
if (oldVersion < 5) {
db!!.execSQL("ALTER TABLE cards ADD COLUMN icon TEXT")
}
} }
fun clearDatabase() { fun clearDatabase() {
@@ -51,6 +58,7 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
values.put("codeValue", card.codeValue) values.put("codeValue", card.codeValue)
values.put("codeType", card.codeType.name) values.put("codeType", card.codeType.name)
values.put("color", card.color) values.put("color", card.color)
values.put("icon", card.icon)
db.insert("cards", null, values) db.insert("cards", null, values)
} }
@@ -70,7 +78,8 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
name = cursor.getString(cursor.getColumnIndexOrThrow("name")), name = cursor.getString(cursor.getColumnIndexOrThrow("name")),
codeType = BarcodeFormat.valueOf(cursor.getString(cursor.getColumnIndexOrThrow("codeType"))), codeType = BarcodeFormat.valueOf(cursor.getString(cursor.getColumnIndexOrThrow("codeType"))),
codeValue = cursor.getString(cursor.getColumnIndexOrThrow("codeValue")), codeValue = cursor.getString(cursor.getColumnIndexOrThrow("codeValue")),
color = cursor.getString(cursor.getColumnIndexOrThrow("color")) color = cursor.getString(cursor.getColumnIndexOrThrow("color")),
icon = cursor.getStringOrNull(cursor.getColumnIndexOrThrow("icon"))
)) ))
} }
@@ -97,7 +106,8 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
name = cursor.getString(cursor.getColumnIndexOrThrow("name")), name = cursor.getString(cursor.getColumnIndexOrThrow("name")),
codeType = BarcodeFormat.valueOf(cursor.getString(cursor.getColumnIndexOrThrow("codeType"))), codeType = BarcodeFormat.valueOf(cursor.getString(cursor.getColumnIndexOrThrow("codeType"))),
codeValue = cursor.getString(cursor.getColumnIndexOrThrow("codeValue")), codeValue = cursor.getString(cursor.getColumnIndexOrThrow("codeValue")),
color = cursor.getString(cursor.getColumnIndexOrThrow("color")) color = cursor.getString(cursor.getColumnIndexOrThrow("color")),
icon = cursor.getStringOrNull(cursor.getColumnIndexOrThrow("icon"))
) )
cursor.close() cursor.close()
@@ -1,20 +1,25 @@
package ru.omni_devel.cards.presentation package ru.omni_devel.cards.presentation
import android.content.Intent import android.content.Intent
import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding 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.outlined.QrCode
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -22,6 +27,7 @@ import androidx.compose.ui.unit.sp
import androidx.core.graphics.toColorInt import androidx.core.graphics.toColorInt
import androidx.wear.compose.material3.Button import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.Text import androidx.wear.compose.material3.Text
@@ -29,12 +35,18 @@ import androidx.wear.compose.material3.Text
fun CardButton(cardInfo: CardInfo) { fun CardButton(cardInfo: CardInfo) {
val context = LocalContext.current val context = LocalContext.current
val cardColor = if (cardInfo.color == null)
MaterialTheme.colorScheme.primaryContainer
else
Color(cardInfo.color.toColorInt())
Box(modifier = Modifier.fillMaxWidth()) { Box(modifier = Modifier.fillMaxWidth()) {
Button( Button(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth().height(64.dp),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = (if (cardInfo.color == null) MaterialTheme.colorScheme.primaryContainer else Color(cardInfo.color.toColorInt())).copy(0.425f) containerColor = cardColor.copy(0.425f)
), ),
shape = RoundedCornerShape(12.dp),
contentPadding = PaddingValues(0.dp), contentPadding = PaddingValues(0.dp),
onClick = { onClick = {
val intent = Intent(context, ShowCardActivity::class.java) val intent = Intent(context, ShowCardActivity::class.java)
@@ -46,21 +58,55 @@ fun CardButton(cardInfo: CardInfo) {
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxSize()
.height(IntrinsicSize.Min) .background(Color.Transparent)
.clip(ButtonDefaults.shape) .padding(horizontal = 8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) { ) {
CardIcon(
if (cardInfo.icon == null) null else base64ToImageBitmap(cardInfo.icon),
cardColor = cardColor
)
Text( Text(
cardInfo.name, cardInfo.name,
fontSize = 16.sp, fontSize = 16.sp,
color = MaterialTheme.colorScheme.onPrimaryContainer, color = MaterialTheme.colorScheme.onPrimaryContainer,
modifier = Modifier modifier = Modifier.fillMaxWidth(),
.padding(16.dp)
.fillMaxWidth()
.weight(1f),
textAlign = TextAlign.Start textAlign = TextAlign.Start
) )
} }
} }
} }
} }
@Composable
fun CardIcon(icon: ImageBitmap?, cardColor: Color) {
Row(
modifier = Modifier
.background(
cardColor.copy(0.525f),
RoundedCornerShape(12.dp)
)
.padding(8.dp)
.size(32.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
if (icon == null) {
Icon(
modifier = Modifier.size(24.dp),
imageVector = Icons.Outlined.QrCode,
tint = MaterialTheme.colorScheme.onPrimaryContainer,
contentDescription = null
)
} else {
Image(
bitmap = icon,
contentDescription = null,
modifier = Modifier.size(32.dp)
)
}
}
}
@@ -1,6 +1,10 @@
package ru.omni_devel.cards.presentation package ru.omni_devel.cards.presentation
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.util.Base64
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap
import com.google.zxing.BarcodeFormat import com.google.zxing.BarcodeFormat
import com.google.zxing.MultiFormatWriter import com.google.zxing.MultiFormatWriter
import com.journeyapps.barcodescanner.BarcodeEncoder import com.journeyapps.barcodescanner.BarcodeEncoder
@@ -11,3 +15,10 @@ fun generateCode(value: String, format: BarcodeFormat, width: Int, height: Int):
return BarcodeEncoder().createBitmap(matrix) return BarcodeEncoder().createBitmap(matrix)
} }
fun base64ToImageBitmap(base64String: String): ImageBitmap {
val decodedBytes = Base64.decode(base64String, Base64.DEFAULT)
val bitmap = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size)
return bitmap.asImageBitmap()
}