Skip to content
This repository was archived by the owner on Oct 24, 2025. It is now read-only.

Commit 0c48d75

Browse files
committed
sample: android
1 parent 6fc8d38 commit 0c48d75

File tree

9 files changed

+697
-125
lines changed

9 files changed

+697
-125
lines changed

samples/android/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ android {
2626
jvmToolchain(17)
2727
}
2828
composeOptions {
29-
kotlinCompilerExtensionVersion = "1.5.6"
29+
kotlinCompilerExtensionVersion = "1.5.10"
3030
}
3131
}
3232

@@ -40,4 +40,5 @@ dependencies {
4040
implementation("androidx.compose.ui:ui:1.5.4")
4141
implementation("androidx.compose.foundation:foundation:1.5.4")
4242
implementation("androidx.compose.material:material:1.5.4")
43+
implementation("com.google.code.gson:gson:2.10.1")
4344
}

samples/android/src/main/java/com/asyncstorage/sqlite/android/example/MainActivity.kt

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,85 @@ package com.asyncstorage.sqlite.android.example
33
import android.os.Bundle
44
import androidx.activity.compose.setContent
55
import androidx.appcompat.app.AppCompatActivity
6-
import com.asyncstorage.sqlite.android.example.ui.MainScreen
7-
import org.asyncstorage.sqlitestorage.SQLiteStorage
8-
import org.asyncstorage.sqlitestorage.SQLiteStorageFactory
6+
import androidx.compose.foundation.layout.Box
7+
import androidx.compose.foundation.layout.fillMaxSize
8+
import androidx.compose.foundation.layout.padding
9+
import androidx.compose.material.BottomNavigation
10+
import androidx.compose.material.BottomNavigationItem
11+
import androidx.compose.material.Icon
12+
import androidx.compose.material.Scaffold
13+
import androidx.compose.material.Text
14+
import androidx.compose.material.icons.Icons
15+
import androidx.compose.material.icons.filled.Home
16+
import androidx.compose.material.icons.filled.Lock
17+
import androidx.compose.material.icons.filled.Menu
18+
import androidx.compose.material.icons.filled.Refresh
19+
import androidx.compose.runtime.Composable
20+
import androidx.compose.runtime.getValue
21+
import androidx.compose.runtime.key
22+
import androidx.compose.runtime.mutableStateOf
23+
import androidx.compose.runtime.remember
24+
import androidx.compose.runtime.setValue
25+
import androidx.compose.ui.Modifier
26+
import androidx.compose.ui.graphics.vector.ImageVector
27+
import com.asyncstorage.sqlite.android.example.ui.basic.BasicPage
28+
import com.asyncstorage.sqlite.android.example.ui.keys.KeysPage
29+
import com.asyncstorage.sqlite.android.example.ui.merge.MergePage
30+
import com.asyncstorage.sqlite.android.example.ui.multi.MultiPage
931

1032
class MainActivity : AppCompatActivity() {
11-
lateinit var db: SQLiteStorage
12-
1333
override fun onCreate(savedInstanceState: Bundle?) {
1434
super.onCreate(savedInstanceState)
15-
db = SQLiteStorageFactory(this).create("my_db")
16-
db.files.size()
1735
setContent {
18-
MainScreen(db)
36+
TabNavigation()
37+
}
38+
}
39+
}
40+
41+
42+
sealed class Screens(val name: String, val icon: ImageVector) {
43+
data object Basic : Screens("Basic", Icons.Filled.Home)
44+
data object Multi : Screens("Multi", Icons.Filled.Menu)
45+
data object Keys : Screens("Keys", Icons.Filled.Lock)
46+
data object Merge : Screens("Merge", Icons.Filled.Refresh)
47+
}
48+
49+
val tabs = listOf(
50+
Screens.Basic,
51+
Screens.Multi,
52+
Screens.Keys,
53+
Screens.Merge,
54+
)
55+
56+
@Composable
57+
fun TabNavigation() {
58+
var activeScreen: Screens by remember {
59+
mutableStateOf(Screens.Basic)
60+
}
61+
62+
Scaffold(bottomBar = {
63+
BottomNavigation {
64+
for (tab in tabs) {
65+
key(tab.name) {
66+
BottomNavigationItem(
67+
selected = activeScreen == tab,
68+
onClick = { activeScreen = tab },
69+
icon = { Icon(tab.icon, contentDescription = null) },
70+
label = {
71+
Text(text = tab.name)
72+
}
73+
)
74+
}
75+
}
76+
}
77+
}) {
78+
Box(modifier = Modifier.padding(it)) {
79+
when (activeScreen) {
80+
Screens.Basic -> BasicPage(modifier = Modifier.fillMaxSize())
81+
Screens.Multi -> MultiPage(modifier = Modifier.fillMaxSize())
82+
Screens.Keys -> KeysPage(modifier = Modifier.fillMaxSize())
83+
Screens.Merge -> MergePage(modifier = Modifier.fillMaxSize())
84+
}
1985
}
2086
}
2187
}

samples/android/src/main/java/com/asyncstorage/sqlite/android/example/ui/MainScreen.kt

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
package com.asyncstorage.sqlite.android.example.ui.basic
2+
3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.Row
6+
import androidx.compose.foundation.layout.Spacer
7+
import androidx.compose.foundation.layout.fillMaxWidth
8+
import androidx.compose.foundation.layout.height
9+
import androidx.compose.foundation.layout.padding
10+
import androidx.compose.foundation.layout.size
11+
import androidx.compose.foundation.layout.width
12+
import androidx.compose.foundation.rememberScrollState
13+
import androidx.compose.foundation.text.KeyboardActions
14+
import androidx.compose.foundation.text.KeyboardOptions
15+
import androidx.compose.foundation.verticalScroll
16+
import androidx.compose.material.Button
17+
import androidx.compose.material.ButtonDefaults
18+
import androidx.compose.material.Divider
19+
import androidx.compose.material.Icon
20+
import androidx.compose.material.IconButton
21+
import androidx.compose.material.Text
22+
import androidx.compose.material.TextField
23+
import androidx.compose.material.icons.Icons
24+
import androidx.compose.material.icons.filled.Clear
25+
import androidx.compose.runtime.Composable
26+
import androidx.compose.runtime.DisposableEffect
27+
import androidx.compose.runtime.getValue
28+
import androidx.compose.runtime.mutableStateListOf
29+
import androidx.compose.runtime.mutableStateOf
30+
import androidx.compose.runtime.remember
31+
import androidx.compose.runtime.rememberCoroutineScope
32+
import androidx.compose.runtime.setValue
33+
import androidx.compose.ui.Alignment
34+
import androidx.compose.ui.Modifier
35+
import androidx.compose.ui.graphics.Color
36+
import androidx.compose.ui.platform.LocalFocusManager
37+
import androidx.compose.ui.text.font.FontWeight
38+
import androidx.compose.ui.text.input.ImeAction
39+
import androidx.compose.ui.unit.dp
40+
import androidx.compose.ui.unit.sp
41+
import com.asyncstorage.sqlite.android.example.ui.rememberStorage
42+
import kotlinx.coroutines.launch
43+
import org.asyncstorage.sqlitestorage.models.Entry
44+
import kotlin.random.Random
45+
46+
47+
@Composable
48+
fun BasicPage(modifier: Modifier = Modifier) {
49+
Column(modifier = modifier.padding(vertical = 8.dp)) {
50+
var databaseName by remember {
51+
mutableStateOf("basic.db")
52+
}
53+
54+
DatabaseNamePicker(databaseName) { databaseName = it }
55+
DatabaseActions(databaseName)
56+
}
57+
}
58+
59+
@Composable
60+
fun DatabaseNamePicker(initial: String, onPick: (String) -> Unit) {
61+
var databaseName by remember {
62+
mutableStateOf(initial)
63+
}
64+
val focusManager = LocalFocusManager.current
65+
66+
67+
fun submitName() {
68+
onPick(databaseName)
69+
focusManager.clearFocus()
70+
}
71+
72+
Row(
73+
modifier = Modifier.fillMaxWidth(),
74+
verticalAlignment = Alignment.CenterVertically,
75+
horizontalArrangement = Arrangement.SpaceEvenly
76+
) {
77+
TextField(
78+
value = databaseName,
79+
onValueChange = { databaseName = it },
80+
maxLines = 1,
81+
singleLine = true,
82+
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
83+
keyboardActions = KeyboardActions(onDone = { submitName() })
84+
)
85+
Button(onClick = { submitName() }) {
86+
Text("Select")
87+
}
88+
}
89+
}
90+
91+
92+
const val KEY = "random"
93+
94+
@Composable
95+
fun DatabaseActions(dbName: String) {
96+
val database = rememberStorage(name = dbName)
97+
var currentValue: String? by remember(database) {
98+
mutableStateOf(null)
99+
}
100+
val changesInTime = remember(database) {
101+
mutableStateListOf<String?>()
102+
}
103+
val scope = rememberCoroutineScope()
104+
105+
DisposableEffect(key1 = database) {
106+
val job = scope.launch {
107+
database.readAsFlow(listOf(KEY)).collect {
108+
changesInTime.add(it.first().value)
109+
}
110+
}
111+
112+
onDispose {
113+
job.cancel()
114+
}
115+
}
116+
117+
118+
fun saveRandom() {
119+
scope.launch {
120+
val value = Random.nextInt(from = 1, until = 100).toString()
121+
val entry = Entry(KEY, value)
122+
database.write(entry)
123+
}
124+
}
125+
126+
fun readRandom() {
127+
scope.launch {
128+
val result = database.read(KEY)
129+
currentValue = result.value ?: "null"
130+
}
131+
}
132+
133+
fun removeRandom() {
134+
scope.launch {
135+
database.remove(KEY)
136+
}
137+
}
138+
139+
140+
141+
Column {
142+
Row(
143+
modifier = Modifier
144+
.fillMaxWidth()
145+
.padding(vertical = 4.dp),
146+
horizontalArrangement = Arrangement.Center
147+
) {
148+
Text("database")
149+
Spacer(modifier = Modifier.size(4.dp))
150+
Text(dbName, fontWeight = FontWeight.Bold)
151+
}
152+
153+
154+
Row(
155+
modifier = Modifier.fillMaxWidth(),
156+
horizontalArrangement = Arrangement.Center
157+
) {
158+
Button(onClick = { saveRandom() }) {
159+
Text("Save")
160+
}
161+
Spacer(modifier = Modifier.width(4.dp))
162+
Button(onClick = { readRandom() }) {
163+
Text("Read")
164+
}
165+
Spacer(modifier = Modifier.width(4.dp))
166+
Button(
167+
onClick = { removeRandom() },
168+
colors = ButtonDefaults.buttonColors(backgroundColor = Color.Red)
169+
) {
170+
Text("Remove", color = Color.White)
171+
}
172+
}
173+
174+
Row(
175+
modifier = Modifier
176+
.fillMaxWidth()
177+
.padding(vertical = 4.dp),
178+
horizontalArrangement = Arrangement.Center
179+
) {
180+
Text("current value:")
181+
Spacer(modifier = Modifier.size(4.dp))
182+
Text(currentValue ?: "null", fontWeight = FontWeight.Bold)
183+
}
184+
185+
Spacer(Modifier.height(16.dp))
186+
Divider()
187+
Spacer(Modifier.height(16.dp))
188+
189+
Row(
190+
modifier = Modifier.fillMaxWidth(),
191+
verticalAlignment = Alignment.CenterVertically,
192+
horizontalArrangement = Arrangement.Start
193+
) {
194+
IconButton(
195+
onClick = { changesInTime.clear() }, modifier = Modifier
196+
.padding(4.dp)
197+
.size(20.dp)
198+
) {
199+
Icon(
200+
Icons.Filled.Clear,
201+
contentDescription = null,
202+
tint = Color.Red,
203+
)
204+
}
205+
Text("Value changes in time:", fontSize = 14.sp)
206+
}
207+
Column(
208+
modifier = Modifier
209+
.fillMaxWidth()
210+
.verticalScroll(state = rememberScrollState()),
211+
verticalArrangement = Arrangement.spacedBy(8.dp)
212+
) {
213+
for (change in changesInTime) {
214+
Text(
215+
text = "updated to: ${change ?: "null"}",
216+
fontSize = 18.sp,
217+
modifier = Modifier.padding(8.dp),
218+
)
219+
Divider()
220+
}
221+
}
222+
}
223+
}

0 commit comments

Comments
 (0)