Compare commits
6
Commits
2a538fdf1c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c593e06e4c | ||
|
|
235afe61e7 | ||
|
|
8f79b60399 | ||
|
|
20a62b77b6 | ||
|
|
4748a46156 | ||
|
|
c1a4414f10 |
@@ -23,7 +23,7 @@ android {
|
|||||||
minSdk = 30
|
minSdk = 30
|
||||||
targetSdk = 36
|
targetSdk = 36
|
||||||
versionCode = generateVersionCode()
|
versionCode = generateVersionCode()
|
||||||
versionName = "4.3.0"
|
versionName = "4.3.1"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
@@ -81,4 +81,5 @@ dependencies {
|
|||||||
implementation("io.ktor:ktor-client-core:3.5.0")
|
implementation("io.ktor:ktor-client-core:3.5.0")
|
||||||
implementation("io.ktor:ktor-client-cio:3.5.0")
|
implementation("io.ktor:ktor-client-cio:3.5.0")
|
||||||
implementation("androidx.compose.material:material-icons-extended")
|
implementation("androidx.compose.material:material-icons-extended")
|
||||||
|
implementation("sh.calvin.reorderable:reorderable:2.4.3")
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
@@ -10,6 +11,14 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.OmniCards">
|
android:theme="@style/Theme.OmniCards">
|
||||||
|
<activity
|
||||||
|
android:name="com.journeyapps.barcodescanner.CaptureActivity"
|
||||||
|
android:screenOrientation="portrait"
|
||||||
|
android:stateNotNeeded="true"
|
||||||
|
android:theme="@style/zxing_CaptureTheme"
|
||||||
|
android:windowSoftInputMode="stateAlwaysHidden"
|
||||||
|
tools:replace="android:screenOrientation" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".SelectIconActivity"
|
android:name=".SelectIconActivity"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
|
|||||||
@@ -15,5 +15,6 @@ class CardInfo (
|
|||||||
val codeType: BarcodeFormat,
|
val codeType: BarcodeFormat,
|
||||||
val codeValue: String,
|
val codeValue: String,
|
||||||
val color: String?,
|
val color: String?,
|
||||||
val icon: String?
|
val icon: String?,
|
||||||
|
val position: Int
|
||||||
) {}
|
) {}
|
||||||
|
|||||||
@@ -2,15 +2,17 @@ package ru.omni_devel.cards
|
|||||||
|
|
||||||
import android.content.ContentValues
|
import android.content.ContentValues
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.database.Cursor
|
||||||
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 androidx.core.database.getStringOrNull
|
||||||
|
import androidx.core.database.sqlite.transaction
|
||||||
import com.google.zxing.BarcodeFormat
|
import com.google.zxing.BarcodeFormat
|
||||||
|
|
||||||
class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?) : SQLiteOpenHelper(context, "omni_cards", factory, 6) {
|
class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?) : SQLiteOpenHelper(context, "omni_cards", factory, 8) {
|
||||||
override fun onCreate(db: SQLiteDatabase?) {
|
override fun onCreate(db: SQLiteDatabase?) {
|
||||||
db!!.execSQL(
|
db!!.execSQL(
|
||||||
"CREATE TABLE IF NOT EXISTS cards (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, codeType TEXT, codeValue TEXT, color TEXT, icon TEXT)"
|
"CREATE TABLE IF NOT EXISTS cards (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, codeType TEXT, codeValue TEXT, color TEXT, icon TEXT, position DEFAULT 0)"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,6 +44,32 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
|
|||||||
if (oldVersion < 6) {
|
if (oldVersion < 6) {
|
||||||
db!!.execSQL("ALTER TABLE cards ADD COLUMN icon TEXT")
|
db!!.execSQL("ALTER TABLE cards ADD COLUMN icon TEXT")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < 7) {
|
||||||
|
db!!.execSQL("ALTER TABLE cards ADD COLUMN position INTEGER DEFAULT 0")
|
||||||
|
db.execSQL("UPDATE cards SET position = id")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readCard(cursor: 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")),
|
||||||
|
icon = cursor.getStringOrNull(cursor.getColumnIndexOrThrow("icon")),
|
||||||
|
position = cursor.getInt(cursor.getColumnIndexOrThrow("position"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun nextPosition(db: SQLiteDatabase): Int {
|
||||||
|
val cursor = db.rawQuery("SELECT COALESCE(MAX(position), -1) + 1 FROM cards", null)
|
||||||
|
cursor.moveToFirst()
|
||||||
|
val next = cursor.getInt(0)
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
return next
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addCard(name: String, codeValue: String, codeType: BarcodeFormat, color: String?, icon: String?) {
|
fun addCard(name: String, codeValue: String, codeType: BarcodeFormat, color: String?, icon: String?) {
|
||||||
@@ -54,6 +82,7 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
|
|||||||
values.put("codeType", codeType.name)
|
values.put("codeType", codeType.name)
|
||||||
values.put("color", color)
|
values.put("color", color)
|
||||||
values.put("icon", icon)
|
values.put("icon", icon)
|
||||||
|
values.put("position", nextPosition(db))
|
||||||
|
|
||||||
db.insert("cards", null, values)
|
db.insert("cards", null, values)
|
||||||
|
|
||||||
@@ -79,18 +108,11 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
|
|||||||
fun getCards(): List<CardInfo> {
|
fun getCards(): List<CardInfo> {
|
||||||
val db = this.readableDatabase
|
val db = this.readableDatabase
|
||||||
|
|
||||||
val cursor = db.rawQuery("SELECT * FROM cards ORDER BY id ASC", null)
|
val cursor = db.rawQuery("SELECT * FROM cards ORDER BY position ASC", null)
|
||||||
val cards = mutableListOf<CardInfo>()
|
val cards = mutableListOf<CardInfo>()
|
||||||
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
cards.add(CardInfo(
|
cards.add(readCard(cursor))
|
||||||
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")),
|
|
||||||
icon = cursor.getStringOrNull(cursor.getColumnIndexOrThrow("icon"))
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
@@ -111,14 +133,7 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val cardInfo = CardInfo(
|
val cardInfo = readCard(cursor)
|
||||||
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")),
|
|
||||||
icon = cursor.getStringOrNull(cursor.getColumnIndexOrThrow("icon"))
|
|
||||||
)
|
|
||||||
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
db.close()
|
db.close()
|
||||||
@@ -143,6 +158,8 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
|
|||||||
fun addCards(cards: List<CardInfo>) {
|
fun addCards(cards: List<CardInfo>) {
|
||||||
val db = this.writableDatabase
|
val db = this.writableDatabase
|
||||||
|
|
||||||
|
db.use { db ->
|
||||||
|
db.transaction {
|
||||||
for (card in cards) {
|
for (card in cards) {
|
||||||
val values = ContentValues()
|
val values = ContentValues()
|
||||||
|
|
||||||
@@ -152,10 +169,27 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
|
|||||||
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)
|
values.put("icon", card.icon)
|
||||||
|
values.put("position", nextPosition(db))
|
||||||
|
|
||||||
db.insert("cards", null, values)
|
db.insert("cards", null, values)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
db.close()
|
fun updatePositions(orderedIds: List<Int>) {
|
||||||
|
val db = this.writableDatabase
|
||||||
|
|
||||||
|
db.use { db ->
|
||||||
|
db.transaction {
|
||||||
|
orderedIds.forEachIndexed { index, id ->
|
||||||
|
val values = ContentValues()
|
||||||
|
|
||||||
|
values.put("position", index)
|
||||||
|
|
||||||
|
db.update("cards", values, "id = ?", arrayOf(id.toString()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import androidx.compose.ui.graphics.Color
|
|||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.core.graphics.toColorInt
|
||||||
import com.google.zxing.BarcodeFormat
|
import com.google.zxing.BarcodeFormat
|
||||||
import com.journeyapps.barcodescanner.ScanContract
|
import com.journeyapps.barcodescanner.ScanContract
|
||||||
import com.journeyapps.barcodescanner.ScanOptions
|
import com.journeyapps.barcodescanner.ScanOptions
|
||||||
@@ -96,6 +97,11 @@ fun CardEditable(
|
|||||||
|
|
||||||
val fieldModifier = Modifier.fillMaxWidth()
|
val fieldModifier = Modifier.fillMaxWidth()
|
||||||
|
|
||||||
|
val cardColor = if (color == null)
|
||||||
|
MaterialTheme.colorScheme.primary
|
||||||
|
else
|
||||||
|
Color(color.toColorInt())
|
||||||
|
|
||||||
val scanLauncher = rememberLauncherForActivityResult(
|
val scanLauncher = rememberLauncherForActivityResult(
|
||||||
contract = ScanContract()
|
contract = ScanContract()
|
||||||
) { result ->
|
) { result ->
|
||||||
@@ -267,7 +273,7 @@ fun CardEditable(
|
|||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
CardIcon(if (icon == null) null else base64ToImageBitmap(icon), MaterialTheme.colorScheme.primary)
|
CardIcon(if (icon == null) null else base64ToImageBitmap(icon), cardColor)
|
||||||
|
|
||||||
Text(stringResource(R.string.do_select_icon))
|
Text(stringResource(R.string.do_select_icon))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material.icons.outlined.Add
|
import androidx.compose.material.icons.outlined.Add
|
||||||
import androidx.compose.material.icons.outlined.QrCode
|
import androidx.compose.material.icons.outlined.QrCode
|
||||||
import androidx.compose.material.icons.outlined.DensityMedium
|
import androidx.compose.material.icons.outlined.DensityMedium
|
||||||
|
import androidx.compose.material.icons.outlined.DragHandle
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||||
import androidx.compose.material3.FloatingActionButton
|
import androidx.compose.material3.FloatingActionButton
|
||||||
@@ -185,7 +186,7 @@ fun TopBar(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CardButton(cardInfo: CardInfo, onDeleteCard: (Int) -> Unit) {
|
fun CardButton(cardInfo: CardInfo, onDeleteCard: (Int) -> Unit, reorderIcon: (@Composable () -> Unit)? = null) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
var menuExpanded by remember { mutableStateOf(false) }
|
var menuExpanded by remember { mutableStateOf(false) }
|
||||||
@@ -222,6 +223,11 @@ fun CardButton(cardInfo: CardInfo, onDeleteCard: (Int) -> Unit) {
|
|||||||
.background(Color.Transparent)
|
.background(Color.Transparent)
|
||||||
.padding(horizontal = 8.dp),
|
.padding(horizontal = 8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
CardIcon(
|
CardIcon(
|
||||||
@@ -237,6 +243,11 @@ fun CardButton(cardInfo: CardInfo, onDeleteCard: (Int) -> Unit) {
|
|||||||
textAlign = TextAlign.Start
|
textAlign = TextAlign.Start
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reorderIcon != null) {
|
||||||
|
reorderIcon()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DropdownMenu(
|
DropdownMenu(
|
||||||
|
|||||||
@@ -9,23 +9,26 @@ import androidx.compose.animation.AnimatedVisibility
|
|||||||
import androidx.compose.animation.expandVertically
|
import androidx.compose.animation.expandVertically
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.animation.scaleIn
|
|
||||||
import androidx.compose.animation.scaleOut
|
|
||||||
import androidx.compose.animation.shrinkVertically
|
import androidx.compose.animation.shrinkVertically
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Add
|
import androidx.compose.material.icons.outlined.Add
|
||||||
import androidx.compose.material.icons.outlined.Sync
|
import androidx.compose.material.icons.outlined.Sync
|
||||||
import androidx.compose.material.icons.outlined.Backup
|
import androidx.compose.material.icons.outlined.Backup
|
||||||
import androidx.compose.material.icons.outlined.Code
|
import androidx.compose.material.icons.outlined.Code
|
||||||
|
import androidx.compose.material.icons.outlined.DragHandle
|
||||||
import androidx.compose.material.icons.outlined.Search
|
import androidx.compose.material.icons.outlined.Search
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -37,12 +40,15 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.runtime.mutableStateListOf
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import ru.omni_devel.cards.ui.theme.OmniCardsTheme
|
import ru.omni_devel.cards.ui.theme.OmniCardsTheme
|
||||||
|
import sh.calvin.reorderable.ReorderableItem
|
||||||
|
import sh.calvin.reorderable.rememberReorderableLazyListState
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
private lateinit var db: DbHelper
|
private lateinit var db: DbHelper
|
||||||
@@ -60,13 +66,22 @@ class MainActivity : ComponentActivity() {
|
|||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
MainPage(innerPadding, cards, onDeleteCard = { cardId ->
|
MainPage(
|
||||||
|
innerPadding,
|
||||||
|
cards,
|
||||||
|
onDeleteCard = { cardId ->
|
||||||
db.removeCard(cardId)
|
db.removeCard(cardId)
|
||||||
cards.removeIf { it.id == cardId }
|
cards.removeIf { it.id == cardId }
|
||||||
syncCardsWithWatch(this, db.getCards())
|
syncCardsWithWatch(this, db.getCards())
|
||||||
}, getDbFun = {
|
},
|
||||||
|
onReorderCards = {
|
||||||
|
db.updatePositions(it)
|
||||||
|
syncCardsWithWatch(this, db.getCards())
|
||||||
|
},
|
||||||
|
getDbFun = {
|
||||||
return@MainPage db
|
return@MainPage db
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,8 +100,9 @@ class MainActivity : ComponentActivity() {
|
|||||||
@Composable
|
@Composable
|
||||||
fun MainPage(
|
fun MainPage(
|
||||||
innerPadding: PaddingValues,
|
innerPadding: PaddingValues,
|
||||||
cards: List<CardInfo>,
|
cards: SnapshotStateList<CardInfo>,
|
||||||
onDeleteCard: (Int) -> Unit,
|
onDeleteCard: (Int) -> Unit,
|
||||||
|
onReorderCards: (List<Int>) -> Unit,
|
||||||
getDbFun: () -> DbHelper
|
getDbFun: () -> DbHelper
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
@@ -95,6 +111,19 @@ fun MainPage(
|
|||||||
var searchQuery by rememberSaveable { mutableStateOf("") }
|
var searchQuery by rememberSaveable { mutableStateOf("") }
|
||||||
var isSearchFieldShowed by rememberSaveable { mutableStateOf(false) }
|
var isSearchFieldShowed by rememberSaveable { mutableStateOf(false) }
|
||||||
|
|
||||||
|
val lazyListState = rememberLazyListState()
|
||||||
|
val reorderableLazyListState = rememberReorderableLazyListState(lazyListState) { from, to ->
|
||||||
|
val fromId = from.key as? Int ?: return@rememberReorderableLazyListState
|
||||||
|
val toId = to.key as? Int ?: return@rememberReorderableLazyListState
|
||||||
|
|
||||||
|
val fromIndex = cards.indexOfFirst { it.id == fromId }
|
||||||
|
val toIndex = cards.indexOfFirst { it.id == toId }
|
||||||
|
|
||||||
|
if (fromIndex != -1 && toIndex != -1) {
|
||||||
|
cards.add(toIndex, cards.removeAt(fromIndex))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
@@ -151,14 +180,11 @@ fun MainPage(
|
|||||||
cardNameCleaned = cardNameCleaned.replace(from, to)
|
cardNameCleaned = cardNameCleaned.replace(from, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cardNameCleaned.contains(queryCleaned)) {
|
return@filter cardNameCleaned.contains(queryCleaned)
|
||||||
return@filter true
|
|
||||||
}
|
|
||||||
|
|
||||||
return@filter false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
|
state = lazyListState,
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
@@ -192,8 +218,40 @@ fun MainPage(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (card in searchResults) {
|
for (card in searchResults) {
|
||||||
item {
|
item(key = card.id) {
|
||||||
CardButton(card, onDeleteCard)
|
ReorderableItem(reorderableLazyListState, key = card.id) { isDragging ->
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.alpha(if (isDragging) 0.7f else 1f)
|
||||||
|
) {
|
||||||
|
var reorderIcon: (@Composable () -> Unit)? = null
|
||||||
|
|
||||||
|
if (queryCleaned.isEmpty()) {
|
||||||
|
reorderIcon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.DragHandle,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||||
|
modifier = Modifier
|
||||||
|
.draggableHandle(
|
||||||
|
onDragStopped = {
|
||||||
|
onReorderCards(cards.map { it.id })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.padding(8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CardButton(
|
||||||
|
card,
|
||||||
|
onDeleteCard,
|
||||||
|
reorderIcon
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,5 +10,6 @@ class CardInfo (
|
|||||||
val codeType: BarcodeFormat,
|
val codeType: BarcodeFormat,
|
||||||
val codeValue: String,
|
val codeValue: String,
|
||||||
val color: String?,
|
val color: String?,
|
||||||
val icon: String?
|
val icon: String?,
|
||||||
|
val position: Int
|
||||||
)
|
)
|
||||||
@@ -2,12 +2,14 @@ package ru.omni_devel.cards.presentation
|
|||||||
|
|
||||||
import android.content.ContentValues
|
import android.content.ContentValues
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.database.Cursor
|
||||||
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 androidx.core.database.getStringOrNull
|
||||||
|
import androidx.core.database.sqlite.transaction
|
||||||
import com.google.zxing.BarcodeFormat
|
import com.google.zxing.BarcodeFormat
|
||||||
|
|
||||||
class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?) : SQLiteOpenHelper(context, "omni_cards", factory, 5) {
|
class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?) : SQLiteOpenHelper(context, "omni_cards", factory, 6) {
|
||||||
override fun onCreate(db: SQLiteDatabase?) {
|
override fun onCreate(db: SQLiteDatabase?) {
|
||||||
db!!.execSQL(
|
db!!.execSQL(
|
||||||
"CREATE TABLE IF NOT EXISTS cards (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, codeType TEXT, codeValue TEXT, color TEXT, icon TEXT)"
|
"CREATE TABLE IF NOT EXISTS cards (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, codeType TEXT, codeValue TEXT, color TEXT, icon TEXT)"
|
||||||
@@ -37,6 +39,23 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
|
|||||||
if (oldVersion < 5) {
|
if (oldVersion < 5) {
|
||||||
db!!.execSQL("ALTER TABLE cards ADD COLUMN icon TEXT")
|
db!!.execSQL("ALTER TABLE cards ADD COLUMN icon TEXT")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < 6) {
|
||||||
|
db!!.execSQL("ALTER TABLE cards ADD COLUMN position INTEGER DEFAULT 0")
|
||||||
|
db.execSQL("UPDATE cards SET position = id")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readCard(cursor: 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")),
|
||||||
|
icon = cursor.getStringOrNull(cursor.getColumnIndexOrThrow("icon")),
|
||||||
|
position = cursor.getInt(cursor.getColumnIndexOrThrow("position"))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearDatabase() {
|
fun clearDatabase() {
|
||||||
@@ -50,6 +69,8 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
|
|||||||
fun addCards(cards: List<CardInfo>) {
|
fun addCards(cards: List<CardInfo>) {
|
||||||
val db = this.writableDatabase
|
val db = this.writableDatabase
|
||||||
|
|
||||||
|
db.use { db ->
|
||||||
|
db.transaction {
|
||||||
for (card in cards) {
|
for (card in cards) {
|
||||||
val values = ContentValues()
|
val values = ContentValues()
|
||||||
|
|
||||||
@@ -59,28 +80,22 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
|
|||||||
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)
|
values.put("icon", card.icon)
|
||||||
|
values.put("position", card.position)
|
||||||
|
|
||||||
db.insert("cards", null, values)
|
db.insert("cards", null, values)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
db.close()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCards(): List<CardInfo> {
|
fun getCards(): List<CardInfo> {
|
||||||
val db = this.readableDatabase
|
val db = this.readableDatabase
|
||||||
|
|
||||||
val cursor = db.rawQuery("SELECT * FROM cards", null)
|
val cursor = db.rawQuery("SELECT * FROM cards ORDER BY position", null)
|
||||||
val cards = mutableListOf<CardInfo>()
|
val cards = mutableListOf<CardInfo>()
|
||||||
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
cards.add(CardInfo(
|
cards.add(readCard(cursor))
|
||||||
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")),
|
|
||||||
icon = cursor.getStringOrNull(cursor.getColumnIndexOrThrow("icon"))
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
@@ -101,14 +116,7 @@ class DbHelper(val context: Context, val factory: SQLiteDatabase.CursorFactory?)
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val cardInfo = CardInfo(
|
val cardInfo = readCard(cursor)
|
||||||
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")),
|
|
||||||
icon = cursor.getStringOrNull(cursor.getColumnIndexOrThrow("icon"))
|
|
||||||
)
|
|
||||||
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
db.close()
|
db.close()
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ class MessagesReceiver : WearableListenerService() {
|
|||||||
val json = String(event.data, Charsets.UTF_8)
|
val json = String(event.data, Charsets.UTF_8)
|
||||||
|
|
||||||
val cards = Json.decodeFromString<List<CardInfo>>(json)
|
val cards = Json.decodeFromString<List<CardInfo>>(json)
|
||||||
|
val oldCards = db.getCards()
|
||||||
|
|
||||||
|
if (cards == oldCards) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
db.clearDatabase()
|
db.clearDatabase()
|
||||||
db.addCards(cards)
|
db.addCards(cards)
|
||||||
|
|||||||
Reference in New Issue
Block a user