refactor: rewrite mobile app in Compose and add error handling for wear
This commit is contained in:
@@ -1,28 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Base.Theme.OmniCards">
|
||||
<activity
|
||||
android:name=".ShowCardActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:exported="false" />
|
||||
android:theme="@style/Theme.OmniCards">
|
||||
<activity
|
||||
android:name=".EditCardActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:exported="false" />
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_edit_card"
|
||||
android:theme="@style/Theme.OmniCards" />
|
||||
<activity
|
||||
android:name=".AddCardActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_add_card"
|
||||
android:theme="@style/Theme.OmniCards" />
|
||||
<activity
|
||||
android:name=".ShowCardActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_show_card"
|
||||
android:theme="@style/Theme.OmniCards" />
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:exported="true">
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.OmniCards">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
|
||||
@@ -14,4 +14,4 @@ class CardInfo (
|
||||
val name: String,
|
||||
val codeType: BarcodeFormat,
|
||||
val codeValue: String,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,124 +1,249 @@
|
||||
package ru.omni_devel.cards
|
||||
|
||||
import android.content.Intent
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Button
|
||||
import android.widget.EditText
|
||||
import android.widget.Spinner
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import com.journeyapps.barcodescanner.ScanContract
|
||||
import com.journeyapps.barcodescanner.ScanOptions
|
||||
import ru.omni_devel.cards.ui.theme.OmniCardsTheme
|
||||
|
||||
class EditCardActivity : AppCompatActivity() {
|
||||
class EditCardActivity : ComponentActivity() {
|
||||
private lateinit var db: DbHelper
|
||||
|
||||
private val barcodeLauncher = registerForActivityResult(ScanContract()) { result ->
|
||||
if (result.contents != null) {
|
||||
setCodeType(result.formatName)
|
||||
|
||||
findViewById<EditText>(R.id.cardValueInput).setText(result.contents)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
setContentView(R.layout.activity_edit_card)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||
insets
|
||||
}
|
||||
|
||||
val actionName = intent.getStringExtra("action") ?: EditCardAction.ADD.name
|
||||
val action = EditCardAction.valueOf(actionName)
|
||||
|
||||
db = DbHelper(this, null)
|
||||
|
||||
val actionLabel: TextView = findViewById(R.id.editCardActionLabel)
|
||||
val cardNameInput: EditText = findViewById(R.id.cardNameInput)
|
||||
val cardValueInput: EditText = findViewById(R.id.cardValueInput)
|
||||
val scanCodeButton: Button = findViewById(R.id.scanCodeButton)
|
||||
val cardCodeTypeSelector: Spinner = findViewById(R.id.cardCodeTypeSelector)
|
||||
val saveCardButton: Button = findViewById(R.id.saveCardButton)
|
||||
val cardId = intent.getIntExtra("cardId", -1)
|
||||
val cardInfo = db.getCard(cardId)
|
||||
|
||||
val options = BarcodeFormat.entries.map { it.name }
|
||||
val adapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, options)
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
cardCodeTypeSelector.adapter = adapter
|
||||
|
||||
scanCodeButton.setOnClickListener {
|
||||
val options = ScanOptions()
|
||||
options.setPrompt("Scan code")
|
||||
options.setBeepEnabled(false)
|
||||
options.setOrientationLocked(false)
|
||||
barcodeLauncher.launch(options)
|
||||
}
|
||||
|
||||
saveCardButton.setOnClickListener {
|
||||
val cardName = cardNameInput.text.toString()
|
||||
val cardValue = cardValueInput.text.toString()
|
||||
val cardCodeType = BarcodeFormat.valueOf(cardCodeTypeSelector.selectedItem.toString())
|
||||
|
||||
when (action) {
|
||||
EditCardAction.ADD -> {
|
||||
db.addCard(cardName, cardValue, cardCodeType)
|
||||
|
||||
finish()
|
||||
}
|
||||
EditCardAction.EDIT -> {
|
||||
val cardId = intent.getIntExtra("cardId", -1)
|
||||
|
||||
db.editCard(cardId, cardName, cardValue, cardCodeType)
|
||||
|
||||
val intent = Intent(this, ShowCardActivity::class.java)
|
||||
|
||||
intent.putExtra("cardId", cardId)
|
||||
|
||||
startActivity(intent)
|
||||
finish()
|
||||
setContent {
|
||||
OmniCardsTheme {
|
||||
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
|
||||
EditCardPage(cardInfo, innerPadding, getDbFun = {
|
||||
return@EditCardPage db
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (action) {
|
||||
EditCardAction.ADD -> {
|
||||
setCodeType("QR_CODE")
|
||||
@Composable
|
||||
fun CardEditable(
|
||||
cardName: String,
|
||||
onCardNameChange: (String) -> Unit,
|
||||
codeValue: String,
|
||||
oncodeValueChange: (String) -> Unit,
|
||||
codeType: BarcodeFormat,
|
||||
onCodeTypeChange: (BarcodeFormat) -> Unit
|
||||
) {
|
||||
var isCodeTypeDropdownExpanded by remember { mutableStateOf(false) }
|
||||
|
||||
actionLabel.text = "Adding card"
|
||||
}
|
||||
EditCardAction.EDIT -> {
|
||||
val cardId = intent.getIntExtra("cardId", -1)
|
||||
val fieldModifier = Modifier.fillMaxWidth()
|
||||
|
||||
val cardInfo = db.getCard(cardId)
|
||||
val scanLauncher = rememberLauncherForActivityResult(
|
||||
contract = ScanContract()
|
||||
) { result ->
|
||||
if (result.contents != null) {
|
||||
oncodeValueChange(result.contents)
|
||||
|
||||
if (cardInfo == null) {
|
||||
Toast.makeText(this, "cardInfo is null", Toast.LENGTH_LONG).show()
|
||||
return
|
||||
}
|
||||
|
||||
actionLabel.text = "Editing card"
|
||||
|
||||
cardNameInput.setText(cardInfo.name)
|
||||
cardValueInput.setText(cardInfo.codeValue)
|
||||
setCodeType(cardInfo.codeType.name)
|
||||
result.formatName?.let { formatName ->
|
||||
try {
|
||||
onCodeTypeChange(BarcodeFormat.valueOf(formatName))
|
||||
} catch (e: IllegalArgumentException) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setCodeType(codeTypeString: String) {
|
||||
val codeTypes = BarcodeFormat.entries.map { it.name }
|
||||
val codeTypeIndex = codeTypes.indexOf(codeTypeString)
|
||||
|
||||
if (codeTypeIndex >= 0) {
|
||||
findViewById<Spinner>(R.id.cardCodeTypeSelector).setSelection(codeTypeIndex)
|
||||
OutlinedTextField(
|
||||
value = cardName,
|
||||
onValueChange = onCardNameChange,
|
||||
modifier = fieldModifier,
|
||||
label = { Text("Name") }
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = codeValue,
|
||||
onValueChange = oncodeValueChange,
|
||||
modifier = Modifier.weight(1f),
|
||||
label = { Text("Value") }
|
||||
)
|
||||
Button(
|
||||
modifier = Modifier.align(Alignment.CenterVertically),
|
||||
onClick = {
|
||||
scanLauncher.launch(
|
||||
ScanOptions().apply {
|
||||
setPrompt("Scan your card")
|
||||
setBeepEnabled(true)
|
||||
setOrientationLocked(false)
|
||||
}
|
||||
)
|
||||
}
|
||||
) {
|
||||
Text("Scan")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = fieldModifier,
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = codeType.name,
|
||||
onValueChange = {},
|
||||
modifier = fieldModifier,
|
||||
label = { Text("Code type") },
|
||||
readOnly = true,
|
||||
)
|
||||
Box(
|
||||
modifier = fieldModifier
|
||||
.matchParentSize()
|
||||
.clickable { isCodeTypeDropdownExpanded = !isCodeTypeDropdownExpanded }
|
||||
)
|
||||
DropdownMenu(
|
||||
expanded = isCodeTypeDropdownExpanded,
|
||||
onDismissRequest = {
|
||||
isCodeTypeDropdownExpanded = false
|
||||
},
|
||||
modifier = fieldModifier
|
||||
) {
|
||||
BarcodeFormat.entries.forEach { format ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(format.name) },
|
||||
onClick = {
|
||||
onCodeTypeChange(format)
|
||||
isCodeTypeDropdownExpanded = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AddCard(innerPadding: PaddingValues, getDbFun: () -> DbHelper) {
|
||||
var cardName by remember { mutableStateOf("") }
|
||||
var codeValue by remember { mutableStateOf("") }
|
||||
var codeType by remember { mutableStateOf(BarcodeFormat.QR_CODE) }
|
||||
|
||||
val context = LocalContext.current as Activity
|
||||
|
||||
Page(
|
||||
"New card",
|
||||
innerPadding
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
CardEditable(
|
||||
cardName = cardName,
|
||||
onCardNameChange = { cardName = it },
|
||||
codeValue = codeValue,
|
||||
oncodeValueChange = { codeValue = it },
|
||||
codeType = codeType,
|
||||
onCodeTypeChange = { codeType = it }
|
||||
)
|
||||
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {
|
||||
val err = checkCardData(cardName, codeValue)
|
||||
|
||||
if (err == null) {
|
||||
getDbFun().addCard(cardName, codeValue, codeType)
|
||||
context.finish()
|
||||
} else {
|
||||
Toast.makeText(context, err, Toast.LENGTH_SHORT)
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text("Save")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EditCard(cardInfo: CardInfo, innerPadding: PaddingValues, getDbFun: () -> DbHelper) {
|
||||
var cardName by remember { mutableStateOf(cardInfo.name) }
|
||||
var codeValue by remember { mutableStateOf(cardInfo.codeValue) }
|
||||
var codeType by remember { mutableStateOf(cardInfo.codeType) }
|
||||
|
||||
val context = LocalContext.current as Activity
|
||||
|
||||
Page(
|
||||
"Editing card id${cardInfo.id}",
|
||||
innerPadding
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
CardEditable(
|
||||
cardName = cardName,
|
||||
onCardNameChange = { cardName = it },
|
||||
codeValue = codeValue,
|
||||
oncodeValueChange = { codeValue = it },
|
||||
codeType = codeType,
|
||||
onCodeTypeChange = { codeType = it }
|
||||
)
|
||||
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {
|
||||
val err = checkCardData(cardName, codeValue)
|
||||
|
||||
if (err == null) {
|
||||
getDbFun().editCard(cardInfo.id, cardName, codeValue, codeType)
|
||||
context.finish()
|
||||
} else {
|
||||
Toast.makeText(context, err, Toast.LENGTH_SHORT)
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text("Save")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EditCardPage(cardInfo: CardInfo?, innerPadding: PaddingValues, getDbFun: () -> DbHelper) {
|
||||
if (cardInfo == null) {
|
||||
AddCard(innerPadding, getDbFun)
|
||||
} else {
|
||||
EditCard(cardInfo, innerPadding, getDbFun)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
package ru.omni_devel.cards
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
@Composable
|
||||
fun Page(name: String, innerPadding: PaddingValues, content: @Composable () -> Unit) {
|
||||
Column(
|
||||
modifier = Modifier.padding(innerPadding)
|
||||
) {
|
||||
TopBar(name)
|
||||
|
||||
Column(
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TopBar(text: String) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().background(MaterialTheme.colorScheme.primaryContainer).padding(horizontal = 12.dp, vertical = 16.dp)
|
||||
) {
|
||||
Text(
|
||||
text,
|
||||
fontSize = 24.sp,
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CardButton(cardInfo: CardInfo, onDeleteCard: (Int) -> Unit, getDbFun: () -> DbHelper) {
|
||||
val context = LocalContext.current
|
||||
var menuExpanded by remember { mutableStateOf(false) }
|
||||
|
||||
Box(modifier = Modifier.fillMaxWidth()) {
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures(
|
||||
onTap = {
|
||||
val intent = Intent(context, ShowCardActivity::class.java)
|
||||
intent.putExtra("cardId", cardInfo.id)
|
||||
context.startActivity(intent)
|
||||
},
|
||||
onLongPress = {
|
||||
menuExpanded = true
|
||||
}
|
||||
)
|
||||
},
|
||||
shape = ButtonDefaults.shape,
|
||||
color = MaterialTheme.colorScheme.primaryContainer,
|
||||
tonalElevation = 2.dp
|
||||
) {
|
||||
Text(
|
||||
cardInfo.name,
|
||||
fontSize = 16.sp,
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
modifier = Modifier
|
||||
.padding(vertical = 16.dp, horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
textAlign = TextAlign.Start
|
||||
)
|
||||
}
|
||||
|
||||
DropdownMenu(
|
||||
expanded = menuExpanded,
|
||||
onDismissRequest = { menuExpanded = false }
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text("Edit") },
|
||||
onClick = {
|
||||
menuExpanded = false
|
||||
|
||||
val intent = Intent(context, EditCardActivity::class.java)
|
||||
|
||||
intent.putExtra("cardId", cardInfo.id)
|
||||
|
||||
context.startActivity(intent)
|
||||
}
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text("Delete") },
|
||||
onClick = {
|
||||
menuExpanded = false
|
||||
|
||||
onDeleteCard(cardInfo.id)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FullWidthButton(onClick: () -> Unit, content: @Composable () -> Unit) {
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = onClick
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
@@ -2,55 +2,64 @@ package ru.omni_devel.cards
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.PopupMenu
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import kotlinx.serialization.json.Json
|
||||
import ru.omni_devel.cards.ui.theme.OmniCardsTheme
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private lateinit var cardsList: LinearLayout
|
||||
class MainActivity : ComponentActivity() {
|
||||
private lateinit var db: DbHelper
|
||||
|
||||
private val cards = mutableStateListOf<CardInfo>()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
setContentView(R.layout.activity_main)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||
insets
|
||||
}
|
||||
|
||||
db = DbHelper(this, null)
|
||||
cardsList = findViewById(R.id.cardsList)
|
||||
|
||||
val addCardButton: Button = findViewById(R.id.addCardButton)
|
||||
val syncWithWearOSButton: Button = findViewById(R.id.syncWithWearOSButton)
|
||||
|
||||
addCardButton.setOnClickListener {
|
||||
val intent = Intent(this, EditCardActivity::class.java)
|
||||
|
||||
intent.putExtra("action", EditCardAction.ADD.name)
|
||||
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
syncWithWearOSButton.setOnClickListener {
|
||||
Toast.makeText(this, "Sync in progress...", Toast.LENGTH_SHORT).show()
|
||||
|
||||
sendToWatch(this, "/updateCards", Json.encodeToString(db.getCards())) { isSuccess ->
|
||||
if (isSuccess) {
|
||||
Toast.makeText(this, "Successfully synced!", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
Toast.makeText(this, "Sync failed! Please, check your connection", Toast.LENGTH_LONG).show()
|
||||
setContent {
|
||||
OmniCardsTheme {
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) { innerPadding ->
|
||||
MainPage(innerPadding, cards, onDeleteCard = { cardId ->
|
||||
db.removeCard(cardId)
|
||||
cards.removeIf { it.id == cardId }
|
||||
}, getDbFun = {
|
||||
return@MainPage db
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,84 +67,102 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
renderCards()
|
||||
|
||||
cards.clear()
|
||||
cards.addAll(db.getCards())
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderCards() {
|
||||
val cards = db.getCards()
|
||||
@Composable
|
||||
fun MainPage(
|
||||
innerPadding: PaddingValues,
|
||||
cards: List<CardInfo>,
|
||||
onDeleteCard: (Int) -> Unit,
|
||||
getDbFun: () -> DbHelper
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
cardsList.removeAllViews()
|
||||
var isActionBarShowed by remember { mutableStateOf(false) }
|
||||
|
||||
if (cards.isEmpty()) {
|
||||
val text = TextView(this)
|
||||
|
||||
val params = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
|
||||
text.text = "Add a card to get started"
|
||||
text.layoutParams = params
|
||||
text.textAlignment = View.TEXT_ALIGNMENT_CENTER
|
||||
|
||||
cardsList.addView(text)
|
||||
} else {
|
||||
for (card in cards) {
|
||||
val button = MaterialButton(this)
|
||||
|
||||
val params = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
params.setMargins(16, 4, 16, 4)
|
||||
|
||||
button.text = card.name
|
||||
button.layoutParams = params
|
||||
button.cornerRadius = (12 * resources.displayMetrics.density).toInt()
|
||||
|
||||
button.setOnClickListener {
|
||||
val intent = Intent(this, ShowCardActivity::class.java)
|
||||
|
||||
intent.putExtra("cardId", card.id)
|
||||
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
button.setOnLongClickListener { view ->
|
||||
val popup = PopupMenu(this, view)
|
||||
|
||||
popup.menu.add("Edit")
|
||||
popup.menu.add("Remove")
|
||||
|
||||
popup.setOnMenuItemClickListener { menuItem ->
|
||||
when (menuItem.title) {
|
||||
"Edit" -> {
|
||||
val intent = Intent(this, EditCardActivity::class.java)
|
||||
|
||||
intent.putExtra("action", EditCardAction.EDIT.name)
|
||||
intent.putExtra("cardId", card.id)
|
||||
|
||||
startActivity(intent)
|
||||
|
||||
true
|
||||
}
|
||||
"Remove" -> {
|
||||
db.removeCard(card.id)
|
||||
renderCards()
|
||||
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Page(
|
||||
"OmniCards",
|
||||
innerPadding
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(rememberScrollState()).padding(bottom = 64.dp).background(Color.Transparent).padding(top = 16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
if (cards.isEmpty()) {
|
||||
Text("Add new card to get started")
|
||||
} else {
|
||||
for (card in cards) {
|
||||
CardButton(card, onDeleteCard, getDbFun)
|
||||
}
|
||||
|
||||
popup.show()
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cardsList.addView(button)
|
||||
if (isActionBarShowed) {
|
||||
Column(
|
||||
modifier = Modifier.align(Alignment.BottomEnd).padding(16.dp).background(MaterialTheme.colorScheme.inversePrimary,
|
||||
RoundedCornerShape(24.dp)).padding(16.dp).fillMaxWidth()
|
||||
) {
|
||||
FullWidthButton(
|
||||
onClick = {
|
||||
isActionBarShowed = false
|
||||
|
||||
val intent = Intent(context, EditCardActivity::class.java)
|
||||
|
||||
context.startActivity(intent)
|
||||
}
|
||||
) {
|
||||
Text("Add card")
|
||||
}
|
||||
FullWidthButton(
|
||||
onClick = {
|
||||
Toast.makeText(context, "Sync in progress...", Toast.LENGTH_SHORT).show()
|
||||
|
||||
sendToWatch(context, "/updateCards", Json.encodeToString(getDbFun().getCards())) { isSuccess ->
|
||||
if (isSuccess) {
|
||||
Toast.makeText(context, "Successfully synced!", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
Toast.makeText(context, "Sync failed! Please, check your connection", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
isActionBarShowed = false
|
||||
}
|
||||
) {
|
||||
Text("Sync with WearOS")
|
||||
}
|
||||
FullWidthButton(
|
||||
onClick = {
|
||||
uriHandler.openUri("https://omni-devel.ru")
|
||||
}
|
||||
) {
|
||||
Text("About author")
|
||||
}
|
||||
FullWidthButton(
|
||||
onClick = {
|
||||
isActionBarShowed = false
|
||||
}
|
||||
) {
|
||||
Text(">")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Button(
|
||||
modifier = Modifier.align(Alignment.BottomEnd).padding(32.dp),
|
||||
onClick = {
|
||||
isActionBarShowed = true
|
||||
}
|
||||
) {
|
||||
Text("<")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,35 +2,61 @@ package ru.omni_devel.cards
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.WindowManager
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import ru.omni_devel.cards.ui.theme.OmniCardsTheme
|
||||
|
||||
class ShowCardActivity : AppCompatActivity() {
|
||||
class ShowCardActivity : ComponentActivity() {
|
||||
private lateinit var db: DbHelper
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
setContentView(R.layout.activity_show_card)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||
insets
|
||||
}
|
||||
|
||||
db = DbHelper(this, null)
|
||||
|
||||
val cardId = intent.getIntExtra("cardId", -1)
|
||||
|
||||
val cardInfo = db.getCard(cardId)
|
||||
|
||||
if (cardInfo == null) {
|
||||
Toast.makeText(this, "Card is not exists", Toast.LENGTH_LONG).show()
|
||||
finish()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
setContent {
|
||||
OmniCardsTheme {
|
||||
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
|
||||
ShowCardPage(innerPadding, cardInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
setBrightness(1.0f)
|
||||
renderCard()
|
||||
setBrightness(1f)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
@@ -39,31 +65,46 @@ class ShowCardActivity : AppCompatActivity() {
|
||||
setBrightness(WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE)
|
||||
}
|
||||
|
||||
private fun renderCard() {
|
||||
val cardId = intent.getIntExtra("cardId", 0)
|
||||
|
||||
val cardInfo = db.getCard(cardId)
|
||||
|
||||
if (cardInfo == null) {
|
||||
Toast.makeText(this, "cardInfo is null", Toast.LENGTH_LONG).show()
|
||||
return
|
||||
}
|
||||
|
||||
val cardCodeView: ImageView = findViewById(R.id.cardCodeView)
|
||||
val cardNameElement: TextView = findViewById(R.id.editCardActionLabel)
|
||||
|
||||
cardNameElement.text = cardInfo.name
|
||||
|
||||
val code = generateCode(cardInfo.codeValue, cardInfo.codeType)
|
||||
|
||||
cardCodeView.setImageBitmap(code)
|
||||
}
|
||||
|
||||
private fun setBrightness(level: Float) {
|
||||
val params = window.attributes
|
||||
|
||||
params.screenBrightness = level
|
||||
|
||||
window.attributes = params
|
||||
window.attributes.screenBrightness = level
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShowCardPage(innerPadding: PaddingValues, cardInfo: CardInfo) {
|
||||
val bitmap = remember(cardInfo) {
|
||||
try {
|
||||
generateCode(cardInfo.codeValue, cardInfo.codeType).asImageBitmap()
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
Page(cardInfo.name, innerPadding) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
if (bitmap != null) {
|
||||
Image(
|
||||
bitmap = bitmap,
|
||||
contentDescription = cardInfo.codeValue,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
contentScale = ContentScale.FillWidth
|
||||
)
|
||||
Text(
|
||||
cardInfo.codeValue,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
"Failed to generate code. Check card data",
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center,
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package ru.omni_devel.cards
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.widget.Toast
|
||||
import com.google.android.gms.wearable.Wearable
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import com.google.zxing.MultiFormatWriter
|
||||
@@ -10,16 +9,14 @@ import com.journeyapps.barcodescanner.BarcodeEncoder
|
||||
|
||||
fun generateCode(value: String, format: BarcodeFormat): Bitmap {
|
||||
val writer = MultiFormatWriter()
|
||||
val matrix = writer.encode(value, format, 600, 300)
|
||||
val matrix = writer.encode(value, format, 800, 400)
|
||||
|
||||
return BarcodeEncoder().createBitmap(matrix)
|
||||
}
|
||||
|
||||
fun sendToWatch(context: Context, path: String, message: String, onResult: (Boolean) -> Unit): Boolean {
|
||||
fun sendToWatch(context: Context, path: String, message: String, onResult: (Boolean) -> Unit) {
|
||||
val nodeClient = Wearable.getNodeClient(context)
|
||||
|
||||
var isSuccess = false
|
||||
|
||||
nodeClient.connectedNodes.addOnSuccessListener { nodes ->
|
||||
if (nodes.isEmpty()) {
|
||||
onResult(false)
|
||||
@@ -35,7 +32,7 @@ fun sendToWatch(context: Context, path: String, message: String, onResult: (Bool
|
||||
node.id,
|
||||
path,
|
||||
message.toByteArray(Charsets.UTF_8)
|
||||
).addOnCompleteListener { task ->
|
||||
).addOnCompleteListener(context.mainExecutor) { task ->
|
||||
completedCount++
|
||||
|
||||
if (task.isSuccessful) {
|
||||
@@ -45,11 +42,19 @@ fun sendToWatch(context: Context, path: String, message: String, onResult: (Bool
|
||||
if (completedCount == nodes.size) {
|
||||
onResult(isAnySuccess)
|
||||
}
|
||||
}.addOnFailureListener {
|
||||
}.addOnFailureListener(context.mainExecutor) {
|
||||
onResult(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isSuccess
|
||||
fun checkCardData(name: String, value: String): String? {
|
||||
if (name.trim().isEmpty()) {
|
||||
return "Name should not be empty"
|
||||
} else if (value.trim().isEmpty()) {
|
||||
return "Code value should not be empty"
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package ru.omni_devel.cards.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
val Purple80 = Color(0xFFD0BCFF)
|
||||
val PurpleGrey80 = Color(0xFFCCC2DC)
|
||||
val Pink80 = Color(0xFFEFB8C8)
|
||||
|
||||
val Purple40 = Color(0xFF6650a4)
|
||||
val PurpleGrey40 = Color(0xFF625b71)
|
||||
val Pink40 = Color(0xFF7D5260)
|
||||
@@ -0,0 +1,58 @@
|
||||
package ru.omni_devel.cards.ui.theme
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
primary = Purple80,
|
||||
secondary = PurpleGrey80,
|
||||
tertiary = Pink80
|
||||
)
|
||||
|
||||
private val LightColorScheme = lightColorScheme(
|
||||
primary = Purple40,
|
||||
secondary = PurpleGrey40,
|
||||
tertiary = Pink40
|
||||
|
||||
/* Other default colors to override
|
||||
background = Color(0xFFFFFBFE),
|
||||
surface = Color(0xFFFFFBFE),
|
||||
onPrimary = Color.White,
|
||||
onSecondary = Color.White,
|
||||
onTertiary = Color.White,
|
||||
onBackground = Color(0xFF1C1B1F),
|
||||
onSurface = Color(0xFF1C1B1F),
|
||||
*/
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun OmniCardsTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
// Dynamic color is available on Android 12+
|
||||
dynamicColor: Boolean = true,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val colorScheme = when {
|
||||
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||
val context = LocalContext.current
|
||||
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||
}
|
||||
|
||||
darkTheme -> DarkColorScheme
|
||||
else -> LightColorScheme
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package ru.omni_devel.cards.ui.theme
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
// Set of Material typography styles to start with
|
||||
val Typography = Typography(
|
||||
bodyLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
/* Other default text styles to override
|
||||
titleLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
labelSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 11.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
*/
|
||||
)
|
||||
@@ -1,87 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".EditCardActivity">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/editCardActionLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:text="Action"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/toolbar2"
|
||||
app:layout_constraintStart_toStartOf="@+id/toolbar2"
|
||||
app:layout_constraintTop_toTopOf="@+id/toolbar2" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar2"
|
||||
app:layout_constraintVertical_bias="0.0">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/cardNameInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="46dp"
|
||||
android:ems="10"
|
||||
android:hint="Card name"
|
||||
android:inputType="text" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/cardValueInput"
|
||||
android:layout_width="259dp"
|
||||
android:layout_height="46dp"
|
||||
android:ems="10"
|
||||
android:hint="Card value"
|
||||
android:inputType="text" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/scanCodeButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:text="Scan" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/cardCodeTypeSelector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/saveCardButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Save" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,73 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:text="OmniCards"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/toolbar"
|
||||
app:layout_constraintStart_toStartOf="@+id/toolbar"
|
||||
app:layout_constraintTop_toTopOf="@+id/toolbar" />
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/cardsList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" />
|
||||
</ScrollView>
|
||||
|
||||
<Button
|
||||
android:id="@+id/addCardButton"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="+"
|
||||
android:textSize="24sp"
|
||||
app:cornerRadius="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/syncWithWearOSButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:backgroundTint="#0E000000"
|
||||
android:text="Sync with WearOS"
|
||||
app:cornerRadius="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/toolbar"
|
||||
app:layout_constraintEnd_toEndOf="@+id/toolbar"
|
||||
app:layout_constraintTop_toTopOf="@+id/toolbar" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,43 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".EditCardActivity">
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".ShowCardActivity">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar2"
|
||||
android:layout_width="0dp"
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/editCardActionLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:text="Card name"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/toolbar2"
|
||||
app:layout_constraintStart_toStartOf="@+id/toolbar2"
|
||||
app:layout_constraintTop_toTopOf="@+id/toolbar2" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/cardCodeView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="300dp"
|
||||
android:scaleType="fitCenter"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar2" />
|
||||
android:fitsSystemWindows="true"
|
||||
>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width = "match_parent"
|
||||
android:layout_height = "?attr/actionBarSize" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<include layout="@layout/content_show_card"/>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginEnd="@dimen/fab_margin"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:srcCompat="@android:drawable/ic_dialog_email" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/nav_host_fragment_content_show_card"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:defaultNavHost="true"
|
||||
app:navGraph="@navigation/nav_graph" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.core.widget.NestedScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".FirstFragment">
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="16dp">
|
||||
<Button
|
||||
android:id="@+id/button_first"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/next"
|
||||
app:layout_constraintBottom_toTopOf="@id/textview_first"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textview_first"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/lorem_ipsum"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/button_first" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.core.widget.NestedScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".SecondFragment">
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="16dp">
|
||||
<Button
|
||||
android:id="@+id/button_second"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/previous"
|
||||
app:layout_constraintBottom_toTopOf="@id/textview_second"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textview_second"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/lorem_ipsum"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/button_second" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
@@ -1,18 +1,4 @@
|
||||
<!--
|
||||
~ Copyright (C) 2026 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
<!--
|
||||
~ Copyright (C) 2026 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/nav_graph"
|
||||
app:startDestination="@id/FirstFragment">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/FirstFragment"
|
||||
android:name="ru.omni_devel.cards.FirstFragment"
|
||||
android:label="@string/first_fragment_label"
|
||||
tools:layout="@layout/fragment_first" >
|
||||
|
||||
<action
|
||||
android:id="@+id/action_FirstFragment_to_SecondFragment"
|
||||
app:destination="@id/SecondFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/SecondFragment"
|
||||
android:name="ru.omni_devel.cards.SecondFragment"
|
||||
android:label="@string/second_fragment_label"
|
||||
tools:layout="@layout/fragment_second" >
|
||||
|
||||
<action
|
||||
android:id="@+id/action_SecondFragment_to_FirstFragment"
|
||||
app:destination="@id/FirstFragment" />
|
||||
</fragment>
|
||||
</navigation>
|
||||
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<dimen name="fab_margin">48dp</dimen>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Base.Theme.OmniCards" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<!-- Customize your dark theme here. -->
|
||||
<!-- <item name="colorPrimary">@color/my_dark_primary</item> -->
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,8 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<style name="Theme.OmniCards" parent="Base.Theme.OmniCards">
|
||||
<!-- Transparent system bars for edge-to-edge. -->
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowLightStatusBar">?attr/isLightTheme</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<dimen name="fab_margin">200dp</dimen>
|
||||
</resources>
|
||||
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<dimen name="fab_margin">48dp</dimen>
|
||||
</resources>
|
||||
@@ -1,33 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Backgrounds -->
|
||||
<color name="bg_app">#0B0E17</color>
|
||||
<color name="bg_surface">#0E1118</color>
|
||||
<color name="bg_card">#131726</color>
|
||||
<color name="bg_elevated">#1A2235</color>
|
||||
<color name="bg_hover">#212B42</color>
|
||||
|
||||
<!-- Accent (indigo) -->
|
||||
<color name="accent_subtle">#152045</color>
|
||||
<color name="accent_primary">#2952C8</color>
|
||||
<color name="accent_hover">#3D6AE8</color>
|
||||
<color name="accent_light">#6B90FF</color>
|
||||
|
||||
<!-- Text -->
|
||||
<color name="text_primary">#DCE3F5</color>
|
||||
<color name="text_secondary">#8A9BBC</color>
|
||||
<color name="text_hint">#4E5E80</color>
|
||||
|
||||
<!-- Borders -->
|
||||
<color name="border_subtle">#1C2030</color>
|
||||
<color name="border_default">#1C2A42</color>
|
||||
<color name="border_active">#2A3D60</color>
|
||||
|
||||
<!-- Semantic -->
|
||||
<color name="success_bg">#0F3320</color>
|
||||
<color name="success">#2ECC71</color>
|
||||
<color name="error_bg">#3D1515</color>
|
||||
<color name="error">#E05555</color>
|
||||
<color name="warning_bg">#3D2E00</color>
|
||||
<color name="warning">#F0A500</color>
|
||||
<color name="purple_200">#FFBB86FC</color>
|
||||
<color name="purple_500">#FF6200EE</color>
|
||||
<color name="purple_700">#FF3700B3</color>
|
||||
<color name="teal_200">#FF03DAC5</color>
|
||||
<color name="teal_700">#FF018786</color>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<dimen name="fab_margin">16dp</dimen>
|
||||
</resources>
|
||||
@@ -1,3 +1,48 @@
|
||||
<resources>
|
||||
<string name="app_name">OmniCards</string>
|
||||
<!-- Strings used for fragments for navigation -->
|
||||
<string name="first_fragment_label">First Fragment</string>
|
||||
<string name="second_fragment_label">Second Fragment</string>
|
||||
<string name="next">Next</string>
|
||||
<string name="previous">Previous</string>
|
||||
|
||||
<string name="lorem_ipsum">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam in scelerisque sem. Mauris
|
||||
volutpat, dolor id interdum ullamcorper, risus dolor egestas lectus, sit amet mattis purus
|
||||
dui nec risus. Maecenas non sodales nisi, vel dictum dolor. Class aptent taciti sociosqu ad
|
||||
litora torquent per conubia nostra, per inceptos himenaeos. Suspendisse blandit eleifend
|
||||
diam, vel rutrum tellus vulputate quis. Aliquam eget libero aliquet, imperdiet nisl a,
|
||||
ornare ex. Sed rhoncus est ut libero porta lobortis. Fusce in dictum tellus.\n\n
|
||||
Suspendisse interdum ornare ante. Aliquam nec cursus lorem. Morbi id magna felis. Vivamus
|
||||
egestas, est a condimentum egestas, turpis nisl iaculis ipsum, in dictum tellus dolor sed
|
||||
neque. Morbi tellus erat, dapibus ut sem a, iaculis tincidunt dui. Interdum et malesuada
|
||||
fames ac ante ipsum primis in faucibus. Curabitur et eros porttitor, ultricies urna vitae,
|
||||
molestie nibh. Phasellus at commodo eros, non aliquet metus. Sed maximus nisl nec dolor
|
||||
bibendum, vel congue leo egestas.\n\n
|
||||
Sed interdum tortor nibh, in sagittis risus mollis quis. Curabitur mi odio, condimentum sit
|
||||
amet auctor at, mollis non turpis. Nullam pretium libero vestibulum, finibus orci vel,
|
||||
molestie quam. Fusce blandit tincidunt nulla, quis sollicitudin libero facilisis et. Integer
|
||||
interdum nunc ligula, et fermentum metus hendrerit id. Vestibulum lectus felis, dictum at
|
||||
lacinia sit amet, tristique id quam. Cras eu consequat dui. Suspendisse sodales nunc ligula,
|
||||
in lobortis sem porta sed. Integer id ultrices magna, in luctus elit. Sed a pellentesque
|
||||
est.\n\n
|
||||
Aenean nunc velit, lacinia sed dolor sed, ultrices viverra nulla. Etiam a venenatis nibh.
|
||||
Morbi laoreet, tortor sed facilisis varius, nibh orci rhoncus nulla, id elementum leo dui
|
||||
non lorem. Nam mollis ipsum quis auctor varius. Quisque elementum eu libero sed commodo. In
|
||||
eros nisl, imperdiet vel imperdiet et, scelerisque a mauris. Pellentesque varius ex nunc,
|
||||
quis imperdiet eros placerat ac. Duis finibus orci et est auctor tincidunt. Sed non viverra
|
||||
ipsum. Nunc quis augue egestas, cursus lorem at, molestie sem. Morbi a consectetur ipsum, a
|
||||
placerat diam. Etiam vulputate dignissim convallis. Integer faucibus mauris sit amet finibus
|
||||
convallis.\n\n
|
||||
Phasellus in aliquet mi. Pellentesque habitant morbi tristique senectus et netus et
|
||||
malesuada fames ac turpis egestas. In volutpat arcu ut felis sagittis, in finibus massa
|
||||
gravida. Pellentesque id tellus orci. Integer dictum, lorem sed efficitur ullamcorper,
|
||||
libero justo consectetur ipsum, in mollis nisl ex sed nisl. Donec maximus ullamcorper
|
||||
sodales. Praesent bibendum rhoncus tellus nec feugiat. In a ornare nulla. Donec rhoncus
|
||||
libero vel nunc consequat, quis tincidunt nisl eleifend. Cras bibendum enim a justo luctus
|
||||
vestibulum. Fusce dictum libero quis erat maximus, vitae volutpat diam dignissim.
|
||||
</string>
|
||||
<string name="title_activity_show_card">ShowCardActivity</string>
|
||||
<string name="title_activity_add_card">AddCardActivity</string>
|
||||
<string name="title_activity_edit_card">EditCardActivity</string>
|
||||
</resources>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="CardButton" parent="Widget.Material3.Button">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">64dp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="cornerRadius">8dp</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,29 +1,10 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="Theme.OmniCards" parent="android:Theme.Material.Light.NoActionBar" />
|
||||
<!-- Base application theme. -->
|
||||
<style name="Base.Theme.OmniCards" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<item name="colorPrimary">@color/accent_primary</item>
|
||||
<item name="colorOnPrimary">@color/text_primary</item>
|
||||
<item name="colorPrimaryContainer">@color/accent_subtle</item>
|
||||
<item name="colorOnPrimaryContainer">@color/accent_light</item>
|
||||
|
||||
<item name="colorSurface">@color/bg_card</item>
|
||||
<item name="colorOnSurface">@color/text_primary</item>
|
||||
<item name="colorSurfaceVariant">@color/bg_elevated</item>
|
||||
<item name="colorOnSurfaceVariant">@color/text_secondary</item>
|
||||
|
||||
<item name="colorOutline">@color/border_default</item>
|
||||
<item name="colorOutlineVariant">@color/border_subtle</item>
|
||||
|
||||
<item name="colorError">@color/error</item>
|
||||
<item name="colorOnError">@color/text_primary</item>
|
||||
<item name="colorErrorContainer">@color/error_bg</item>
|
||||
|
||||
<item name="android:windowBackground">@color/bg_app</item>
|
||||
<item name="android:textColorPrimary">@color/text_primary</item>
|
||||
<item name="android:textColorSecondary">@color/text_secondary</item>
|
||||
<item name="android:textColorHint">@color/text_hint</item>
|
||||
<item name="android:colorBackground">@color/bg_app</item>
|
||||
|
||||
<item name="android:statusBarColor">@color/bg_app</item>
|
||||
<item name="android:navigationBarColor">@color/bg_app</item>
|
||||
<!-- Customize your light theme here. -->
|
||||
<!-- <item name="colorPrimary">@color/my_light_primary</item> -->
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Sample backup rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/guide/topics/data/autobackup
|
||||
for details.
|
||||
Note: This file is ignored for devices older than API 31
|
||||
See https://developer.android.com/about/versions/12/backup-restore
|
||||
-->
|
||||
<full-backup-content>
|
||||
<!--
|
||||
<include domain="sharedpref" path="."/>
|
||||
<exclude domain="sharedpref" path="device.xml"/>
|
||||
-->
|
||||
</full-backup-content>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Sample data extraction rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
|
||||
for details.
|
||||
-->
|
||||
<data-extraction-rules>
|
||||
<cloud-backup>
|
||||
<!-- TODO: Use <include> and <exclude> to control what is backed up.
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
-->
|
||||
</cloud-backup>
|
||||
<!--
|
||||
<device-transfer>
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
</device-transfer>
|
||||
-->
|
||||
</data-extraction-rules>
|
||||
Reference in New Issue
Block a user