feat(connector): add Navigation

This commit is contained in:
Anthony 2024-04-01 13:24:13 +02:00
parent 32c9be2eee
commit ddb6c94d5e
9 changed files with 308 additions and 78 deletions

View File

@ -8,6 +8,7 @@ plugins {
kotlin { kotlin {
jvm("desktop") jvm("desktop")
jvmToolchain(21)
sourceSets { sourceSets {
val desktopMain by getting val desktopMain by getting
@ -24,6 +25,34 @@ kotlin {
desktopMain.dependencies { desktopMain.dependencies {
implementation(compose.desktop.currentOs) implementation(compose.desktop.currentOs)
implementation("org.jetbrains.compose.material3:material3-desktop:1.6.1") implementation("org.jetbrains.compose.material3:material3-desktop:1.6.1")
// Voyager - Navigation
val voyagerVersion = "1.0.0"
// Multiplatform
// Navigator
implementation("cafe.adriel.voyager:voyager-navigator:$voyagerVersion")
// Screen Model
implementation("cafe.adriel.voyager:voyager-screenmodel:$voyagerVersion")
// BottomSheetNavigator
implementation("cafe.adriel.voyager:voyager-bottom-sheet-navigator:$voyagerVersion")
// TabNavigator
implementation("cafe.adriel.voyager:voyager-tab-navigator:$voyagerVersion")
// Transitions
implementation("cafe.adriel.voyager:voyager-transitions:$voyagerVersion")
// Desktop + Android
// Kodein integration
implementation("cafe.adriel.voyager:voyager-kodein:$voyagerVersion")
// RxJava integration
implementation("cafe.adriel.voyager:voyager-rxjava:$voyagerVersion")
} }
} }
} }

View File

@ -0,0 +1,36 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabOptions
import connector.composeapp.generated.resources.Res
import connector.composeapp.generated.resources.info_24px
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.painterResource
class About : Tab {
@OptIn(ExperimentalResourceApi::class)
override val options: TabOptions
@Composable
get() {
val title = "About"
val icon = painterResource(Res.drawable.info_24px)
return remember {
TabOptions(
index = 0u,
title = title,
icon = icon,
)
}
}
@Composable
override fun Content() {
Column {
Text("About")
}
}
}

View File

@ -1,27 +1,22 @@
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Menu import androidx.compose.material.icons.filled.Menu
import androidx.compose.material.icons.outlined.Edit
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import connector.composeapp.generated.resources.* import cafe.adriel.voyager.navigator.tab.CurrentTab
import cafe.adriel.voyager.navigator.tab.LocalTabNavigator
import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabNavigator
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.jetbrains.compose.resources.ExperimentalResourceApi import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.ui.tooling.preview.Preview import org.jetbrains.compose.ui.tooling.preview.Preview
import theme.AppTheme import theme.AppTheme
@ -30,49 +25,35 @@ import theme.AppTheme
@Preview @Preview
fun App() { fun App() {
AppTheme { AppTheme {
var showContent by remember { mutableStateOf(false) } AppScaffold()
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
AppScaffold {
Button(onClick = { showContent = !showContent }) {
Text("Click me!")
}
AnimatedVisibility(showContent) {
val greeting = remember { Greeting().greet() }
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
Image(painterResource(Res.drawable.compose_multiplatform), null)
Text("Compose: $greeting")
}
}
}
}
} }
} }
@Composable @Composable
fun AppScaffold(content: @Composable() () -> Unit) { fun AppScaffold() {
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
TabNavigator(Projects) {
Scaffold( Scaffold(
topBar = { topBar = {
TopBar(drawerState, scope) TopBar(drawerState, scope)
}, },
) { innerPadding -> content = { innerPadding ->
Column( Column(
modifier = Modifier.padding(innerPadding) modifier = Modifier.padding(innerPadding)
) { ) {
NavigationDrawer(drawerState) { NavigationDrawer(drawerState) {
Column( CurrentTab()
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
content()
Text("Test")
} }
} }
} }
)
} }
} }
/** /**
* Component for the bar on top of the screen * Component for the bar on top of the screen
*/ */
@ -128,48 +109,18 @@ fun NavigationDrawer(
ModalDrawerSheet { ModalDrawerSheet {
Column(modifier = Modifier.verticalScroll(rememberScrollState()) ) { Column(modifier = Modifier.verticalScroll(rememberScrollState()) ) {
Text("Project Name...", modifier = Modifier.padding(16.dp)) Text("Project Name...", modifier = Modifier.padding(16.dp))
NavigationDrawerItem( TabNavigationItem(Projects)
label = { Text(text = "Projects") },
icon = { Icon(painterResource(Res.drawable.folder_24px), null) },
selected = false,
onClick = { /* TODO */ },
)
HorizontalDivider() HorizontalDivider()
Text("Tester", modifier = Modifier.padding(16.dp)) Text("Tester", modifier = Modifier.padding(16.dp))
NavigationDrawerItem( TabNavigationItem(Procedures())
label = { Text(text = "Procedures") }, TabNavigationItem(SimulatorTest())
icon = { Icon(imageVector = Icons.Outlined.Edit, null) }, TabNavigationItem(TestResults())
selected = false,
onClick = { /* TODO */ },
)
NavigationDrawerItem(
label = { Text(text = "Simulator Test") },
icon = { Icon(painterResource(Res.drawable.check_box_24px), null) },
selected = false,
onClick = { /* TODO */ },
)
NavigationDrawerItem(
label = { Text(text = "Test Results") },
icon = { Icon(painterResource(Res.drawable.history_24px), null) },
selected = false,
onClick = { /* TODO */ },
)
HorizontalDivider() HorizontalDivider()
Text("Application", modifier = Modifier.padding(16.dp)) Text("Application", modifier = Modifier.padding(16.dp))
NavigationDrawerItem( TabNavigationItem(Settings())
label = { Text(text = "Settings") }, TabNavigationItem(About())
icon = { Icon(imageVector = Icons.Outlined.Settings, null) },
selected = false,
onClick = { /* TODO */ },
)
NavigationDrawerItem(
label = { Text(text = "About") },
icon = { Icon(painterResource(Res.drawable.info_24px), null) },
selected = false,
onClick = { /* TODO */ },
)
} }
} }
} }
@ -177,3 +128,18 @@ fun NavigationDrawer(
content() content()
} }
} }
/**
* Creates button in NavigationDrawer
*/
@Composable
private fun TabNavigationItem(tab: Tab) {
val tabNavigator = LocalTabNavigator.current
NavigationDrawerItem(
label = { Text(tab.options.title) },
icon = { tab.options.icon?.let { Icon(it, null) } },
selected = tabNavigator.current == tab,
onClick = { tabNavigator.current = tab },
)
}

View File

@ -0,0 +1,55 @@
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Edit
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabOptions
import connector.composeapp.generated.resources.Res
import connector.composeapp.generated.resources.compose_multiplatform
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.painterResource
class Procedures : Tab {
override val options: TabOptions
@Composable
get() {
val title = "Procedures"
val icon = rememberVectorPainter(Icons.Outlined.Edit)
return remember {
TabOptions(
index = 1u,
title = title,
icon = icon,
)
}
}
@OptIn(ExperimentalResourceApi::class)
@Composable
override fun Content() {
var showContent by remember { mutableStateOf(false) }
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
Button(onClick = { showContent = !showContent }) {
Text("Click me!")
}
AnimatedVisibility(showContent) {
val greeting = remember { Greeting().greet() }
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
Image(painterResource(Res.drawable.compose_multiplatform), null)
Text("Compose: $greeting")
}
}
}
}
}

View File

@ -0,0 +1,35 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabOptions
import connector.composeapp.generated.resources.Res
import connector.composeapp.generated.resources.folder_24px
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.painterResource
object Projects : Tab {
@OptIn(ExperimentalResourceApi::class)
override val options: TabOptions
@Composable
get() {
val title = "Projects"
val icon = painterResource(Res.drawable.folder_24px)
return remember {
TabOptions(
index = 0u,
title = title,
icon = icon,
)
}
}
@Composable
override fun Content() {
Column {
Text("Projects")
}
}
}

View File

@ -0,0 +1,36 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabOptions
import org.jetbrains.compose.resources.ExperimentalResourceApi
class Settings : Tab {
@OptIn(ExperimentalResourceApi::class)
override val options: TabOptions
@Composable
get() {
val title = "Settings"
val icon = rememberVectorPainter(Icons.Outlined.Settings)
return remember {
TabOptions(
index = 4u,
title = title,
icon = icon,
)
}
}
@Composable
override fun Content() {
Column {
Text("Settings")
}
}
}

View File

@ -0,0 +1,36 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabOptions
import connector.composeapp.generated.resources.Res
import connector.composeapp.generated.resources.check_box_24px
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.painterResource
class SimulatorTest : Tab {
@OptIn(ExperimentalResourceApi::class)
override val options: TabOptions
@Composable
get() {
val title = "Simulator Test"
val icon = painterResource(Res.drawable.check_box_24px)
return remember {
TabOptions(
index = 2u,
title = title,
icon = icon,
)
}
}
@Composable
override fun Content() {
Column {
Text("Simulator Test")
}
}
}

View File

@ -0,0 +1,36 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import cafe.adriel.voyager.navigator.tab.Tab
import cafe.adriel.voyager.navigator.tab.TabOptions
import connector.composeapp.generated.resources.Res
import connector.composeapp.generated.resources.history_24px
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.painterResource
class TestResults : Tab {
@OptIn(ExperimentalResourceApi::class)
override val options: TabOptions
@Composable
get() {
val title = "Test Results"
val icon = painterResource(Res.drawable.history_24px)
return remember {
TabOptions(
index = 3u,
title = title,
icon = icon,
)
}
}
@Composable
override fun Content() {
Column {
Text("Test Results")
}
}
}

View File

@ -6,6 +6,7 @@ plugins {
kotlin { kotlin {
jvm() jvm()
jvmToolchain(21)
sourceSets { sourceSets {
commonMain.dependencies { commonMain.dependencies {