From a69cd0b110724d8f46b7e0ad6c1006ace5d6f5fd Mon Sep 17 00:00:00 2001 From: Fabian Wolter Date: Sun, 1 Feb 2026 18:14:18 +0100 Subject: [PATCH] first design draft --- app/build.gradle.kts | 2 + .../cloudsync/ExampleInstrumentedTest.kt | 49 ------ .../com/fabisahne/cloudsync/MainActivity.kt | 13 +- .../com/fabisahne/cloudsync/ui/SyncApp.kt | 2 + .../fabisahne/cloudsync/ui/SyncAppState.kt | 1 + .../ui/navigation/NavigationState.kt | 71 --------- .../cloudsync/ui/navigation/Navigator.kt | 45 ------ .../cloudsync/ui/navigation/navigation.kt | 22 +++ .../cloudsync/ui/screens/FolderPairScreen.kt | 32 ++++ .../cloudsync/ui/screens/HomeScreen.kt | 62 ++++++++ .../fabisahne/cloudsync/ui/tabs/AccountTab.kt | 33 ++++ .../cloudsync/ui/tabs/FolderPairTab.kt | 59 ++++++++ .../fabisahne/cloudsync/ui/tabs/HistoryTab.kt | 141 ++++++++++++++++++ .../cloudsync/ui/tabs/SettingsTab.kt | 33 ++++ .../com/fabisahne/cloudsync/ui/theme/Color.kt | 11 -- .../com/fabisahne/cloudsync/ui/theme/Theme.kt | 22 +-- .../fabisahne/cloudsync/ExampleUnitTest.kt | 28 ---- gradle/libs.versions.toml | 10 +- 18 files changed, 410 insertions(+), 226 deletions(-) delete mode 100644 app/src/androidTest/java/com/fabisahne/cloudsync/ExampleInstrumentedTest.kt create mode 100644 app/src/main/java/com/fabisahne/cloudsync/ui/SyncApp.kt create mode 100644 app/src/main/java/com/fabisahne/cloudsync/ui/SyncAppState.kt delete mode 100644 app/src/main/java/com/fabisahne/cloudsync/ui/navigation/NavigationState.kt delete mode 100644 app/src/main/java/com/fabisahne/cloudsync/ui/navigation/Navigator.kt create mode 100644 app/src/main/java/com/fabisahne/cloudsync/ui/navigation/navigation.kt create mode 100644 app/src/main/java/com/fabisahne/cloudsync/ui/screens/FolderPairScreen.kt create mode 100644 app/src/main/java/com/fabisahne/cloudsync/ui/screens/HomeScreen.kt create mode 100644 app/src/main/java/com/fabisahne/cloudsync/ui/tabs/AccountTab.kt create mode 100644 app/src/main/java/com/fabisahne/cloudsync/ui/tabs/FolderPairTab.kt create mode 100644 app/src/main/java/com/fabisahne/cloudsync/ui/tabs/HistoryTab.kt create mode 100644 app/src/main/java/com/fabisahne/cloudsync/ui/tabs/SettingsTab.kt delete mode 100644 app/src/main/java/com/fabisahne/cloudsync/ui/theme/Color.kt delete mode 100644 app/src/test/java/com/fabisahne/cloudsync/ExampleUnitTest.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9394ac0..22c0199 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -61,4 +61,6 @@ dependencies { implementation(libs.androidx.lifecycle.viewmodel.navigation3) implementation(libs.androidx.material3.adaptive.navigation3) implementation(libs.kotlinx.serialization.core) + + implementation(libs.bundles.voyager) } \ No newline at end of file diff --git a/app/src/androidTest/java/com/fabisahne/cloudsync/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/fabisahne/cloudsync/ExampleInstrumentedTest.kt deleted file mode 100644 index ded8df8..0000000 --- a/app/src/androidTest/java/com/fabisahne/cloudsync/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.fabisahne.cloudsync - -import androidx.compose.ui.test.junit4.createComposeRule -import androidx.compose.ui.test.onNodeWithText -import androidx.compose.ui.test.performTextInput -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.fabisahne.cloudsync.ui.theme.CloudSyncTheme - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* -import org.junit.Rule -import java.text.NumberFormat - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.fabisahne.cloudsync", appContext.packageName) - } - - @get:Rule - val composeTestRule = createComposeRule() - - @Test - fun calculateTip_20PercentTip() { - composeTestRule.setContent { - CloudSyncTheme { - TipTimeLayout() - } - } - composeTestRule.onNodeWithText("Bill Amount") - .performTextInput("10") - - val expected = NumberFormat.getCurrencyInstance().format(1.5) - composeTestRule.onNodeWithText("Tip Amount: $expected").assertExists( - "No node with this text was found." - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/fabisahne/cloudsync/MainActivity.kt b/app/src/main/java/com/fabisahne/cloudsync/MainActivity.kt index 2b4219b..deca6f9 100644 --- a/app/src/main/java/com/fabisahne/cloudsync/MainActivity.kt +++ b/app/src/main/java/com/fabisahne/cloudsync/MainActivity.kt @@ -4,23 +4,22 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Home -import androidx.compose.material3.Icon +import androidx.compose.material3.ExperimentalMaterial3Api +import cafe.adriel.voyager.navigator.Navigator +import com.fabisahne.cloudsync.ui.screens.HomeScreen import com.fabisahne.cloudsync.ui.theme.CloudSyncTheme class MainActivity : ComponentActivity() { + @OptIn(ExperimentalMaterial3Api::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { CloudSyncTheme { - Icon( - Icons.Filled.Home, - contentDescription = "asdf", - ) + Navigator(HomeScreen) } } } } + diff --git a/app/src/main/java/com/fabisahne/cloudsync/ui/SyncApp.kt b/app/src/main/java/com/fabisahne/cloudsync/ui/SyncApp.kt new file mode 100644 index 0000000..3075556 --- /dev/null +++ b/app/src/main/java/com/fabisahne/cloudsync/ui/SyncApp.kt @@ -0,0 +1,2 @@ +package com.fabisahne.cloudsync.ui + diff --git a/app/src/main/java/com/fabisahne/cloudsync/ui/SyncAppState.kt b/app/src/main/java/com/fabisahne/cloudsync/ui/SyncAppState.kt new file mode 100644 index 0000000..d4351a4 --- /dev/null +++ b/app/src/main/java/com/fabisahne/cloudsync/ui/SyncAppState.kt @@ -0,0 +1 @@ +package com.fabisahne.cloudsync.ui diff --git a/app/src/main/java/com/fabisahne/cloudsync/ui/navigation/NavigationState.kt b/app/src/main/java/com/fabisahne/cloudsync/ui/navigation/NavigationState.kt deleted file mode 100644 index 1129f22..0000000 --- a/app/src/main/java/com/fabisahne/cloudsync/ui/navigation/NavigationState.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.fabisahne.cloudsync.ui.navigation - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.runtime.snapshots.SnapshotStateList -import androidx.compose.runtime.toMutableStateList -import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator -import androidx.navigation3.runtime.NavBackStack -import androidx.navigation3.runtime.NavEntry -import androidx.navigation3.runtime.NavEntryDecorator -import androidx.navigation3.runtime.NavKey -import androidx.navigation3.runtime.rememberDecoratedNavEntries -import androidx.navigation3.runtime.rememberNavBackStack -import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator - -@Composable -fun rememberNavigationState( - startKey: NavKey, - topLevelKeys: Set, -): NavigationState { - val topLevelStack = rememberNavBackStack(startKey) - val subStacks = topLevelKeys.associateWith { key -> rememberNavBackStack(key) } - - return remember(startKey, topLevelKeys) { - NavigationState( - startKey = startKey, - topLevelStack = topLevelStack, - subStacks = subStacks - ) - } -} - -class NavigationState( - val startKey: NavKey, - val topLevelStack: NavBackStack, - val subStacks: Map> -) { - val currentTopLevelKey: NavKey by derivedStateOf { topLevelStack.last() } - - val topLevelKeys - get() = subStacks.keys - - val currentSubStack: NavBackStack - get() = subStacks[currentTopLevelKey] - ?: error("Sub stack for $currentTopLevelKey does not exist") - - val currentKey: NavKey by derivedStateOf { currentSubStack.last() } -} - -@Composable -fun NavigationState.toEntries( - entryProvider: (NavKey) -> NavEntry, -): SnapshotStateList> { - val decoratedEntries = subStacks.mapValues { (_, stack) -> - val decorators = listOf>( - rememberSaveableStateHolderNavEntryDecorator(), - rememberViewModelStoreNavEntryDecorator(), - ) - rememberDecoratedNavEntries( - backStack = stack, - entryDecorators = decorators, - entryProvider = entryProvider, - ) - } - - return topLevelStack - .flatMap { decoratedEntries[it] ?: emptyList() } - .toMutableStateList() -} \ No newline at end of file diff --git a/app/src/main/java/com/fabisahne/cloudsync/ui/navigation/Navigator.kt b/app/src/main/java/com/fabisahne/cloudsync/ui/navigation/Navigator.kt deleted file mode 100644 index cbfdc87..0000000 --- a/app/src/main/java/com/fabisahne/cloudsync/ui/navigation/Navigator.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.fabisahne.cloudsync.ui.navigation - -import androidx.navigation3.runtime.NavKey - -class Navigator(val state: NavigationState) { - fun navigate(key: NavKey) { - when (key) { - state.currentTopLevelKey -> clearSubStack() - in state.topLevelKeys -> goToTopLevel(key) - else -> goToKey(key) - } - } - - fun goBack() { - when (state.currentKey) { - state.startKey -> error("You cannot go back from the start route") - state.currentTopLevelKey -> state.topLevelStack.removeLastOrNull() - else -> state.currentSubStack.removeLastOrNull() - } - } - - private fun goToKey(key: NavKey) { - state.currentSubStack.apply { - remove(key) - add(key) - } - } - - private fun goToTopLevel(key: NavKey) { - state.topLevelStack.apply { - if (key == state.startKey) { - clear() - } else { - remove(key) - } - add(key) - } - } - - private fun clearSubStack() { - state.currentSubStack.run { - if (size > 1) subList(1, size).clear() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/fabisahne/cloudsync/ui/navigation/navigation.kt b/app/src/main/java/com/fabisahne/cloudsync/ui/navigation/navigation.kt new file mode 100644 index 0000000..4562eb8 --- /dev/null +++ b/app/src/main/java/com/fabisahne/cloudsync/ui/navigation/navigation.kt @@ -0,0 +1,22 @@ +package com.fabisahne.cloudsync.ui.navigation + +import androidx.compose.foundation.layout.RowScope +import androidx.compose.material3.Icon +import androidx.compose.material3.NavigationBarItem +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.navigator.tab.LocalTabNavigator +import cafe.adriel.voyager.navigator.tab.Tab + + +@Composable +fun RowScope.TabNavigationItem(tab: Tab) { + val tabNavigator = LocalTabNavigator.current + + NavigationBarItem( + selected = tabNavigator.current.key == tab.key, + onClick = { tabNavigator.current = tab }, + label = { Text(tab.options.title) }, + icon = { Icon(painter = tab.options.icon!!, contentDescription = tab.options.title) } + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/fabisahne/cloudsync/ui/screens/FolderPairScreen.kt b/app/src/main/java/com/fabisahne/cloudsync/ui/screens/FolderPairScreen.kt new file mode 100644 index 0000000..bd8efc0 --- /dev/null +++ b/app/src/main/java/com/fabisahne/cloudsync/ui/screens/FolderPairScreen.kt @@ -0,0 +1,32 @@ +package com.fabisahne.cloudsync.ui.screens + +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import cafe.adriel.voyager.core.screen.Screen + +data class FolderPairScreen( + val id: Long +) : Screen { + @OptIn(ExperimentalMaterial3Api::class) + @Composable + override fun Content() { + Scaffold( + topBar = { + TopAppBar( + title = { Text("Folder Pair") } + ) + }, + content = { contentPadding -> + Surface(modifier = Modifier.padding(contentPadding)) { + Text("ASDF: $id") + } + } + ) + } +} diff --git a/app/src/main/java/com/fabisahne/cloudsync/ui/screens/HomeScreen.kt b/app/src/main/java/com/fabisahne/cloudsync/ui/screens/HomeScreen.kt new file mode 100644 index 0000000..ef06f3e --- /dev/null +++ b/app/src/main/java/com/fabisahne/cloudsync/ui/screens/HomeScreen.kt @@ -0,0 +1,62 @@ +package com.fabisahne.cloudsync.ui.screens + +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.NavigationBar +import androidx.compose.material3.NavigationBarDefaults +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow +import cafe.adriel.voyager.navigator.tab.CurrentTab +import cafe.adriel.voyager.navigator.tab.TabNavigator +import com.fabisahne.cloudsync.ui.navigation.TabNavigationItem +import com.fabisahne.cloudsync.ui.tabs.AccountTab +import com.fabisahne.cloudsync.ui.tabs.FolderPairTab +import com.fabisahne.cloudsync.ui.tabs.HistoryTab +import com.fabisahne.cloudsync.ui.tabs.SettingsTab + + +object HomeScreen : Screen { + private val TABS = listOf( + HistoryTab, + FolderPairTab, + AccountTab, + SettingsTab, + ) + + @OptIn(ExperimentalMaterial3Api::class) + @Composable + override fun Content() { + val navigator = LocalNavigator.currentOrThrow + + TabNavigator( + HistoryTab + ) { tabNavigator -> + Scaffold( + topBar = { + TopAppBar( + title = { Text(text = tabNavigator.current.options.title) } + ) + }, + content = { padding -> + Surface(modifier = Modifier.padding(padding)) { + CurrentTab() + } + }, + bottomBar = { + NavigationBar(windowInsets = NavigationBarDefaults.windowInsets) { + TABS.forEach { + TabNavigationItem(it) + } + } + } + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fabisahne/cloudsync/ui/tabs/AccountTab.kt b/app/src/main/java/com/fabisahne/cloudsync/ui/tabs/AccountTab.kt new file mode 100644 index 0000000..17b0aa7 --- /dev/null +++ b/app/src/main/java/com/fabisahne/cloudsync/ui/tabs/AccountTab.kt @@ -0,0 +1,33 @@ +package com.fabisahne.cloudsync.ui.tabs + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.AccountBox +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 + + +object AccountTab : Tab { + override val options: TabOptions + @Composable + get() { + val title = "Accounts" + val icon = rememberVectorPainter(Icons.Default.AccountBox) + + return remember { + TabOptions( + index = 2u, + title = title, + icon = icon + ) + } + } + + @Composable + override fun Content() { + Text("Cloud Accounts") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fabisahne/cloudsync/ui/tabs/FolderPairTab.kt b/app/src/main/java/com/fabisahne/cloudsync/ui/tabs/FolderPairTab.kt new file mode 100644 index 0000000..34bf629 --- /dev/null +++ b/app/src/main/java/com/fabisahne/cloudsync/ui/tabs/FolderPairTab.kt @@ -0,0 +1,59 @@ +package com.fabisahne.cloudsync.ui.tabs + +import androidx.compose.foundation.layout.absoluteOffset +import androidx.compose.foundation.layout.absolutePadding +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.FolderCopy +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon +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.vector.rememberVectorPainter +import cafe.adriel.voyager.navigator.tab.Tab +import cafe.adriel.voyager.navigator.tab.TabOptions + +object FolderPairTab : Tab { + override val options: TabOptions + @Composable + get() { + val title = "Folder Pairs" + val icon = rememberVectorPainter(Icons.Default.FolderCopy) + + return remember { + TabOptions( + index = 1u, + title = title, + icon = icon + ) + } + } + + @Composable + override fun Content() { +// Text("Folder Pairs") +// FloatingActionButton( +// +// modifier = Modifier.absolute(), +// onClick = {} +// ) { +// Icon(Icons.Default.Add, "Add Pair") +// } + + Scaffold( + floatingActionButton = { + FloatingActionButton( + onClick = {} + ) { + Icon(Icons.Default.Add, "Add Pair") + } + } + ) { paddingValues -> + Text("Pairs here", Modifier.padding(paddingValues)) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fabisahne/cloudsync/ui/tabs/HistoryTab.kt b/app/src/main/java/com/fabisahne/cloudsync/ui/tabs/HistoryTab.kt new file mode 100644 index 0000000..5d3a6dc --- /dev/null +++ b/app/src/main/java/com/fabisahne/cloudsync/ui/tabs/HistoryTab.kt @@ -0,0 +1,141 @@ +package com.fabisahne.cloudsync.ui.tabs + +import androidx.compose.foundation.layout.Arrangement +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.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.History +import androidx.compose.material.icons.outlined.History +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +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.graphics.vector.rememberVectorPainter +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow +import cafe.adriel.voyager.navigator.tab.LocalTabNavigator +import cafe.adriel.voyager.navigator.tab.Tab +import cafe.adriel.voyager.navigator.tab.TabOptions +import com.fabisahne.cloudsync.ui.screens.FolderPairScreen +import com.fabisahne.cloudsync.ui.theme.CloudSyncTheme +import java.time.LocalDate + +object HistoryTab : Tab { + override val options: TabOptions + @Composable + get() { + val isSelected = LocalTabNavigator.current.current.key == key + val icon = if (isSelected) + Icons.Outlined.History + else + Icons.Default.History + return TabOptions( + index = 0u, + title = "History", + icon = rememberVectorPainter(icon), + ) + } + + @Composable + override fun Content() { + val navigator = LocalNavigator.currentOrThrow.parent!! + + LazyColumn( + contentPadding = PaddingValues(10.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + items(5) { index -> + HistoryItem( + "Account", + "Folder Pair $index", + LocalDate.now().minusDays(index.toLong()), + isError = index % 2 == 0, + onClick = { navigator.push(FolderPairScreen(index.toLong())) } + ) + } + } + } +} + +@Composable +fun HistoryItem( + account: String, + pairName: String, + date: LocalDate, + isError: Boolean = false, + onClick: () -> Unit = {}, +) { + val (containerColor, contentColor) = if (isError) + MaterialTheme.colorScheme.errorContainer to MaterialTheme.colorScheme.onErrorContainer + else + CardDefaults.cardColors().containerColor to CardDefaults.cardColors().contentColor + + Card( + onClick = onClick, + modifier = Modifier + .fillMaxWidth() + .height(90.dp), + colors = CardDefaults.cardColors( + containerColor = containerColor, + contentColor = contentColor + ), + ) { + Column( + modifier = Modifier + .padding(16.dp) + .fillMaxSize(), + verticalArrangement = Arrangement.SpaceBetween + ) { + Text("$account | $pairName", style = MaterialTheme.typography.titleMedium) + Row( + modifier = Modifier.fillMaxSize(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.Bottom + ) { + Text( + if (isError) "Error" else "Success", + style = MaterialTheme.typography.bodyMedium + ) + Text(date.toString(), style = MaterialTheme.typography.bodyMedium) + } + } + + } +} + +@Preview +@Composable +fun HistoryCardPreviewLight() { + CloudSyncTheme { + HistoryItem( + "Account", + "Folder Pair", + LocalDate.now(), + ) + } +} + +@Preview +@Composable +fun HistoryCardPreviewDark() { + CloudSyncTheme( + darkTheme = true + ) { + HistoryItem( + "Account", + "Folder Pair", + LocalDate.now() + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fabisahne/cloudsync/ui/tabs/SettingsTab.kt b/app/src/main/java/com/fabisahne/cloudsync/ui/tabs/SettingsTab.kt new file mode 100644 index 0000000..f4c7e06 --- /dev/null +++ b/app/src/main/java/com/fabisahne/cloudsync/ui/tabs/SettingsTab.kt @@ -0,0 +1,33 @@ +package com.fabisahne.cloudsync.ui.tabs + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.AccountBox +import androidx.compose.material.icons.filled.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 + +object SettingsTab : Tab { + override val options: TabOptions + @Composable + get() { + val title = "Settings" + val icon = rememberVectorPainter(Icons.Default.Settings) + + return remember { + TabOptions( + index = 2u, + title = title, + icon = icon + ) + } + } + + @Composable + override fun Content() { + Text("Settings") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fabisahne/cloudsync/ui/theme/Color.kt b/app/src/main/java/com/fabisahne/cloudsync/ui/theme/Color.kt deleted file mode 100644 index 57db38a..0000000 --- a/app/src/main/java/com/fabisahne/cloudsync/ui/theme/Color.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.fabisahne.cloudsync.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) \ No newline at end of file diff --git a/app/src/main/java/com/fabisahne/cloudsync/ui/theme/Theme.kt b/app/src/main/java/com/fabisahne/cloudsync/ui/theme/Theme.kt index 17338cf..afd3d80 100644 --- a/app/src/main/java/com/fabisahne/cloudsync/ui/theme/Theme.kt +++ b/app/src/main/java/com/fabisahne/cloudsync/ui/theme/Theme.kt @@ -1,30 +1,24 @@ package com.fabisahne.cloudsync.ui.theme +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.runtime.Composable import androidx.compose.ui.platform.LocalContext -private val DarkColorScheme = darkColorScheme( - primary = Purple80, - secondary = PurpleGrey80, - tertiary = Pink80 -) @Composable fun CloudSyncTheme( - dynamicColor: Boolean = true, + darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { - val colorScheme = when { - dynamicColor -> { - val context = LocalContext.current - dynamicDarkColorScheme(context) - } + val context = LocalContext.current - else -> DarkColorScheme - } + val colorScheme = if (darkTheme) + dynamicDarkColorScheme(context) + else + dynamicLightColorScheme(context) MaterialTheme( colorScheme = colorScheme, diff --git a/app/src/test/java/com/fabisahne/cloudsync/ExampleUnitTest.kt b/app/src/test/java/com/fabisahne/cloudsync/ExampleUnitTest.kt deleted file mode 100644 index 32a53e6..0000000 --- a/app/src/test/java/com/fabisahne/cloudsync/ExampleUnitTest.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.fabisahne.cloudsync - -import org.junit.Test - -import org.junit.Assert.* -import java.text.NumberFormat - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } - - @Test - fun calculateTip_20Percent() { - val amount = 10.00 - val tipPercent = 20.00 - - val expected = NumberFormat.getCurrencyInstance().format(2) - - assertEquals(expected, calculateTip(amount, tipPercent)) - } -} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d23570e..511b5f0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ lifecycleRuntimeKtx = "2.10.0" activityCompose = "1.12.2" kotlin = "2.0.21" composeBom = "2024.09.00" -compileSdk = "36" +voyager = "1.1.0-beta03" nav3Core = "1.0.0" lifeCycleViewmodelNav3 = "2.10.0" @@ -40,7 +40,15 @@ androidx-lifecycle-viewmodel-navigation3 = { module = "androidx.lifecycle:lifecy kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinxSerializationCore" } androidx-material3-adaptive-navigation3 = { group = "androidx.compose.material3.adaptive", name = "adaptive-navigation3", version.ref = "material3AdaptiveNav3" } +voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } +voyager-screenmodel = { module = "cafe.adriel.voyager:voyager-screenmodel", version.ref = "voyager" } +voyager-tab-navigator = { module = "cafe.adriel.voyager:voyager-tab-navigator", version.ref = "voyager" } +voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" } + [plugins] android-application = { id = "com.android.application", version.ref = "agp" } kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } jetbrains-kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlinSerialization" } + +[bundles] +voyager = ["voyager-navigator", "voyager-screenmodel", "voyager-tab-navigator", "voyager-transitions"] \ No newline at end of file