mirror of
https://github.com/smyalygames/vegan-e-numbers.git
synced 2025-05-18 17:04:14 +02:00
feat(app): add ScreenModel for list and search bar
This commit is contained in:
parent
f21c70746a
commit
351223826b
@ -34,6 +34,7 @@ kotlin {
|
|||||||
androidMain.dependencies {
|
androidMain.dependencies {
|
||||||
implementation(compose.preview)
|
implementation(compose.preview)
|
||||||
implementation(libs.androidx.activity.compose)
|
implementation(libs.androidx.activity.compose)
|
||||||
|
implementation(libs.kotlinx.coroutines.android)
|
||||||
}
|
}
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
implementation(compose.runtime)
|
implementation(compose.runtime)
|
||||||
@ -43,8 +44,13 @@ kotlin {
|
|||||||
implementation(compose.ui)
|
implementation(compose.ui)
|
||||||
implementation(compose.components.resources)
|
implementation(compose.components.resources)
|
||||||
implementation(compose.components.uiToolingPreview)
|
implementation(compose.components.uiToolingPreview)
|
||||||
|
|
||||||
implementation(libs.kotlinx.serialization.json)
|
implementation(libs.kotlinx.serialization.json)
|
||||||
|
implementation(libs.kotlinx.coroutines.core)
|
||||||
|
|
||||||
implementation(libs.voyager.navigator)
|
implementation(libs.voyager.navigator)
|
||||||
|
implementation(libs.voyager.tab)
|
||||||
|
implementation(libs.voyager.screenmodel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,4 +91,7 @@ android {
|
|||||||
debugImplementation(compose.uiTooling)
|
debugImplementation(compose.uiTooling)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dependencies {
|
||||||
|
implementation(libs.androidx.material3.android)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
import android.os.Build
|
|
||||||
|
|
||||||
class AndroidPlatform : Platform {
|
|
||||||
override val name: String = "Android ${Build.VERSION.SDK_INT}"
|
|
||||||
}
|
|
||||||
|
|
||||||
actual fun getPlatform(): Platform = AndroidPlatform()
|
|
@ -1,78 +1,13 @@
|
|||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.Menu
|
|
||||||
import androidx.compose.material.icons.filled.Search
|
|
||||||
import androidx.compose.material3.*
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
|
||||||
import cafe.adriel.voyager.navigator.Navigator
|
import cafe.adriel.voyager.navigator.Navigator
|
||||||
import org.jetbrains.compose.ui.tooling.preview.Preview
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
import tab.ENumberList
|
import tab.list.ListMain
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@Preview
|
@Preview
|
||||||
fun App() {
|
fun App() {
|
||||||
MaterialTheme {
|
MaterialTheme {
|
||||||
AppScaffold()
|
Navigator(ListMain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
|
||||||
fun AppScaffold() {
|
|
||||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
|
||||||
|
|
||||||
Scaffold(
|
|
||||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
|
||||||
topBar = {
|
|
||||||
TopBar(scrollBehavior)
|
|
||||||
}
|
|
||||||
) { innerPadding ->
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(innerPadding)
|
|
||||||
) {
|
|
||||||
Navigator(ENumberList())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
|
||||||
fun TopBar(
|
|
||||||
scrollBehavior: TopAppBarScrollBehavior
|
|
||||||
) {
|
|
||||||
|
|
||||||
CenterAlignedTopAppBar(
|
|
||||||
title = {
|
|
||||||
Text(
|
|
||||||
text = "Vegan E Numbers",
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
navigationIcon = {
|
|
||||||
IconButton(
|
|
||||||
onClick = {/* TODO Implement Navigation Drawer */}
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Filled.Menu,
|
|
||||||
contentDescription = "Navigation Menu",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions = {
|
|
||||||
IconButton(
|
|
||||||
onClick = {/* TODO Implement Search Function */}
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Filled.Search,
|
|
||||||
contentDescription = "Search for E Number",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
class Greeting {
|
|
||||||
private val platform = getPlatform()
|
|
||||||
|
|
||||||
fun greet(): String {
|
|
||||||
return "Hello, ${platform.name}!"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
interface Platform {
|
|
||||||
val name: String
|
|
||||||
}
|
|
||||||
|
|
||||||
expect fun getPlatform(): Platform
|
|
51
composeApp/src/commonMain/kotlin/component/TopBar.kt
Normal file
51
composeApp/src/commonMain/kotlin/component/TopBar.kt
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package component
|
||||||
|
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Menu
|
||||||
|
import androidx.compose.material.icons.filled.Search
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun TopBar(
|
||||||
|
scrollBehavior: TopAppBarScrollBehavior,
|
||||||
|
searchActive: MutableState<Boolean>
|
||||||
|
) {
|
||||||
|
|
||||||
|
CenterAlignedTopAppBar(
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
text = "Vegan E Numbers",
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(
|
||||||
|
onClick = {/* TODO Implement Navigation Drawer */}
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Menu,
|
||||||
|
contentDescription = "Navigation Menu",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions = {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
println("Clicked on Search")
|
||||||
|
searchActive.value = true
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Search,
|
||||||
|
contentDescription = "Search for E Number",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scrollBehavior = scrollBehavior,
|
||||||
|
)
|
||||||
|
}
|
42
composeApp/src/commonMain/kotlin/tab/LoadingScreen.kt
Normal file
42
composeApp/src/commonMain/kotlin/tab/LoadingScreen.kt
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package tab
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import cafe.adriel.voyager.core.screen.Screen
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loading screen for use when using a ScreenModel in a loading state.
|
||||||
|
* Includes a CircularProgressIndicator with text below: "Loading *loadingTitle*"
|
||||||
|
*
|
||||||
|
* @param loadingTitle `String` of the page that is being loaded.
|
||||||
|
*/
|
||||||
|
class LoadingScreen (private val loadingTitle: String) : Screen {
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun Content() {
|
||||||
|
Column (
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.fillMaxHeight(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
) {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
modifier = Modifier.width(64.dp),
|
||||||
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
|
trackColor = MaterialTheme.colorScheme.surfaceVariant
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(Modifier.size(64.dp))
|
||||||
|
|
||||||
|
Text("Loading $loadingTitle", style = MaterialTheme.typography.displaySmall )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package tab
|
package tab.list
|
||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
@ -14,49 +14,17 @@ import androidx.compose.material.icons.outlined.Info
|
|||||||
import androidx.compose.material.icons.outlined.Warning
|
import androidx.compose.material.icons.outlined.Warning
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.mutableStateListOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import cafe.adriel.voyager.core.screen.Screen
|
import cafe.adriel.voyager.core.screen.Screen
|
||||||
import data.EGroup
|
import data.EGroup
|
||||||
import data.ENumber
|
import data.ENumber
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import org.jetbrains.compose.resources.ExperimentalResourceApi
|
|
||||||
import veganenumbers.composeapp.generated.resources.Res.readBytes
|
|
||||||
|
|
||||||
class ENumberList : Screen {
|
class ENumberList(private val eNumbers: List<EGroup>) : Screen {
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads JSON file containing all e numbers
|
|
||||||
* @return List of grouped E Numbers in `EGroup` type
|
|
||||||
*/
|
|
||||||
@OptIn(ExperimentalResourceApi::class)
|
|
||||||
private suspend fun getENumbers(): List<EGroup> {
|
|
||||||
val bytes = readBytes("files/enumbers.json")
|
|
||||||
|
|
||||||
println("Loading")
|
|
||||||
|
|
||||||
val eNumbers = Json.decodeFromString<List<EGroup>>(bytes.decodeToString())
|
|
||||||
|
|
||||||
println("Loaded")
|
|
||||||
|
|
||||||
return eNumbers
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
val eNumbers = remember {
|
|
||||||
mutableStateListOf<EGroup>()
|
|
||||||
}
|
|
||||||
println("Starting")
|
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
eNumbers.addAll(getENumbers())
|
|
||||||
}
|
|
||||||
|
|
||||||
LazyColumn(contentPadding = PaddingValues(6.dp)) {
|
LazyColumn(contentPadding = PaddingValues(6.dp)) {
|
||||||
eNumbers.forEach { eGroup ->
|
eNumbers.forEach { eGroup ->
|
||||||
stickyHeader {
|
stickyHeader {
|
123
composeApp/src/commonMain/kotlin/tab/list/ListMain.kt
Normal file
123
composeApp/src/commonMain/kotlin/tab/list/ListMain.kt
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package tab.list
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
import androidx.compose.ui.semantics.semantics
|
||||||
|
import androidx.compose.ui.semantics.traversalIndex
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import cafe.adriel.voyager.core.model.rememberNavigatorScreenModel
|
||||||
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
import cafe.adriel.voyager.navigator.tab.Tab
|
||||||
|
import cafe.adriel.voyager.navigator.tab.TabOptions
|
||||||
|
import component.TopBar
|
||||||
|
import tab.LoadingScreen
|
||||||
|
|
||||||
|
object ListMain : Tab {
|
||||||
|
override val options: TabOptions
|
||||||
|
@Composable
|
||||||
|
get() {
|
||||||
|
val title = "E Numbers List"
|
||||||
|
|
||||||
|
return remember {
|
||||||
|
TabOptions(
|
||||||
|
index = 0u,
|
||||||
|
title = title
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
override fun Content() {
|
||||||
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
val screenModel = navigator.rememberNavigatorScreenModel { ListScreenModel() }
|
||||||
|
val state by screenModel.state.collectAsState()
|
||||||
|
|
||||||
|
val searchActive = rememberSaveable { mutableStateOf(false) }
|
||||||
|
|
||||||
|
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
|
topBar = {
|
||||||
|
if (!searchActive.value) {
|
||||||
|
TopBar(scrollBehavior = scrollBehavior, searchActive = searchActive)
|
||||||
|
} else {
|
||||||
|
Search(searchActive = searchActive)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) { innerPadding ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(innerPadding)
|
||||||
|
) {
|
||||||
|
when (val s = state) {
|
||||||
|
is ListScreenModel.State.Loading -> LoadingScreen("E Numbers").Content()
|
||||||
|
is ListScreenModel.State.Result -> ENumberList(s.eNumbers).Content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(currentCompositeKeyHash) {
|
||||||
|
screenModel.getENumbers()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
private fun Search(searchActive: MutableState<Boolean>) {
|
||||||
|
var text by rememberSaveable { mutableStateOf("") }
|
||||||
|
|
||||||
|
SearchBar(
|
||||||
|
modifier = Modifier
|
||||||
|
.semantics { traversalIndex = 0f },
|
||||||
|
query = text,
|
||||||
|
onQueryChange = { text = it },
|
||||||
|
onSearch = { searchActive.value = false },
|
||||||
|
onActiveChange = { searchActive.value = it },
|
||||||
|
active = searchActive.value,
|
||||||
|
leadingIcon = {
|
||||||
|
IconButton(onClick = { searchActive.value = false }) {
|
||||||
|
Icon(Icons.AutoMirrored.Filled.ArrowBack, "Exit Search")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trailingIcon = {
|
||||||
|
IconButton(onClick = { text = "" }) {
|
||||||
|
Icon(imageVector = Icons.Filled.Clear, contentDescription = "Clear Search")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Column(Modifier.verticalScroll(rememberScrollState())) {
|
||||||
|
repeat(4) { idx ->
|
||||||
|
val resultText = "Suggestion $idx"
|
||||||
|
ListItem(
|
||||||
|
headlineContent = { Text(resultText) },
|
||||||
|
supportingContent = { Text("Additional info") },
|
||||||
|
leadingContent = { Icon(Icons.Filled.Star, contentDescription = null) },
|
||||||
|
colors = ListItemDefaults.colors(containerColor = Color.Transparent),
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable {
|
||||||
|
text = resultText
|
||||||
|
searchActive.value = false
|
||||||
|
}
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp, vertical = 4.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
composeApp/src/commonMain/kotlin/tab/list/ListScreenModel.kt
Normal file
34
composeApp/src/commonMain/kotlin/tab/list/ListScreenModel.kt
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package tab.list
|
||||||
|
|
||||||
|
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||||
|
import data.EGroup
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import org.jetbrains.compose.resources.ExperimentalResourceApi
|
||||||
|
import veganenumbers.composeapp.generated.resources.Res.readBytes
|
||||||
|
|
||||||
|
class ListScreenModel : StateScreenModel<ListScreenModel.State>(State.Loading) {
|
||||||
|
sealed class State {
|
||||||
|
object Loading : State()
|
||||||
|
data class Result(val eNumbers: List<EGroup>) : State()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads JSON file containing all e numbers
|
||||||
|
* @return List of grouped E Numbers in `EGroup` type
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalResourceApi::class)
|
||||||
|
suspend fun getENumbers() {
|
||||||
|
coroutineScope {
|
||||||
|
launch {
|
||||||
|
mutableState.value = State.Loading
|
||||||
|
|
||||||
|
val bytes = readBytes("files/enumbers.json")
|
||||||
|
val eNumbers = Json.decodeFromString<List<EGroup>>(bytes.decodeToString())
|
||||||
|
|
||||||
|
mutableState.value = State.Result(eNumbers = eNumbers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,15 +13,19 @@ androidx-material3 = "1.6.11"
|
|||||||
androidx-test-junit = "1.1.5"
|
androidx-test-junit = "1.1.5"
|
||||||
compose-plugin = "1.6.10"
|
compose-plugin = "1.6.10"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
|
koin-bom = "3.5.6"
|
||||||
kotlin = "2.0.0"
|
kotlin = "2.0.0"
|
||||||
kotlinx = "1.7.0"
|
kotlinx-serialization = "1.7.0"
|
||||||
|
kotlinx-coroutines = "1.9.0-RC"
|
||||||
material3Android = "1.2.1"
|
material3Android = "1.2.1"
|
||||||
voyager = "1.1.0-beta02"
|
voyager = "1.1.0-beta02"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
|
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
|
||||||
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
|
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
|
||||||
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx"}
|
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization"}
|
||||||
|
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
|
||||||
|
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" }
|
||||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-ktx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-ktx" }
|
||||||
androidx-test-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-junit" }
|
androidx-test-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-junit" }
|
||||||
@ -33,8 +37,16 @@ androidx-constraintlayout = { group = "androidx.constraintlayout", name = "const
|
|||||||
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" }
|
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" }
|
||||||
androidx-material3-android = { group = "androidx.compose.material3", name = "material3-android", version.ref = "material3Android" }
|
androidx-material3-android = { group = "androidx.compose.material3", name = "material3-android", version.ref = "material3Android" }
|
||||||
|
|
||||||
|
# Koin
|
||||||
|
koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koin-bom" }
|
||||||
|
koin-core = { module = "io.insert-koin:koin-core" }
|
||||||
|
koin-compose = { module = "io.insert-koin:koin-compose" }
|
||||||
|
|
||||||
# Voyager
|
# Voyager
|
||||||
voyager-navigator = { group = "cafe.adriel.voyager", name = "voyager-navigator", version.ref = "voyager" }
|
voyager-navigator = { group = "cafe.adriel.voyager", name = "voyager-navigator", version.ref = "voyager" }
|
||||||
|
voyager-tab = { group = "cafe.adriel.voyager", name = "voyager-tab-navigator", version.ref = "voyager" }
|
||||||
|
voyager-screenmodel = { group = "cafe.adriel.voyager", name = "voyager-screenmodel", version.ref = "voyager" }
|
||||||
|
voyager-koin = { group = "cafe.adriel.voyager", name = "voyager-koin", version.ref = "voyager" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user