diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts
index af8d140..c2bbdee 100644
--- a/composeApp/build.gradle.kts
+++ b/composeApp/build.gradle.kts
@@ -1,25 +1,31 @@
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
-import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
-import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidApplication)
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.composeCompiler)
+ alias(libs.plugins.sqlDelight)
}
kotlin {
androidTarget {
- @OptIn(ExperimentalKotlinGradlePluginApi::class)
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_11)
+ compilations.all {
+ kotlinOptions {
+ jvmTarget = "21"
+ }
}
}
jvm("desktop")
+
+ sqldelight{
+ databases {
+ create("PolyculeDatabase") {
+ packageName = "com.menagerie.ophelia"
+ }
+ }
+ }
sourceSets {
val desktopMain by getting
@@ -28,6 +34,7 @@ kotlin {
implementation(compose.preview)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.material3.android)
+ implementation(libs.sqldelight.android)
}
commonMain.dependencies {
implementation(compose.runtime)
@@ -43,11 +50,13 @@ kotlin {
implementation("org.jetbrains.androidx.navigation:navigation-compose:2.7.0-alpha07")
api(libs.datastore.preferences)
api(libs.datastore)
+ implementation(libs.sqldelight.coroutines)
}
desktopMain.dependencies {
implementation(compose.desktop.currentOs)
implementation(libs.kotlinx.coroutines.swing)
implementation(libs.androidx.material3.desktop)
+ implementation(libs.sqldelight.jvm)
}
}
}
@@ -74,8 +83,8 @@ android {
}
}
compileOptions {
- sourceCompatibility = JavaVersion.VERSION_11
- targetCompatibility = JavaVersion.VERSION_11
+ sourceCompatibility = JavaVersion.VERSION_21
+ targetCompatibility = JavaVersion.VERSION_21
}
}
dependencies {
diff --git a/composeApp/src/androidMain/kotlin/AndroidAppModule.kt b/composeApp/src/androidMain/kotlin/AndroidAppModule.kt
new file mode 100644
index 0000000..f87ff77
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/AndroidAppModule.kt
@@ -0,0 +1,17 @@
+import android.content.Context
+import com.menagerie.ophelia.AppModule
+import com.menagerie.ophelia.DatabaseDriverFactory
+import com.menagerie.ophelia.PolyculeDatabase
+import com.menagerie.ophelia.data.user.UserDataSource
+
+class AndroidAppModule(
+ private val context: Context,
+) : AppModule {
+ private val db by lazy {
+ PolyculeDatabase(
+ driver = DatabaseDriverFactory(context).create()
+ )
+ }
+
+ override fun provideUserDataSource() = UserDataSource(db)
+}
\ No newline at end of file
diff --git a/composeApp/src/androidMain/kotlin/com/menagerie/ophelia/DatabaseDriverFactory.android.kt b/composeApp/src/androidMain/kotlin/com/menagerie/ophelia/DatabaseDriverFactory.android.kt
new file mode 100644
index 0000000..c6faba3
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/com/menagerie/ophelia/DatabaseDriverFactory.android.kt
@@ -0,0 +1,10 @@
+package com.menagerie.ophelia
+
+import android.content.Context
+import app.cash.sqldelight.db.SqlDriver
+import app.cash.sqldelight.driver.android.AndroidSqliteDriver
+
+actual class DatabaseDriverFactory(private val context: Context) {
+ actual fun create(): SqlDriver =
+ AndroidSqliteDriver(PolyculeDatabase.Schema, context, "POLYCULE_DATABASE")
+}
\ No newline at end of file
diff --git a/composeApp/src/androidMain/kotlin/com/menagerie/ophelia/MainActivity.kt b/composeApp/src/androidMain/kotlin/com/menagerie/ophelia/MainActivity.kt
index a2f00f9..24fe342 100644
--- a/composeApp/src/androidMain/kotlin/com/menagerie/ophelia/MainActivity.kt
+++ b/composeApp/src/androidMain/kotlin/com/menagerie/ophelia/MainActivity.kt
@@ -12,13 +12,12 @@ class MainActivity : ComponentActivity() {
WindowCompat.setDecorFitsSystemWindows(window, false)
-
setContent {
- MainView(
+ MainView(
prefs = remember {
createDataStore(application)
}
- )
+ )
}
}
}
diff --git a/composeApp/src/androidMain/res/values/strings.xml b/composeApp/src/androidMain/res/values/strings.xml
index 69d8175..afc421d 100644
--- a/composeApp/src/androidMain/res/values/strings.xml
+++ b/composeApp/src/androidMain/res/values/strings.xml
@@ -1,3 +1,4 @@
Ophelia
+
\ No newline at end of file
diff --git a/composeApp/src/commonMain/composeResources/font/header_font.xml b/composeApp/src/commonMain/composeResources/font/header_font.xml
new file mode 100644
index 0000000..348b911
--- /dev/null
+++ b/composeApp/src/commonMain/composeResources/font/header_font.xml
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml
new file mode 100644
index 0000000..afb796a
--- /dev/null
+++ b/composeApp/src/commonMain/composeResources/values/strings.xml
@@ -0,0 +1,71 @@
+
+
+ Back
+ A Polycule Pocket-dex
+ Get Started
+ Welcome Back
+
+ ##Routes
+ polyculeHome
+ home
+
+ ##Bio
+ Add Bio
+ Edit Bio
+ Finish
+ Bio Loaded
+ Open context menu
+ Name
+ New Bio Added!
+ Bio Edited!
+ Welcome Aboard!
+
+
+ ##Tags
+ Monogamous
+ Plural
+ Furry
+ Therian
+ BDSM
+ Alcohol
+ Weed
+ Asexual
+ Transgender
+
+ ##Ophelia
+ Ophelia Says
+ What do you think; looks like you?
+
+ - Hi!
+ - I'm Ophelia, a Polycule companion system designed to help you keep track of your metas, reference a charter, and find things in common with your polycule.
+ - I'm meant to work dynamically with how polyamory works for you, so what all those words mean will be something we work out together later.
+ - First, I need to get to know "you".
+ - Click Go to get started.
+
+
+ - I'm Ophelia, what's your name?
+ - Your Name is how you'll be addressed in the app, and is the primary way you'll be referred to in polycules.
+ - But don't worry; your name, like everything about you, can be changed at any time!
+
+ "Nice to meet you,%1$s!
+
+ - Personal Pronouns are words used to refer to a person without always using their name.
+ - Since Pronouns are a personal choice, I want to leave them as open as possible for you!
+ - We're dealing with four Personal Pronouns, and using mine as an example: She (subjective) / Her (objective) / Hers (possessive) / Herself (reflexive)
+ - Your Pronouns will be used when referring to you in specific contexts, and are displayed alongside your name in most contexts.
+
+
+ - Tags are a way to highlight important things about yourself.
+ - They also lead to more detailed parts of you bio, where you can flesh out specific parts of your bio.
+
+
+
+ - Great!
+ - Now, there's just one more thing! We need to create a polycule for you. A "polycule" for our purposes is defined as a group of people with a shared relationship process.
+ - A person may be in a polycule with any number of people, including just themselves, and in any number of polycules.
+ - All we need to get started is a name:
+
+
+ ##Helpers
+ Go
+
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/App.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/App.kt
index 5b1950e..9eed838 100644
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/App.kt
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/App.kt
@@ -2,7 +2,9 @@ package com.menagerie.ophelia
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
+import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.material3.Scaffold
@@ -18,14 +20,19 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
-import com.menagerie.ophelia.HomeScreen.HomeScreen
-import com.menagerie.ophelia.HomeScreen.MainMenu
-import com.menagerie.ophelia.HomeScreen.Settings
-import com.menagerie.ophelia.model.Recipe
-import com.menagerie.ophelia.model.recipesList
-import com.menagerie.ophelia.recipesdetails.RecipeDetails
-import com.menagerie.ophelia.recipeslist.RecipesListScreen
import com.menagerie.ophelia.sensor.SensorManager
+import com.menagerie.ophelia.view.HomeScreen.HomeScreen
+import com.menagerie.ophelia.view.HomeScreen.MainMenu
+import com.menagerie.ophelia.view.HomeScreen.Settings
+import com.menagerie.ophelia.view.newUser.AddNameScreen
+import com.menagerie.ophelia.view.recipe.model.Recipe
+import com.menagerie.ophelia.view.recipe.model.recipesList
+import com.menagerie.ophelia.view.recipe.recipesdetails.RecipeDetails
+import com.menagerie.ophelia.view.recipe.recipeslist.RecipesListScreen
+import com.menagerie.ophelia.view.tags.model.Tag
+import com.menagerie.ophelia.view.tags.tagsdetails.TagsDetails
+import com.menagerie.ophelia.view.tags.tagslist.TagsListScreen
+import com.menagerie.ophelia.view.newUser.NewUserStartScreen
enum class DetailListAppScreen {
List,
@@ -47,8 +54,6 @@ fun App(
sensorManager = sensorManager,
prefs = prefs
)
-
-
}
@Composable
@@ -59,38 +64,58 @@ fun OpheliaNavHost(
prefs: DataStore
){
val items by remember { mutableStateOf(recipesList) }
- var show by remember { mutableStateOf(false) }
+ var showBar by remember { mutableStateOf(false) }
Scaffold {
Column {
//TODO : replace this with a composable task bar
- if (show) {
- Row {
- Button(
- onClick = {
- navController.popBackStack()
+ //TODO : replace row with a lazyGrid for better mobile support
+ if (showBar) {
+
+ val listState = rememberLazyGridState()
+ LazyVerticalGrid(
+ state = listState, columns = GridCells.Fixed(if (isLarge) 3 else 1)
+ ) {
+ item {
+ Button(
+ onClick = {
+ navController.popBackStack()
+ }
+ ) {
+ Text(text = "Back - TEMP")
}
- ) {
- Text(text = "Back - TEMP")
}
- Button(
- onClick = {
- navController.navigate("mainMenu")
+ item {
+ Button(
+ onClick = {
+ navController.navigate("mainMenu")
+ }
+ ) {
+ Text(text = "Home - TEMP")
}
- ) {
- Text(text = "Home - TEMP")
}
- Button(
- onClick = {
- navController.navigate("settings")
+ item {
+ Button(
+ onClick = {
+ navController.navigate("settings")
+ }
+ ) {
+ Text(text = "Settings - TEMP")
}
- ) {
- Text(text = "Settings - TEMP")
}
- Button(onClick = {
- //TODO : This should take the user to their bio page
- }){
- Text(text = "You - TEMP")
+ item {
+ Button(onClick = {
+ //TODO : This should take the user to their bio page
+ }) {
+ Text(text = "You - TEMP")
+ }
+ }
+ item {
+ Button(onClick = {
+ navController.navigate("dex")
+ }) {
+ Text(text = "Encyclopedia - TEMP")
+ }
}
}
}
@@ -106,15 +131,17 @@ fun OpheliaNavHost(
isLarge = isLarge,
sensorManager = sensorManager
)
+
welcomeGraph(navController)
composable("home") {
+ showBar = false
HomeScreen {
- show = true
- navController.navigate("mainMenu")
+ navController.navigate("newUserStart")
}
}
composable("mainMenu") {
+ showBar = true
MainMenu(
onPolyClick = {
//TODO : This should take the user to their polycule's main page
@@ -137,13 +164,14 @@ fun OpheliaNavHost(
}
}
+//Graph for new user startup
fun NavGraphBuilder.welcomeGraph(navController: NavHostController) {
-// composable("newUserStart") {
-// NewUserStartScreen { navController.navigate("newUserName") }
-// }
-// composable("newUserName") {
-// AddNameScreen { navController.navigate("newUserPronouns") }
-// }
+ composable("newUserStart") {
+ NewUserStartScreen { navController.navigate("mainMenu") }
+ }
+ composable("newUserName") {
+ AddNameScreen { navController.navigate("newUserPronouns") }
+ }
// composable("newUserPronouns") {
// AddPronounsScreen { navController.navigate("newUserTags") }
// }
@@ -161,6 +189,7 @@ fun NavGraphBuilder.welcomeGraph(navController: NavHostController) {
// }
}
+//Graph for Polycule navigation
fun NavGraphBuilder.polyculeGraph(navController: NavHostController) {
// composable("polyculeHome") {
// PolyculeHomeView(
@@ -197,6 +226,7 @@ fun NavGraphBuilder.polyculeGraph(navController: NavHostController) {
// }
}
+//Graph for your Cookbook
fun NavGraphBuilder.recipeGraph(
navController: NavHostController,
items: List,
@@ -220,7 +250,37 @@ fun NavGraphBuilder.recipeGraph(
isLarge = isLarge,
sensorManager = sensorManager,
recipe = currentRecipe,
- goBack = { navController.popBackStack() }
)
}
+}
+
+//Graph for the Tags
+fun NavGraphBuilder.tagGraph(
+ navController: NavHostController,
+ items: List,
+ isLarge: Boolean,
+ sensorManager: SensorManager?,
+ ) {
+
+ var currentTag = items.first()
+
+ composable(route = DetailListAppScreen.List.name){
+ TagsListScreen(
+ isLarge = isLarge,
+ items = items,
+ onClick = { tag ->
+ currentTag = tag
+ navController.navigate(DetailListAppScreen.Details.name)
+ }
+ )
+ }
+
+ composable(route = DetailListAppScreen.Details.name) {
+ TagsDetails(
+ isLarge = isLarge,
+ sensorManager = sensorManager,
+ tag = currentTag,
+ )
+ }
+
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/AppModule.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/AppModule.kt
new file mode 100644
index 0000000..75ff34e
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/AppModule.kt
@@ -0,0 +1,7 @@
+package com.menagerie.ophelia
+
+import com.menagerie.ophelia.data.user.UserDataSource
+
+interface AppModule {
+ fun provideUserDataSource(): UserDataSource
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/DatabaseDriverFactory.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/DatabaseDriverFactory.kt
new file mode 100644
index 0000000..46e7153
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/DatabaseDriverFactory.kt
@@ -0,0 +1,7 @@
+package com.menagerie.ophelia
+
+import app.cash.sqldelight.db.SqlDriver
+
+expect class DatabaseDriverFactory {
+ fun create(): SqlDriver
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/data/user/DataSource.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/data/user/DataSource.kt
new file mode 100644
index 0000000..b9b4efb
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/data/user/DataSource.kt
@@ -0,0 +1,24 @@
+package com.menagerie.ophelia.data.user
+
+import app.cash.sqldelight.coroutines.asFlow
+import app.cash.sqldelight.coroutines.mapToList
+import com.menagerie.ophelia.PolyculeDatabase
+import kotlinx.coroutines.Dispatchers
+
+class UserDataSource(db: PolyculeDatabase) {
+ private val queries = db.userQueries
+
+ fun insert(id: Long?, name: String) {
+ queries.insert(id = id, name = name)
+ }
+
+ fun getAll() = queries.getAll().asFlow().mapToList(Dispatchers.IO)
+
+ fun update(id: Long, name: String) {
+ queries.updateName(id = id, name = name)
+ }
+
+ fun delete(id: Long) {
+ queries.delete(id = id)
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/RecipeDetailsLarge.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/RecipeDetailsLarge.kt
deleted file mode 100644
index 414b6de..0000000
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/RecipeDetailsLarge.kt
+++ /dev/null
@@ -1,270 +0,0 @@
-package com.menagerie.ophelia.recipesdetails
-
-import androidx.compose.animation.core.animateIntOffsetAsState
-import androidx.compose.animation.core.tween
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.aspectRatio
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.offset
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.rememberLazyListState
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.ArrowBack
-import androidx.compose.material3.Card
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.blur
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.draw.rotate
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.graphics.graphicsLayer
-import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
-import androidx.compose.ui.input.nestedscroll.NestedScrollSource
-import androidx.compose.ui.input.nestedscroll.nestedScroll
-import androidx.compose.ui.input.pointer.PointerEventType
-import androidx.compose.ui.input.pointer.pointerInput
-import androidx.compose.ui.layout.ContentScale
-import androidx.compose.ui.layout.onGloballyPositioned
-import androidx.compose.ui.unit.IntOffset
-import androidx.compose.ui.unit.IntSize
-import androidx.compose.ui.unit.Velocity
-import androidx.compose.ui.unit.dp
-import com.menagerie.ophelia.model.Recipe
-import com.menagerie.ophelia.sensor.Listener
-import com.menagerie.ophelia.sensor.SensorData
-import com.menagerie.ophelia.sensor.SensorManager
-import org.jetbrains.compose.resources.painterResource
-import kotlin.math.PI
-import androidx.compose.material3.Icon
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
-import com.menagerie.ophelia.ui.theme.orangeDark
-import com.menagerie.ophelia.ui.theme.sugar
-import com.menagerie.ophelia.ui.theme.yellow
-
-@Composable
-fun RecipeDetailsLarge(
- recipe: Recipe,
- goBack: () -> Unit,
- sensorManager: SensorManager?,
-) {
- val imageRotation = remember { mutableStateOf(0) }
- val sensorDataLive = remember { mutableStateOf(SensorData(0.0f, 0.0f)) }
- val roll by derivedStateOf { (sensorDataLive.value.roll * 20).coerceIn(-4f, 4f) }
- val pitch by derivedStateOf { (sensorDataLive.value.pitch * 20).coerceIn(-4f, 4f) }
-
- val tweenDuration = 300
-
- sensorManager?.registerListener(object : Listener {
- override fun onUpdate(sensorData: SensorData) {
- sensorDataLive.value = sensorData
- }
- })
-
- val backgroundShadowOffset = animateIntOffsetAsState(
- targetValue = IntOffset((roll * 6f).toInt(), (pitch * 6f).toInt()),
- animationSpec = tween(tweenDuration)
- )
- val backgroundImageOffset = animateIntOffsetAsState(
- targetValue = IntOffset(-roll.toInt(), pitch.toInt()), animationSpec = tween(tweenDuration)
- )
-
- val nestedScrollConnection = remember {
- object : NestedScrollConnection {
- override fun onPreScroll(
- available: Offset, source: NestedScrollSource
- ): Offset {
- imageRotation.value += (available.y * 0.5).toInt()
- return Offset.Zero
- }
-
- override fun onPostScroll(
- consumed: Offset, available: Offset, source: NestedScrollSource
- ): Offset {
- val delta = available.y
- imageRotation.value += ((delta * PI / 180) * 10).toInt()
- return super.onPostScroll(consumed, available, source)
- }
-
- override suspend fun onPreFling(available: Velocity): Velocity {
- imageRotation.value += available.y.toInt()
- return super.onPreFling(available)
- }
- }
- }
-
- Box(
- modifier = Modifier.fillMaxSize()
- .background(if (recipe.bgColor == sugar) yellow else sugar)
- ) {
- val size = mutableStateOf(IntSize(0, 0))
- Row {
- Box(modifier = Modifier.fillMaxSize().onGloballyPositioned {
- size.value = it.size
- }.weight(1f).pointerInput(Unit) {
- awaitPointerEventScope {
- while (true) {
- val event = awaitPointerEvent()
- // on every relayout Compose will send synthetic Move event,
- // so we skip it to avoid event spam
- if (event.type == PointerEventType.Move) {
- val position = event.changes.first().position
- sensorDataLive.value = SensorData(
- roll = position.x - size.value.height / 4,
- pitch = (position.y - size.value.width / 4)
- )
- }
- }
-
- }
- }) {
- Card(
- modifier = Modifier
- .clip(RoundedCornerShape(topEnd = 35.dp, bottomEnd = 35.dp)),
- shape = RoundedCornerShape(
- topEnd = 35.dp,
- bottomEnd = 35.dp,
- ),
- ) {
- // background image + its shadow
- Box(modifier = Modifier.fillMaxSize().background(recipe.bgColor)) {
- if (recipe.bgImageLarge != null) {
- val painter = painterResource(recipe.bgImageLarge)
- Image(painter = painter,
- contentDescription = null,
- contentScale = ContentScale.Crop,
- modifier = Modifier.offset {
- backgroundShadowOffset.value
- }.graphicsLayer {
- scaleX = 1.050f
- scaleY = 1.050f
- }.blur(radius = 8.dp),
- colorFilter = ColorFilter.tint(
- orangeDark.copy(alpha = 0.3f)
- )
- )
-
- Image(
- painter = painter,
- contentDescription = null,
- contentScale = ContentScale.Crop,
- modifier = Modifier.background(
- Color.Transparent,
- RoundedCornerShape(
- bottomEnd = 35.dp, bottomStart = 35.dp
- ),
- ).offset {
- backgroundImageOffset.value
- }.graphicsLayer {
- shadowElevation = 8f
- scaleX = 1.050f
- scaleY = 1.050f
- },
- )
- }
-
- // image shadows and image
- Box(
- modifier = Modifier.aspectRatio(1f).padding(32.dp)
- .align(Alignment.Center)
- ) {
- Box(modifier = Modifier.padding(32.dp)) {
- Image(
- painter = painterResource(recipe.image),
- contentDescription = null,
- modifier = Modifier.aspectRatio(1f).align(Alignment.Center)
- .padding(16.dp).rotate(imageRotation.value.toFloat())
- )
- }
- }
- }
- }
- }
-
- Box(
- modifier = Modifier.fillMaxSize()
- .background(if (recipe.bgColor == sugar) yellow else sugar)
- .pointerInput(Unit) {
- awaitPointerEventScope {
- while (true) {
- val event = awaitPointerEvent()
- if (event.type == PointerEventType.Scroll) {
- val position = event.changes.first().position
- // on every relayout Compose will send synthetic Move event,
- // so we skip it to avoid event spam
- imageRotation.value =
- (imageRotation.value + position.getDistance()
- .toInt() * 0.010).toInt()
- }
- }
- }
- }.weight(1f)
- ) {
- val listState = rememberLazyListState()
-
- Box(
- modifier = Modifier.fillMaxSize()
- ) {
- LazyColumn(
- contentPadding = PaddingValues(64.dp),
- userScrollEnabled = true,
- verticalArrangement = Arrangement.Absolute.spacedBy(16.dp),
- modifier = Modifier.fillMaxSize().nestedScroll(nestedScrollConnection),
- state = listState
- ) {
- StepsAndDetails(
- recipe = recipe
- )
- }
- }
- }
- }
-
- BackButton(goBack)
-
- }
-}
-
-@Composable
-fun BackButton(goBack: () -> Unit) {
- Box(
- modifier = Modifier.padding(start = 32.dp, top = 16.dp).clip(
- RoundedCornerShape(50)
- ).clickable {
- goBack()
- }.background(
- color = Color.Black, shape = RoundedCornerShape(50)
- ).padding(top = 8.dp, bottom = 8.dp, start = 16.dp, end = 16.dp)
- ) {
- Row(verticalAlignment = Alignment.CenterVertically) {
- Icon(
- imageVector = Icons.AutoMirrored.Default.ArrowBack,
- contentDescription = null,
- tint = Color.White,
- modifier = Modifier.size(20.dp)
- )
- Spacer(Modifier.padding(start = 8.dp))
- Text(
- text = "Back to Recipes",
- color = Color.White
- )
- }
- }
-}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/RecipeDetailsSmall.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/RecipeDetailsSmall.kt
deleted file mode 100644
index 780fd5b..0000000
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/RecipeDetailsSmall.kt
+++ /dev/null
@@ -1,252 +0,0 @@
-package com.menagerie.ophelia.recipesdetails
-
-import androidx.compose.animation.core.animateIntOffsetAsState
-import androidx.compose.animation.core.tween
-import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.rememberLazyListState
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.alpha
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.draw.shadow
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
-import androidx.compose.ui.input.nestedscroll.NestedScrollSource
-import androidx.compose.ui.input.nestedscroll.nestedScroll
-import androidx.compose.ui.unit.IntOffset
-import androidx.compose.ui.unit.Velocity
-import androidx.compose.ui.unit.dp
-import com.menagerie.ophelia.model.Recipe
-import com.menagerie.ophelia.ui.theme.sugar
-import com.menagerie.ophelia.ui.theme.yellow
-import com.menagerie.ophelia.ui.theme.orangeDark
-import com.menagerie.ophelia.sensor.Listener
-import com.menagerie.ophelia.sensor.SensorData
-import com.menagerie.ophelia.sensor.SensorManager
-import kotlin.math.PI
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.WindowInsets
-import androidx.compose.foundation.layout.aspectRatio
-import androidx.compose.foundation.layout.offset
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.systemBars
-import androidx.compose.foundation.layout.windowInsetsPadding
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.ArrowBack
-import androidx.compose.ui.draw.blur
-import androidx.compose.ui.graphics.graphicsLayer
-import org.jetbrains.compose.resources.painterResource
-import androidx.compose.ui.draw.*
-import androidx.compose.material3.Icon
-import androidx.compose.ui.layout.ContentScale
-
-@OptIn(ExperimentalFoundationApi::class)
-@Composable
-fun RecipeDetailsSmall(
- recipe: Recipe,
- goBack: () -> Unit,
- sensorManager: SensorManager?,
-) {
- val imageRotation = remember { mutableStateOf(0) }
- val sensorDataLive = remember { mutableStateOf(SensorData(0.0f, 0.0f)) }
- val roll by derivedStateOf { (sensorDataLive.value.roll).coerceIn(-3f, 3f) }
- val pitch by derivedStateOf { (sensorDataLive.value.pitch).coerceIn(-2f, 2f) }
-
- val tweenDuration = 300
-
- sensorManager?.registerListener(object : Listener {
- override fun onUpdate(sensorData: SensorData) {
- sensorDataLive.value = sensorData
- }
- })
-
- val backgroundShadowOffset = animateIntOffsetAsState(
- targetValue = IntOffset((roll * 6f).toInt(), (pitch * 6f).toInt()),
- animationSpec = tween(tweenDuration)
- )
- val backgroundImageOffset = animateIntOffsetAsState(
- targetValue = IntOffset(-roll.toInt(), pitch.toInt()), animationSpec = tween(tweenDuration)
- )
-
- val toolbarOffsetHeightPx = remember { mutableStateOf(340f) }
- val nestedScrollConnection = remember {
- object : NestedScrollConnection {
- override fun onPreScroll(
- available: Offset, source: NestedScrollSource
- ): Offset {
- val delta = available.y
- val newOffset = toolbarOffsetHeightPx.value + delta
- toolbarOffsetHeightPx.value = newOffset.coerceIn(0f, 340f)
- imageRotation.value += (available.y * 0.5).toInt()
- return Offset.Zero
- }
-
- override fun onPostScroll(
- consumed: Offset, available: Offset, source: NestedScrollSource
- ): Offset {
- val delta = available.y
- imageRotation.value += ((delta * PI / 180) * 10).toInt()
- return super.onPostScroll(consumed, available, source)
- }
-
- override suspend fun onPreFling(available: Velocity): Velocity {
- imageRotation.value += available.y.toInt()
- return super.onPreFling(available)
- }
- }
- }
-
- val candidateHeight = maxOf(toolbarOffsetHeightPx.value, 300f)
- val listState = rememberLazyListState()
- val (fraction, setFraction) = remember { mutableStateOf(1f) }
-
-
- Box(
- modifier = Modifier.fillMaxSize()
- .background(color = if (recipe.bgColor == sugar) yellow else sugar)
- ) {
- LazyColumn(
- modifier = Modifier.fillMaxSize().nestedScroll(nestedScrollConnection),
- state = listState
- ) {
-
- stickyHeader {
- Box(
- modifier = Modifier.shadow(
- elevation = if (fraction < 0.05) {
- ((1 - fraction) * 16).dp
- } else 0.dp,
- clip = false,
- ambientColor = Color(0xffCE5A01).copy(if (fraction < 0.1) 1f - fraction else 0f),
- spotColor = Color(0xffCE5A01).copy(if (fraction < 0.1) 1f - fraction else 0f)
- ).alpha(if (fraction < 0.2) 1f - fraction else 0f).fillMaxWidth()
- .background(
- recipe.bgColor,
- RoundedCornerShape(
- bottomEnd = 35.dp, bottomStart = 35.dp
- ),
- ).clip(RoundedCornerShape(bottomEnd = 35.dp, bottomStart = 35.dp))
- .height(candidateHeight.dp)
- ) {
- Box(
- modifier = Modifier.fillMaxSize()
- ) {
-
- //bg image and shadow
- recipe.bgImage?.let {
- Image(painter = painterResource(it),
- contentDescription = null,
- contentScale = ContentScale.FillWidth,
- modifier = Modifier.offset {
- backgroundShadowOffset.value
- }.graphicsLayer {
- scaleX = 1.050f
- scaleY = 1.050f
- }.blur(radius = 8.dp),
- colorFilter = androidx.compose.ui.graphics.ColorFilter.tint(
- orangeDark.copy(alpha = 0.3f)
- )
- )
- Image(painter = painterResource(it),
- contentDescription = null,
- contentScale = ContentScale.FillWidth,
- modifier = Modifier.background(
- Color.Transparent,
- RoundedCornerShape(
- bottomEnd = 35.dp, bottomStart = 35.dp
- ),
- ).offset {
- backgroundImageOffset.value
- }.graphicsLayer {
- shadowElevation = 8f
- scaleX = 1.050f
- scaleY = 1.050f
- },
- alpha = 1 - fraction
- )
- }
-
- Box(
- modifier = Modifier.aspectRatio(1f).align(Alignment.Center)
- ) {
- Box {
- //image rounded shadow
-// Box(modifier = Modifier.offset {
-// IntOffset(
-// x = (roll * 2).dp.roundToPx(),
-// y = -(pitch * 2).dp.roundToPx()
-// )
-// }) {
-//
-// Image(
-// painter = painterResource(recipe.image),
-// contentDescription = null,
-// modifier = Modifier.aspectRatio(1f)
-// .align(Alignment.Center).padding(16.dp).shadow(
-// elevation = 16.dp,
-// shape = CircleShape,
-// clip = false,
-// ambientColor = Color.Red,
-// spotColor = Color.Red,
-// ),
-// colorFilter = androidx.compose.ui.graphics.ColorFilter.tint(
-// orangeDark.copy(alpha = 0.0f)
-// )
-// )
-// }
-
- Image(
- painter = painterResource(recipe.image),
- contentDescription = null,
- modifier = Modifier.aspectRatio(1f).align(Alignment.Center)
- .windowInsetsPadding(WindowInsets.systemBars)
- .padding(16.dp).rotate(imageRotation.value.toFloat())
- .background(
- Color.Transparent,
- CircleShape,
- )
- )
- }
- }
- }
- }
- }
-
- StepsAndDetails(
- recipe = recipe
- )
- }
-
- Box(modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars).size(50.dp)
- .padding(10.dp).alpha(
- alpha = if (fraction <= 0) 1f else 0f,
- ).background(
- color = Color.Black, shape = RoundedCornerShape(50)
- ).shadow(elevation = 16.dp).padding(5.dp).clickable {
- goBack()
- }) {
- Icon(
- imageVector = Icons.AutoMirrored.Default.ArrowBack,
- contentDescription = null,
- tint = recipe.bgColor,
- modifier = Modifier.size(30.dp)
- )
- }
- }
-}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/HomeScreen/Home.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/HomeScreen/Home.kt
similarity index 94%
rename from composeApp/src/commonMain/kotlin/com/menagerie/ophelia/HomeScreen/Home.kt
rename to composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/HomeScreen/Home.kt
index 8eed7f0..f84eb7e 100644
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/HomeScreen/Home.kt
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/HomeScreen/Home.kt
@@ -1,4 +1,4 @@
-package com.menagerie.ophelia.HomeScreen
+package com.menagerie.ophelia.view.HomeScreen
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -14,7 +14,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
-import com.menagerie.ophelia.ui.theme.OpheliaTheme
@Composable
fun HomeScreen(
@@ -56,6 +55,7 @@ fun HeaderText(
) {
Text(text = text)
}
+ Spacer(modifier = Modifier.weight(1f))
}
}
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/HomeScreen/MainMenu.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/HomeScreen/MainMenu.kt
similarity index 94%
rename from composeApp/src/commonMain/kotlin/com/menagerie/ophelia/HomeScreen/MainMenu.kt
rename to composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/HomeScreen/MainMenu.kt
index 536bd12..611b8c9 100644
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/HomeScreen/MainMenu.kt
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/HomeScreen/MainMenu.kt
@@ -1,4 +1,4 @@
-package com.menagerie.ophelia.HomeScreen
+package com.menagerie.ophelia.view.HomeScreen
import androidx.compose.foundation.layout.Column
import androidx.compose.material.Button
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/HomeScreen/Settings.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/HomeScreen/Settings.kt
similarity index 97%
rename from composeApp/src/commonMain/kotlin/com/menagerie/ophelia/HomeScreen/Settings.kt
rename to composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/HomeScreen/Settings.kt
index 7bc369a..76aa387 100644
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/HomeScreen/Settings.kt
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/HomeScreen/Settings.kt
@@ -1,4 +1,4 @@
-package com.menagerie.ophelia.HomeScreen
+package com.menagerie.ophelia.view.HomeScreen
import androidx.compose.foundation.layout.Column
import androidx.compose.material.Button
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/Ophelia.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/Ophelia.kt
new file mode 100644
index 0000000..7bfe541
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/Ophelia.kt
@@ -0,0 +1,73 @@
+package com.menagerie.ophelia.view
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.font.Font
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.unit.dp
+import ophelia.composeapp.generated.resources.Res
+import ophelia.composeapp.generated.resources.header_font
+import ophelia.composeapp.generated.resources.ophelia
+import ophelia.composeapp.generated.resources.welcome_blurb
+import org.jetbrains.compose.resources.StringArrayResource
+import org.jetbrains.compose.resources.StringResource
+import org.jetbrains.compose.resources.painterResource
+import org.jetbrains.compose.resources.stringArrayResource
+
+
+//@Composable
+//fun OpheliaSpanStyle(): SpanStyle {
+// val fontFamily = (Res.font.header_font)
+//
+// return SpanStyle(
+// letterSpacing = MaterialTheme.typography.bodyLarge.letterSpacing,
+// fontFamily = fontFamily,
+// fontSize = MaterialTheme.typography.bodyLarge.fontSize)
+//}
+
+
+@Composable
+fun OpheliaFace(
+ modifier: Modifier
+) {
+ Image(painter = painterResource(Res.drawable.ophelia),
+ contentDescription = null,
+ modifier = modifier
+ )
+}
+
+@Composable
+fun OpheliaWelcome(
+ modifier: Modifier
+) {
+ Box(
+ modifier = modifier
+ .fillMaxSize()
+ .padding(24.dp)
+ ) {
+ Text(
+ text = OpheliaSaysArray(Res.array.welcome_blurb)
+ )
+ }
+}
+
+@Composable
+fun OpheliaSaysArray(
+ res: StringArrayResource,
+ separator: String = "\n\n"
+): AnnotatedString {
+ return buildAnnotatedString {
+ //pushStyle(OpheliaSpanStyle())
+ append(stringArrayResource(res).joinToString(separator = separator))
+ toAnnotatedString()
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipeslist/RecipeImage.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/common/list/ListItemImage.kt
similarity index 91%
rename from composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipeslist/RecipeImage.kt
rename to composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/common/list/ListItemImage.kt
index a50d040..111b556 100644
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipeslist/RecipeImage.kt
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/common/list/ListItemImage.kt
@@ -1,4 +1,4 @@
-package com.menagerie.ophelia.recipeslist
+package com.menagerie.ophelia.view.common.list
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
@@ -14,7 +14,7 @@ import org.jetbrains.compose.resources.DrawableResource
import org.jetbrains.compose.resources.painterResource
@Composable
-fun RecipeImage(imageBitmap: DrawableResource, modifier: Modifier){
+fun ListImage(imageBitmap: DrawableResource, modifier: Modifier){
Box(modifier = modifier) {
Box(
modifier = modifier
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipeslist/RecipeListItemImageWrapper.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/common/list/ListItemImageWrapper.kt
similarity index 83%
rename from composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipeslist/RecipeListItemImageWrapper.kt
rename to composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/common/list/ListItemImageWrapper.kt
index 5a45038..003a21f 100644
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipeslist/RecipeListItemImageWrapper.kt
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/common/list/ListItemImageWrapper.kt
@@ -1,4 +1,4 @@
-package com.menagerie.ophelia.recipeslist
+package com.menagerie.ophelia.view.common.list
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.FastOutSlowInEasing
@@ -18,14 +18,14 @@ import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
@Composable
-fun RecipeListItemImageWrapper(
+fun ListItemImageWrapper(
modifier: Modifier,
child: @Composable () -> Unit,
) {
val animationDuration = 700
val scale = remember { Animatable(0.3f) }
- val rotation = remember {Animatable(20f)}
- val offset = remember {Animatable(0f)}
+ val rotation = remember { Animatable(20f) }
+ val offset = remember { Animatable(0f) }
LaunchedEffect(Unit) {
scale.animateTo(
@@ -47,13 +47,13 @@ fun RecipeListItemImageWrapper(
}
LaunchedEffect(Unit) {
- offset.animateTo(
- 60f,
- animationSpec = tween(
- durationMillis = animationDuration / 2,
- easing = FastOutSlowInEasing
+ offset.animateTo(
+ 60f,
+ animationSpec = tween(
+ durationMillis = animationDuration / 2,
+ easing = FastOutSlowInEasing
+ )
)
- )
offset.animateTo(
targetValue = 0f,
animationSpec = spring(
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipeslist/RecipeListItemWrapper.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/common/list/ListItemWrapper.kt
similarity index 93%
rename from composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipeslist/RecipeListItemWrapper.kt
rename to composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/common/list/ListItemWrapper.kt
index 3091b95..8f2739d 100644
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipeslist/RecipeListItemWrapper.kt
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/common/list/ListItemWrapper.kt
@@ -1,4 +1,4 @@
-package com.menagerie.ophelia.recipeslist
+package com.menagerie.ophelia.view.common.list
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.CubicBezierEasing
@@ -11,13 +11,13 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
-const val perspectiveValue = 0.004
const val rotateX = 9f
+//Wrapper for animating cards
@Composable
-fun RecipeListItemWrapper(
+fun ListItemWrapper(
child: @Composable () -> Unit,
- scrollDirection: Boolean
+ scrollDirection: Boolean,
) {
val scaleAnimatable = remember { Animatable(initialValue = 0.75f) }
val rotateXAnimatable =
@@ -66,4 +66,5 @@ fun RecipeListItemWrapper(
{
child()
}
+
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/newUser/AddNameScreen.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/newUser/AddNameScreen.kt
new file mode 100644
index 0000000..6918c32
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/newUser/AddNameScreen.kt
@@ -0,0 +1,11 @@
+package com.menagerie.ophelia.view.newUser
+
+import androidx.compose.runtime.Composable
+
+@Composable
+fun AddNameScreen(
+ onGo: () -> Unit,
+) {
+ //val inputViewModel: BioListViewModel.InputBioViewModel()
+
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/newUser/NewUserStartScreen.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/newUser/NewUserStartScreen.kt
new file mode 100644
index 0000000..16935fc
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/newUser/NewUserStartScreen.kt
@@ -0,0 +1,46 @@
+package com.menagerie.ophelia.view.newUser
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Button
+import androidx.compose.material3.Scaffold
+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 com.menagerie.ophelia.view.OpheliaFace
+import com.menagerie.ophelia.view.OpheliaWelcome
+import ophelia.composeapp.generated.resources.Res
+import ophelia.composeapp.generated.resources.go
+import org.jetbrains.compose.resources.stringResource
+
+@Composable
+fun NewUserStartScreen(
+ onGo: () -> Unit = {},
+) {
+ Scaffold {
+ Column {
+ OpheliaFace(
+ modifier = Modifier
+ .align(Alignment.CenterHorizontally)
+ .padding(top = 12.dp)
+ )
+ OpheliaWelcome(
+ modifier = Modifier.weight(1f)
+ )
+ Button(
+ onClick = onGo,
+ modifier = Modifier
+ .padding(12.dp)
+ .align(Alignment.End)
+ ) {
+ Text(stringResource(Res.string.go))
+ }
+ Spacer(
+ modifier = Modifier.padding(12.dp)
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/model/Recipe.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/model/Recipe.kt
similarity index 92%
rename from composeApp/src/commonMain/kotlin/com/menagerie/ophelia/model/Recipe.kt
rename to composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/model/Recipe.kt
index d8245dd..61888eb 100644
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/model/Recipe.kt
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/model/Recipe.kt
@@ -1,4 +1,4 @@
-package com.menagerie.ophelia.model
+package com.menagerie.ophelia.view.recipe.model
import androidx.compose.ui.graphics.Color
import org.jetbrains.compose.resources.DrawableResource
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/model/exampleRecipes.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/model/exampleRecipes.kt
similarity index 99%
rename from composeApp/src/commonMain/kotlin/com/menagerie/ophelia/model/exampleRecipes.kt
rename to composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/model/exampleRecipes.kt
index f2755cb..62ad743 100644
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/model/exampleRecipes.kt
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/model/exampleRecipes.kt
@@ -1,4 +1,4 @@
-package com.menagerie.ophelia.model
+package com.menagerie.ophelia.view.recipe.model
import androidx.compose.ui.graphics.Color
import com.menagerie.ophelia.ui.theme.green
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/IngredientItem.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/IngredientItem.kt
similarity index 96%
rename from composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/IngredientItem.kt
rename to composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/IngredientItem.kt
index 9d96849..5258b28 100644
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/IngredientItem.kt
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/IngredientItem.kt
@@ -1,4 +1,4 @@
-package com.menagerie.ophelia.recipesdetails
+package com.menagerie.ophelia.view.recipe.recipesdetails
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
@@ -20,7 +20,7 @@ import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.luminance
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
-import com.menagerie.ophelia.model.Recipe
+import com.menagerie.ophelia.view.recipe.model.Recipe
import ophelia.composeapp.generated.resources.Res
import ophelia.composeapp.generated.resources.ophelia
import org.jetbrains.compose.resources.ExperimentalResourceApi
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/InstructionItem.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/InstructionItem.kt
similarity index 96%
rename from composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/InstructionItem.kt
rename to composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/InstructionItem.kt
index fa0aaad..c1af6a9 100644
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/InstructionItem.kt
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/InstructionItem.kt
@@ -1,4 +1,4 @@
-package com.menagerie.ophelia.recipesdetails
+package com.menagerie.ophelia.view.recipe.recipesdetails
import androidx.compose.foundation.background
import androidx.compose.foundation.border
@@ -22,7 +22,7 @@ import androidx.compose.ui.text.style.LineHeightStyle
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
-import com.menagerie.ophelia.model.Recipe
+import com.menagerie.ophelia.view.recipe.model.Recipe
@Composable
fun InstructionItem(recipe: Recipe, index: Int) {
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/RecipeDetails.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/RecipeDetails.kt
similarity index 51%
rename from composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/RecipeDetails.kt
rename to composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/RecipeDetails.kt
index cc8173c..0a9ffbe 100644
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/RecipeDetails.kt
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/RecipeDetails.kt
@@ -1,28 +1,21 @@
-package com.menagerie.ophelia.recipesdetails
+package com.menagerie.ophelia.view.recipe.recipesdetails
-import androidx.compose.animation.AnimatedVisibilityScope
-import androidx.compose.animation.ExperimentalSharedTransitionApi
-import androidx.compose.animation.SharedTransitionScope
import androidx.compose.runtime.Composable
-import com.menagerie.ophelia.model.Recipe
+import com.menagerie.ophelia.view.recipe.model.Recipe
import com.menagerie.ophelia.sensor.SensorManager
-@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
fun RecipeDetails(
recipe: Recipe,
- goBack: () -> Unit,
sensorManager: SensorManager?,
isLarge: Boolean,
) {
if (isLarge) RecipeDetailsLarge(
recipe = recipe,
- goBack = goBack,
sensorManager = sensorManager
)
else RecipeDetailsSmall(
recipe = recipe,
- goBack = goBack,
sensorManager = sensorManager
)
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/RecipeDetailsLarge.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/RecipeDetailsLarge.kt
new file mode 100644
index 0000000..9eebdf0
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/RecipeDetailsLarge.kt
@@ -0,0 +1,238 @@
+package com.menagerie.ophelia.view.recipe.recipesdetails
+
+import androidx.compose.animation.core.animateIntOffsetAsState
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.aspectRatio
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.filled.ArrowBack
+import androidx.compose.material3.Card
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.blur
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.rotate
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import androidx.compose.ui.input.nestedscroll.NestedScrollSource
+import androidx.compose.ui.input.nestedscroll.nestedScroll
+import androidx.compose.ui.input.pointer.PointerEventType
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.Velocity
+import androidx.compose.ui.unit.dp
+import com.menagerie.ophelia.view.recipe.model.Recipe
+import com.menagerie.ophelia.sensor.Listener
+import com.menagerie.ophelia.sensor.SensorData
+import com.menagerie.ophelia.sensor.SensorManager
+import com.menagerie.ophelia.ui.theme.orangeDark
+import com.menagerie.ophelia.ui.theme.sugar
+import com.menagerie.ophelia.ui.theme.yellow
+import org.jetbrains.compose.resources.painterResource
+import kotlin.math.PI
+
+@Composable
+fun RecipeDetailsLarge(
+ recipe: Recipe,
+ sensorManager: SensorManager?,
+) {
+ val imageRotation = remember { mutableStateOf(0) }
+ val sensorDataLive = remember { mutableStateOf(SensorData(0.0f, 0.0f)) }
+ val roll by derivedStateOf { (sensorDataLive.value.roll * 20).coerceIn(-4f, 4f) }
+ val pitch by derivedStateOf { (sensorDataLive.value.pitch * 20).coerceIn(-4f, 4f) }
+
+ val tweenDuration = 300
+
+ sensorManager?.registerListener(object : Listener {
+ override fun onUpdate(sensorData: SensorData) {
+ sensorDataLive.value = sensorData
+ }
+ })
+
+ val backgroundShadowOffset = animateIntOffsetAsState(
+ targetValue = IntOffset((roll * 6f).toInt(), (pitch * 6f).toInt()),
+ animationSpec = tween(tweenDuration)
+ )
+ val backgroundImageOffset = animateIntOffsetAsState(
+ targetValue = IntOffset(-roll.toInt(), pitch.toInt()), animationSpec = tween(tweenDuration)
+ )
+
+ val nestedScrollConnection = remember {
+ object : NestedScrollConnection {
+ override fun onPreScroll(
+ available: Offset, source: NestedScrollSource
+ ): Offset {
+ imageRotation.value += (available.y * 0.5).toInt()
+ return Offset.Zero
+ }
+
+ override fun onPostScroll(
+ consumed: Offset, available: Offset, source: NestedScrollSource
+ ): Offset {
+ val delta = available.y
+ imageRotation.value += ((delta * PI / 180) * 10).toInt()
+ return super.onPostScroll(consumed, available, source)
+ }
+
+ override suspend fun onPreFling(available: Velocity): Velocity {
+ imageRotation.value += available.y.toInt()
+ return super.onPreFling(available)
+ }
+ }
+ }
+
+ Box(
+ modifier = Modifier.fillMaxSize()
+ .background(if (recipe.bgColor == sugar) yellow else sugar)
+ ) {
+ val size = mutableStateOf(IntSize(0, 0))
+ Row {
+ Box(modifier = Modifier.fillMaxSize().onGloballyPositioned {
+ size.value = it.size
+ }.weight(1f).pointerInput(Unit) {
+ awaitPointerEventScope {
+ while (true) {
+ val event = awaitPointerEvent()
+ // on every relayout Compose will send synthetic Move event,
+ // so we skip it to avoid event spam
+ if (event.type == PointerEventType.Move) {
+ val position = event.changes.first().position
+ sensorDataLive.value = SensorData(
+ roll = position.x - size.value.height / 4,
+ pitch = (position.y - size.value.width / 4)
+ )
+ }
+ }
+
+ }
+ }) {
+ Card(
+ modifier = Modifier
+ .clip(RoundedCornerShape(topEnd = 35.dp, bottomEnd = 35.dp)),
+ shape = RoundedCornerShape(
+ topEnd = 35.dp,
+ bottomEnd = 35.dp,
+ ),
+ ) {
+ // background image + its shadow
+ Box(modifier = Modifier.fillMaxSize().background(recipe.bgColor)) {
+ if (recipe.bgImageLarge != null) {
+ val painter = painterResource(recipe.bgImageLarge)
+ Image(painter = painter,
+ contentDescription = null,
+ contentScale = ContentScale.Crop,
+ modifier = Modifier.offset {
+ backgroundShadowOffset.value
+ }.graphicsLayer {
+ scaleX = 1.050f
+ scaleY = 1.050f
+ }.blur(radius = 8.dp),
+ colorFilter = ColorFilter.tint(
+ orangeDark.copy(alpha = 0.3f)
+ )
+ )
+
+ Image(
+ painter = painter,
+ contentDescription = null,
+ contentScale = ContentScale.Crop,
+ modifier = Modifier.background(
+ Color.Transparent,
+ RoundedCornerShape(
+ bottomEnd = 35.dp, bottomStart = 35.dp
+ ),
+ ).offset {
+ backgroundImageOffset.value
+ }.graphicsLayer {
+ shadowElevation = 8f
+ scaleX = 1.050f
+ scaleY = 1.050f
+ },
+ )
+ }
+
+ // image shadows and image
+ Box(
+ modifier = Modifier.aspectRatio(1f).padding(32.dp)
+ .align(Alignment.Center)
+ ) {
+ Box(modifier = Modifier.padding(32.dp)) {
+ Image(
+ painter = painterResource(recipe.image),
+ contentDescription = null,
+ modifier = Modifier.aspectRatio(1f).align(Alignment.Center)
+ .padding(16.dp).rotate(imageRotation.value.toFloat())
+ )
+ }
+ }
+ }
+ }
+ }
+
+ Box(
+ modifier = Modifier.fillMaxSize()
+ .background(if (recipe.bgColor == sugar) yellow else sugar)
+ .pointerInput(Unit) {
+ awaitPointerEventScope {
+ while (true) {
+ val event = awaitPointerEvent()
+ if (event.type == PointerEventType.Scroll) {
+ val position = event.changes.first().position
+ // on every relayout Compose will send synthetic Move event,
+ // so we skip it to avoid event spam
+ imageRotation.value =
+ (imageRotation.value + position.getDistance()
+ .toInt() * 0.010).toInt()
+ }
+ }
+ }
+ }.weight(1f)
+ ) {
+ val listState = rememberLazyListState()
+
+ Box(
+ modifier = Modifier.fillMaxSize()
+ ) {
+ LazyColumn(
+ contentPadding = PaddingValues(64.dp),
+ userScrollEnabled = true,
+ verticalArrangement = Arrangement.Absolute.spacedBy(16.dp),
+ modifier = Modifier.fillMaxSize().nestedScroll(nestedScrollConnection),
+ state = listState
+ ) {
+ StepsAndDetails(
+ recipe = recipe
+ )
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/RecipeDetailsSmall.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/RecipeDetailsSmall.kt
new file mode 100644
index 0000000..2558028
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/RecipeDetailsSmall.kt
@@ -0,0 +1,210 @@
+package com.menagerie.ophelia.view.recipe.recipesdetails
+
+import androidx.compose.animation.core.animateIntOffsetAsState
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.shadow
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import androidx.compose.ui.input.nestedscroll.NestedScrollSource
+import androidx.compose.ui.input.nestedscroll.nestedScroll
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.Velocity
+import androidx.compose.ui.unit.dp
+import com.menagerie.ophelia.view.recipe.model.Recipe
+import com.menagerie.ophelia.ui.theme.sugar
+import com.menagerie.ophelia.ui.theme.yellow
+import com.menagerie.ophelia.ui.theme.orangeDark
+import com.menagerie.ophelia.sensor.Listener
+import com.menagerie.ophelia.sensor.SensorData
+import com.menagerie.ophelia.sensor.SensorManager
+import kotlin.math.PI
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.aspectRatio
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.systemBars
+import androidx.compose.foundation.layout.windowInsetsPadding
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.filled.ArrowBack
+import androidx.compose.ui.draw.blur
+import androidx.compose.ui.graphics.graphicsLayer
+import org.jetbrains.compose.resources.painterResource
+import androidx.compose.ui.draw.*
+import androidx.compose.material3.Icon
+import androidx.compose.ui.layout.ContentScale
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun RecipeDetailsSmall(
+ recipe: Recipe,
+ sensorManager: SensorManager?,
+) {
+ val imageRotation = remember { mutableStateOf(0) }
+ val sensorDataLive = remember { mutableStateOf(SensorData(0.0f, 0.0f)) }
+ val roll by derivedStateOf { (sensorDataLive.value.roll).coerceIn(-3f, 3f) }
+ val pitch by derivedStateOf { (sensorDataLive.value.pitch).coerceIn(-2f, 2f) }
+
+ val tweenDuration = 300
+
+ sensorManager?.registerListener(object : Listener {
+ override fun onUpdate(sensorData: SensorData) {
+ sensorDataLive.value = sensorData
+ }
+ })
+
+ val backgroundShadowOffset = animateIntOffsetAsState(
+ targetValue = IntOffset((roll * 6f).toInt(), (pitch * 6f).toInt()),
+ animationSpec = tween(tweenDuration)
+ )
+ val backgroundImageOffset = animateIntOffsetAsState(
+ targetValue = IntOffset(-roll.toInt(), pitch.toInt()), animationSpec = tween(tweenDuration)
+ )
+
+ val toolbarOffsetHeightPx = remember { mutableStateOf(340f) }
+ val nestedScrollConnection = remember {
+ object : NestedScrollConnection {
+ override fun onPreScroll(
+ available: Offset, source: NestedScrollSource
+ ): Offset {
+ val delta = available.y
+ val newOffset = toolbarOffsetHeightPx.value + delta
+ toolbarOffsetHeightPx.value = newOffset.coerceIn(0f, 340f)
+ imageRotation.value += (available.y * 0.5).toInt()
+ return Offset.Zero
+ }
+
+ override fun onPostScroll(
+ consumed: Offset, available: Offset, source: NestedScrollSource
+ ): Offset {
+ val delta = available.y
+ imageRotation.value += ((delta * PI / 180) * 10).toInt()
+ return super.onPostScroll(consumed, available, source)
+ }
+
+ override suspend fun onPreFling(available: Velocity): Velocity {
+ imageRotation.value += available.y.toInt()
+ return super.onPreFling(available)
+ }
+ }
+ }
+
+ val candidateHeight = maxOf(toolbarOffsetHeightPx.value, 300f)
+ val listState = rememberLazyListState()
+ val (fraction, setFraction) = remember { mutableStateOf(1f) }
+
+
+ Box(
+ modifier = Modifier.fillMaxSize()
+ .background(color = if (recipe.bgColor == sugar) yellow else sugar)
+ ) {
+ LazyColumn(
+ modifier = Modifier.fillMaxSize().nestedScroll(nestedScrollConnection),
+ state = listState
+ ) {
+
+ stickyHeader {
+ Box(
+ modifier = Modifier.shadow(
+ elevation = if (fraction < 0.05) {
+ ((1 - fraction) * 16).dp
+ } else 0.dp,
+ clip = false,
+ ambientColor = Color(0xffCE5A01).copy(if (fraction < 0.1) 1f - fraction else 0f),
+ spotColor = Color(0xffCE5A01).copy(if (fraction < 0.1) 1f - fraction else 0f)
+ ).alpha(if (fraction < 0.2) 1f - fraction else 0f).fillMaxWidth()
+ .background(
+ recipe.bgColor,
+ RoundedCornerShape(
+ bottomEnd = 35.dp, bottomStart = 35.dp
+ ),
+ ).clip(RoundedCornerShape(bottomEnd = 35.dp, bottomStart = 35.dp))
+ .height(candidateHeight.dp)
+ ) {
+ Box(
+ modifier = Modifier.fillMaxSize()
+ ) {
+
+ //bg image and shadow
+ recipe.bgImage?.let {
+ Image(painter = painterResource(it),
+ contentDescription = null,
+ contentScale = ContentScale.FillWidth,
+ modifier = Modifier.offset {
+ backgroundShadowOffset.value
+ }.graphicsLayer {
+ scaleX = 1.050f
+ scaleY = 1.050f
+ }.blur(radius = 8.dp),
+ colorFilter = androidx.compose.ui.graphics.ColorFilter.tint(
+ orangeDark.copy(alpha = 0.3f)
+ )
+ )
+ Image(painter = painterResource(it),
+ contentDescription = null,
+ contentScale = ContentScale.FillWidth,
+ modifier = Modifier.background(
+ Color.Transparent,
+ RoundedCornerShape(
+ bottomEnd = 35.dp, bottomStart = 35.dp
+ ),
+ ).offset {
+ backgroundImageOffset.value
+ }.graphicsLayer {
+ shadowElevation = 8f
+ scaleX = 1.050f
+ scaleY = 1.050f
+ },
+ alpha = 1 - fraction
+ )
+ }
+
+ Box(
+ modifier = Modifier.aspectRatio(1f).align(Alignment.Center)
+ ) {
+ Box {
+ Image(
+ painter = painterResource(recipe.image),
+ contentDescription = null,
+ modifier = Modifier.aspectRatio(1f).align(Alignment.Center)
+ .windowInsetsPadding(WindowInsets.systemBars)
+ .padding(16.dp).rotate(imageRotation.value.toFloat())
+ .background(
+ Color.Transparent,
+ CircleShape,
+ )
+ )
+ }
+ }
+ }
+ }
+ }
+
+ StepsAndDetails(
+ recipe = recipe
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/StepsAndDetails.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/StepsAndDetails.kt
similarity index 90%
rename from composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/StepsAndDetails.kt
rename to composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/StepsAndDetails.kt
index 4e81c88..2fb0092 100644
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipesdetails/StepsAndDetails.kt
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipesdetails/StepsAndDetails.kt
@@ -1,4 +1,4 @@
-package com.menagerie.ophelia.recipesdetails
+package com.menagerie.ophelia.view.recipe.recipesdetails
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyListScope
@@ -8,7 +8,7 @@ import androidx.compose.material3.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
-import com.menagerie.ophelia.model.Recipe
+import com.menagerie.ophelia.view.recipe.model.Recipe
internal fun LazyListScope.StepsAndDetails(
@@ -39,7 +39,7 @@ internal fun LazyListScope.StepsAndDetails(
}
- itemsIndexed(recipe.ingredients) { index, value ->
+ itemsIndexed(recipe.ingredients) { _, value ->
IngredientItem(recipe, value)
}
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipeslist/RecipeListItem.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipeslist/RecipeListItem.kt
similarity index 90%
rename from composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipeslist/RecipeListItem.kt
rename to composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipeslist/RecipeListItem.kt
index ee9df74..f35957f 100644
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipeslist/RecipeListItem.kt
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipeslist/RecipeListItem.kt
@@ -1,4 +1,4 @@
-package com.menagerie.ophelia.recipeslist
+package com.menagerie.ophelia.view.recipe.recipeslist
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@@ -22,7 +22,9 @@ import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
-import com.menagerie.ophelia.model.Recipe
+import com.menagerie.ophelia.view.common.list.ListImage
+import com.menagerie.ophelia.view.common.list.ListItemImageWrapper
+import com.menagerie.ophelia.view.recipe.model.Recipe
@Composable
@@ -73,9 +75,9 @@ fun RecipeListItem(
Spacer(modifier = Modifier.weight(1f))
}
}
- RecipeListItemImageWrapper(modifier = Modifier.align(Alignment.BottomEnd)
+ ListItemImageWrapper(modifier = Modifier.align(Alignment.BottomEnd)
.fillMaxWidth(0.45f).aspectRatio(1f), child = {
- RecipeImage(
+ ListImage(
imageBitmap = recipe.image, modifier = Modifier
)
})
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipeslist/RecipesList.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipeslist/RecipesList.kt
similarity index 92%
rename from composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipeslist/RecipesList.kt
rename to composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipeslist/RecipesList.kt
index 6c7e1df..101e82d 100644
--- a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/recipeslist/RecipesList.kt
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/recipe/recipeslist/RecipesList.kt
@@ -1,4 +1,4 @@
-package com.menagerie.ophelia.recipeslist
+package com.menagerie.ophelia.view.recipe.recipeslist
import androidx.compose.animation.AnimatedVisibilityScope
import androidx.compose.animation.ExperimentalSharedTransitionApi
@@ -17,7 +17,8 @@ import androidx.compose.foundation.lazy.grid.LazyGridState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
-import com.menagerie.ophelia.model.Recipe
+import com.menagerie.ophelia.view.common.list.ListItemWrapper
+import com.menagerie.ophelia.view.recipe.model.Recipe
import com.menagerie.ophelia.ui.theme.sugar
@Composable
@@ -39,7 +40,7 @@ fun RecipesListScreen(
}
items(items.size) { item ->
val recipe = items[item]
- RecipeListItemWrapper(
+ ListItemWrapper(
scrollDirection = listState.isScrollingUp(),
child = {
RecipeListItem(
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/tags/model/Tag.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/tags/model/Tag.kt
new file mode 100644
index 0000000..9d5227e
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/tags/model/Tag.kt
@@ -0,0 +1,15 @@
+package com.menagerie.ophelia.view.tags.model
+
+import androidx.compose.ui.graphics.Color
+import org.jetbrains.compose.resources.DrawableResource
+import org.jetbrains.compose.resources.ExperimentalResourceApi
+
+data class Tag @OptIn(ExperimentalResourceApi::class) constructor(
+ val id: Int,
+ val title: String,
+ val description: String,
+ val image: DrawableResource,
+ val bgImage: DrawableResource? = null,
+ val bgImageLarge: DrawableResource? = null,
+ val bgColor: Color
+)
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/tags/model/defaultTags.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/tags/model/defaultTags.kt
new file mode 100644
index 0000000..c38d4f9
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/tags/model/defaultTags.kt
@@ -0,0 +1,71 @@
+package com.menagerie.ophelia.view.tags.model
+
+import com.menagerie.ophelia.ui.theme.sugar
+import ophelia.composeapp.generated.resources.Res
+import ophelia.composeapp.generated.resources.ophelia
+
+val tagList = listOf(
+ Tag(
+ id = 1,
+ title = "Alcohol",
+ description = "",
+ image = Res.drawable.ophelia,
+ bgColor = sugar
+ ),
+ Tag(
+ id = 2,
+ title = "Asexual",
+ description = "",
+ image = Res.drawable.ophelia,
+ bgColor = sugar
+ ),
+ Tag(
+ id = 3,
+ title = "BDSM",
+ description = "",
+ image = Res.drawable.ophelia,
+ bgColor = sugar
+ ),
+ Tag(
+ id = 4,
+ title = "Furry",
+ description = "",
+ image = Res.drawable.ophelia,
+ bgColor = sugar
+ ),
+ Tag(
+ id = 5,
+ title = "Monogamous",
+ description = "",
+ image = Res.drawable.ophelia,
+ bgColor = sugar
+ ),
+ Tag(
+ id = 6,
+ title = "Plural",
+ description = "",
+ image = Res.drawable.ophelia,
+ bgColor = sugar
+ ),
+ Tag(
+ id = 7,
+ title = "Therian",
+ description = "",
+ image = Res.drawable.ophelia,
+ bgColor = sugar
+ ),
+ Tag(
+ id = 8,
+ title = "Transgender",
+ description = "",
+ image = Res.drawable.ophelia,
+ bgColor = sugar
+ ),
+ Tag(
+ id = 9,
+ title = "Weed",
+ description = "",
+ image = Res.drawable.ophelia,
+ bgColor = sugar
+ ),
+)
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/tags/tagsdetails/TagsDetails.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/tags/tagsdetails/TagsDetails.kt
new file mode 100644
index 0000000..4a4a0c4
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/tags/tagsdetails/TagsDetails.kt
@@ -0,0 +1,14 @@
+package com.menagerie.ophelia.view.tags.tagsdetails
+
+import androidx.compose.runtime.Composable
+import com.menagerie.ophelia.sensor.SensorManager
+import com.menagerie.ophelia.view.tags.model.Tag
+
+@Composable
+fun TagsDetails(
+ sensorManager: SensorManager?,
+ tag: Tag,
+ isLarge: Boolean
+) {
+
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/tags/tagslist/TagListItem.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/tags/tagslist/TagListItem.kt
new file mode 100644
index 0000000..7148e9a
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/tags/tagslist/TagListItem.kt
@@ -0,0 +1,89 @@
+package com.menagerie.ophelia.view.tags.tagslist
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.aspectRatio
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Card
+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.draw.clip
+import androidx.compose.ui.draw.shadow
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import com.menagerie.ophelia.view.common.list.ListImage
+import com.menagerie.ophelia.view.common.list.ListItemImageWrapper
+import com.menagerie.ophelia.view.tags.model.Tag
+
+//The Actual Content of the Card
+@Composable
+fun TagListItem(
+ tag: Tag,
+ onClick: (tag: Tag) -> Unit,
+) {
+ Box(modifier = Modifier) {
+ Box(modifier = Modifier.padding(top = 8.dp, start = 16.dp, end = 16.dp, bottom = 16.dp)
+ .fillMaxWidth().aspectRatio(1.5f)
+ .shadow(
+ elevation = 16.dp,
+ shape = RoundedCornerShape(35.dp),
+ clip = true,
+ ambientColor = Color(0xffCE5A01),
+ spotColor = Color(0xffCE5A01)
+ )
+ .background(color = tag.bgColor, shape = RoundedCornerShape(35.dp)).fillMaxHeight().clickable {
+ onClick(tag)
+ }) {
+ Card(
+ backgroundColor = tag.bgColor,
+ shape = RoundedCornerShape(35.dp),
+ modifier = Modifier.clip(RoundedCornerShape(35.dp))
+ ) {
+ Box(
+ modifier = Modifier.fillMaxWidth().aspectRatio(1.5f)
+ ) {
+ Row(
+ modifier = Modifier.fillMaxHeight().padding(16.dp).fillMaxWidth(0.55f),
+ verticalAlignment = Alignment.Bottom
+ ) {
+ Column(modifier = Modifier.align(Alignment.Bottom)) {
+ Text(
+ text = tag.title,
+ style = MaterialTheme.typography.headlineSmall,
+ modifier = Modifier
+ )
+
+ Text(
+ tag.description,
+ style = MaterialTheme.typography.displayMedium,
+ maxLines = 3,
+ overflow = TextOverflow.Ellipsis,
+ modifier = Modifier.padding(top = 8.dp),
+ )
+ }
+ Spacer(modifier = Modifier.weight(1f))
+ }
+ }
+ ListItemImageWrapper(modifier = Modifier.align(Alignment.BottomEnd)
+ .fillMaxWidth(0.45f).aspectRatio(1f), child = {
+ ListImage(
+ imageBitmap = tag.image, modifier = Modifier
+ )
+ })
+ }
+
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/tags/tagslist/TagsList.kt b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/tags/tagslist/TagsList.kt
new file mode 100644
index 0000000..548196e
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/menagerie/ophelia/view/tags/tagslist/TagsList.kt
@@ -0,0 +1,81 @@
+package com.menagerie.ophelia.view.tags.tagslist
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.systemBars
+import androidx.compose.foundation.layout.windowInsetsPadding
+import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.LazyGridState
+import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
+import androidx.compose.foundation.lazy.grid.rememberLazyGridState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import com.menagerie.ophelia.view.common.list.ListItemWrapper
+import com.menagerie.ophelia.view.tags.model.Tag
+import com.menagerie.ophelia.ui.theme.sugar
+
+@Composable
+fun TagsListScreen(
+ items: List,
+ onClick: (tag: Tag) -> Unit,
+ isLarge: Boolean,
+) {
+ //wrap the whole screen in a box (or scaffold)
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(sugar)
+ ){
+ val listState = rememberLazyGridState() //keep track of how the cells are arranged
+ LazyVerticalGrid(
+ state = listState,
+ columns = GridCells.Fixed(if (isLarge) 3 else 1) //TODO : replace check with enum values?
+
+ ) {
+ if(isLarge.not())
+ item {
+ Spacer(modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars))
+ } //add a top spacer on mobile for the system bars
+ items(items.size) { item ->
+ val tag = items[item]
+ ListItemWrapper(
+ scrollDirection = listState.isScrollingUp(),
+ child = {
+ TagListItem(
+ tag = tag,
+ onClick = onClick
+ )
+ }
+ )
+ } //grid items list of tags
+ } // grid
+ } // Box
+} // screen
+
+
+//TODO : Move this to its own helper file
+@Composable
+private fun LazyGridState.isScrollingUp(): Boolean {
+ var previousIndex by remember(this) {mutableStateOf(firstVisibleItemIndex)}
+ var previousScrollOffset by remember(this) {mutableStateOf(firstVisibleItemScrollOffset)}
+ return remember(this) {
+ derivedStateOf {
+ if(previousIndex != firstVisibleItemIndex) {
+ previousIndex > firstVisibleItemIndex
+ } else {
+ previousScrollOffset >= firstVisibleItemScrollOffset
+ }.also {
+ previousIndex = firstVisibleItemIndex
+ previousScrollOffset = firstVisibleItemScrollOffset
+ }
+ }
+ }.value
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/sqldelight/com/menagerie/ophelia/User.sq b/composeApp/src/commonMain/sqldelight/com/menagerie/ophelia/User.sq
new file mode 100644
index 0000000..059184e
--- /dev/null
+++ b/composeApp/src/commonMain/sqldelight/com/menagerie/ophelia/User.sq
@@ -0,0 +1,20 @@
+CREATE TABLE User (
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ name TEXT NOT NULL
+);
+
+insert:
+INSERT OR REPLACE INTO User(id, name)
+VALUES(?,?);
+
+getAll:
+SELECT * FROM User;
+
+updateName:
+UPDATE User
+SET name = :name
+WHERE id IS :id;
+
+delete:
+DELETE FROM User
+WHERE id IS :id;
diff --git a/composeApp/src/desktopMain/kotlin/com/menagerie/ophelia/DatabaseDriverFactory.desktop.kt b/composeApp/src/desktopMain/kotlin/com/menagerie/ophelia/DatabaseDriverFactory.desktop.kt
new file mode 100644
index 0000000..56cbb5c
--- /dev/null
+++ b/composeApp/src/desktopMain/kotlin/com/menagerie/ophelia/DatabaseDriverFactory.desktop.kt
@@ -0,0 +1,12 @@
+package com.menagerie.ophelia
+
+import app.cash.sqldelight.db.SqlDriver
+import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
+
+actual class DatabaseDriverFactory {
+ actual fun create(): SqlDriver {
+ val driver: SqlDriver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)
+ PolyculeDatabase.Schema.create(driver)
+ return driver
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/desktopMain/kotlin/com/menagerie/ophelia/DesktopAppModule.kt b/composeApp/src/desktopMain/kotlin/com/menagerie/ophelia/DesktopAppModule.kt
new file mode 100644
index 0000000..98e9a4c
--- /dev/null
+++ b/composeApp/src/desktopMain/kotlin/com/menagerie/ophelia/DesktopAppModule.kt
@@ -0,0 +1,13 @@
+package com.menagerie.ophelia
+
+import com.menagerie.ophelia.data.user.UserDataSource
+
+class DesktopAppModule : AppModule {
+ private val db by lazy {
+ PolyculeDatabase(
+ driver = DatabaseDriverFactory().create()
+ )
+ }
+
+ override fun provideUserDataSource() = UserDataSource(db)
+}
\ No newline at end of file
diff --git a/composeApp/src/desktopMain/kotlin/com/menagerie/ophelia/main.kt b/composeApp/src/desktopMain/kotlin/com/menagerie/ophelia/main.kt
index e64b158..caeeb43 100644
--- a/composeApp/src/desktopMain/kotlin/com/menagerie/ophelia/main.kt
+++ b/composeApp/src/desktopMain/kotlin/com/menagerie/ophelia/main.kt
@@ -3,8 +3,10 @@ package com.menagerie.ophelia
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
+import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
+import androidx.compose.ui.window.rememberWindowState
import androidx.datastore.preferences.core.stringPreferencesKey
import com.menagerie.ophelia.ui.theme.OpheliaTheme
import kotlinx.coroutines.flow.map
@@ -28,6 +30,7 @@ fun main() {
Window(
onCloseRequest = ::exitApplication,
title = "Ophelia",
+ state = rememberWindowState(height = 900.dp, width = 1200.dp)
) {
val currentThemeString by prefs
diff --git a/composeApp/src/main/res/values/arrays.xml b/composeApp/src/main/res/values/arrays.xml
new file mode 100644
index 0000000..141bfc0
--- /dev/null
+++ b/composeApp/src/main/res/values/arrays.xml
@@ -0,0 +1,17 @@
+
+
+
+ - @array/com_google_android_gms_fonts_certs_dev
+ - @array/com_google_android_gms_fonts_certs_prod
+
+
+ -
+ MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
+
+
+
+ -
+ MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
+
+
+
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 3752de5..048c0b4 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -19,6 +19,7 @@ material3Android = "1.3.1"
material3Desktop = "1.3.1"
uiTextGoogleFonts = "1.7.5"
core = "1.15.0"
+sqldelight = "2.0.2"
navigation-compose = "2.7.0-alpha07"
datastore = "1.1.1"
@@ -39,6 +40,9 @@ kotlinx-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-co
androidx-material3-android = { group = "androidx.compose.material3", name = "material3-android", version.ref = "material3Android" }
androidx-material3-desktop = { group = "androidx.compose.material3", name = "material3-desktop", version.ref = "material3Desktop" }
androidx-ui-text-google-fonts = { group = "androidx.compose.ui", name = "ui-text-google-fonts", version.ref = "uiTextGoogleFonts" }
+sqldelight-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
+sqldelight-jvm = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqldelight" }
+sqldelight-coroutines = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqldelight" }
androidx-core = { group = "androidx.core", name = "core", version.ref = "core" }
datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" }
datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastore" }
@@ -48,4 +52,5 @@ androidApplication = { id = "com.android.application", version.ref = "agp" }
androidLibrary = { id = "com.android.library", version.ref = "agp" }
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
-kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
\ No newline at end of file
+kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
+sqlDelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" }
\ No newline at end of file