Compare commits
51 commits
Author | SHA1 | Date | |
---|---|---|---|
49406f610c | |||
e0f6406fab | |||
e2a1b8fb50 | |||
4ce2b6ea76 | |||
88199d3fcc | |||
f22cf73708 | |||
69320517b6 | |||
81306b4140 | |||
38afc6f5c9 | |||
7eaa2de71e | |||
261509417d | |||
866111e4ba | |||
4471a95ab1 | |||
19c2cc56ed | |||
3ae7688aeb | |||
fbc690cb56 | |||
2e1c8b2b93 | |||
17d9f6d0f7 | |||
8e5911fe43 | |||
1c950ef339 | |||
27611b180a | |||
f6834e5e4f | |||
652fcfe9a8 | |||
b29bb87190 | |||
6a9329cdcf | |||
04c02e3dae | |||
334d4e15e8 | |||
2f2ba59ca3 | |||
49628a73f4 | |||
9d10a82966 | |||
0207185ce3 | |||
7ddb939c2f | |||
60deff6c2a | |||
5758466477 | |||
74fbe13c8e | |||
0fac8f4611 | |||
9d6ba8ed10 | |||
080d85c266 | |||
418968c428 | |||
2a9f385a82 | |||
5bb06e8d49 | |||
0d8b2518f1 | |||
a3a01b5581 | |||
fb2756b668 | |||
817472400b | |||
cf73f9a833 | |||
1d674be4f4 | |||
ba6d0d956b | |||
f2d72d9aa9 | |||
0a72b9fc82 | |||
5874e90288 |
22 changed files with 464 additions and 111 deletions
16
.woodpecker/android-build.yml
Normal file
16
.woodpecker/android-build.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
when:
|
||||
- event: push
|
||||
branch: [ dockerBuild, master ]
|
||||
- event: tag
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: gradle:8.10.2-jdk17
|
||||
environment:
|
||||
ANDROID_HOME: /sdk
|
||||
commands:
|
||||
- apt update && apt install -y sdkmanager openjdk-11-jdk
|
||||
- sdkmanager "tools" && yes | sdkmanager --licenses
|
||||
#More info
|
||||
# https://developer.android.com/build/building-cmdline
|
||||
- gradle assembleDebug
|
17
.woodpecker/deb-build.yml
Normal file
17
.woodpecker/deb-build.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
when:
|
||||
- event: push
|
||||
branch: [ dockerBuild, master ]
|
||||
- event: tag
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: gradle:8.10.2-jdk17
|
||||
environment:
|
||||
ANDROID_HOME: /sdk
|
||||
commands:
|
||||
- apt update && apt install -y sdkmanager openjdk-11-jdk
|
||||
- sdkmanager "tools" && yes | sdkmanager --licenses
|
||||
- gradle buildDeb
|
||||
|
||||
depends_on:
|
||||
- android-build
|
59
.woodpecker/release-packaging.yml
Normal file
59
.woodpecker/release-packaging.yml
Normal file
|
@ -0,0 +1,59 @@
|
|||
when:
|
||||
- event: tag
|
||||
|
||||
steps:
|
||||
- name: build-releases
|
||||
image: gradle:8.10.2-jdk17
|
||||
environment:
|
||||
ANDROID_HOME: /sdk
|
||||
KEYSTORE_FILE:
|
||||
from_secret: keystore_file
|
||||
TEST_ENV:
|
||||
from_secret: test_secret
|
||||
KEYSTORE_PASSWORD:
|
||||
from_secret: keystore_password
|
||||
KEY_ALIAS:
|
||||
from_secret: key_alias
|
||||
KEY_PASSWORD:
|
||||
from_secret: key_password
|
||||
commands:
|
||||
- apt update && apt install -y sdkmanager openjdk-11-jdk
|
||||
- sdkmanager "tools" && yes | sdkmanager --licenses
|
||||
- gradle clean
|
||||
- echo "$TEST_ENV"
|
||||
- echo "$KEYSTORE_FILE" | base64 -d > keystore.jks
|
||||
# Package Release Deb currently fails on local
|
||||
- gradle buildDeb
|
||||
- gradle assembleRelease -Pandroid.injected.signing.store.file=$(pwd)/keystore.jks -Pandroid.injected.signing.store.password=$KEYSTORE_PASSWORD -Pandroid.injected.signing.key.alias="$KEY_ALIAS" -Pandroid.injected.signing.key.password=$KEY_PASSWORD
|
||||
- name: publish-packages
|
||||
image: woodpeckerci/plugin-release
|
||||
settings:
|
||||
files:
|
||||
- androidApp/build/outputs/apk/release/androidApp-release.apk
|
||||
- desktopApp/build/compose/binaries/main/deb/bakers-menagerie_*.deb
|
||||
checksum:
|
||||
- androidApp/build/outputs/apk/release/androidApp-release.apk
|
||||
- desktopApp/build/compose/binaries/main/deb/bakers-menagerie_*.deb
|
||||
target: master
|
||||
draft: true
|
||||
overwrite: true
|
||||
generate-release-notes: true
|
||||
api_key:
|
||||
from_secret: ci_access_token
|
||||
- name: publish-container
|
||||
image: woodpeckerci/plugin-kaniko
|
||||
repo: git.blizzard.systems/Menagerie/Menagerie_Cookbook
|
||||
username:
|
||||
from_secret: ci_username
|
||||
password:
|
||||
from_secret: ci_access_token
|
||||
registry: git.blizzard.systems
|
||||
dockerfile: Dockerfile.web-serve
|
||||
auto-tag: true
|
||||
cache: true
|
||||
|
||||
depends_on:
|
||||
- android-build
|
||||
- deb-build
|
||||
- web-build
|
||||
|
10
.woodpecker/web-build.yml
Normal file
10
.woodpecker/web-build.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
when:
|
||||
- event: push
|
||||
branch: [ dockerBuild, master ]
|
||||
- event: tag
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: gradle:8.10.2-jdk21
|
||||
commands:
|
||||
- gradle wasmJsBrowserDistribution
|
29
Dockerfile.dpkg-build
Normal file
29
Dockerfile.dpkg-build
Normal file
|
@ -0,0 +1,29 @@
|
|||
# Original build used JVM 21.0.3
|
||||
# Gradle version 8.10.2
|
||||
|
||||
### For RPM Builds, need to implement Nebula RPM plugin; see https://plugins.gradle.org/plugin/com.netflix.nebula.rpm
|
||||
FROM gradle:8.10.2-jdk21 AS cache
|
||||
RUN apt update && apt install -y sdkmanager openjdk-11-jdk
|
||||
RUN sdkmanager "tools"
|
||||
RUN yes | sdkmanager --licenses
|
||||
RUN mkdir -p /src
|
||||
ENV GRADLE_USER_HOME=/home/gradle/cache_home
|
||||
COPY gradle /src/gradle
|
||||
COPY build.gradle.kts gradle.properties settings.gradle.kts /src/.
|
||||
COPY androidApp/build.gradle.kts /src/androidApp/.
|
||||
COPY automotiveApp/build.gradle.kts /src/automotiveApp/.
|
||||
COPY desktopApp/build.gradle.kts /src/desktopApp/.
|
||||
COPY shared/build.gradle.kts /src/shared/.
|
||||
COPY tvApp/build.gradle.kts /src/tvApp/.
|
||||
COPY webApp/build.gradle.kts /src/webApp/.
|
||||
WORKDIR /src
|
||||
RUN ls -lahR
|
||||
RUN gradle -q javaToolchains
|
||||
RUN gradle buildEnvironment --refresh-dependencies
|
||||
|
||||
FROM gradle:8.10.2-jdk21 AS build
|
||||
WORKDIR /src
|
||||
COPY --from=cache /home/gradle/cache_home /home/gradle/.
|
||||
COPY --chown=gradle:gradle . /src/.
|
||||
RUN gradle clean
|
||||
RUN gradle packageReleaseDeb
|
27
Dockerfile.web-serve
Normal file
27
Dockerfile.web-serve
Normal file
|
@ -0,0 +1,27 @@
|
|||
# Original build used JVM 21.0.3
|
||||
# Gradle version 8.10.2
|
||||
FROM gradle:8.10.2-jdk21 AS cache
|
||||
RUN apt update && apt install -y sdkmanager openjdk-11-jdk
|
||||
RUN sdkmanager "tools"
|
||||
RUN yes | sdkmanager --licenses
|
||||
RUN mkdir -p /src
|
||||
ENV GRADLE_USER_HOME=/home/gradle/cache_home
|
||||
COPY gradle /src/gradle
|
||||
COPY build.gradle.kts gradle.properties settings.gradle.kts /src/.
|
||||
COPY androidApp/build.gradle.kts /src/androidApp/.
|
||||
COPY automotiveApp/build.gradle.kts /src/automotiveApp/.
|
||||
COPY desktopApp/build.gradle.kts /src/desktopApp/.
|
||||
COPY shared/build.gradle.kts /src/shared/.
|
||||
COPY tvApp/build.gradle.kts /src/tvApp/.
|
||||
COPY webApp/build.gradle.kts /src/webApp/.
|
||||
WORKDIR /src
|
||||
RUN gradle buildEnvironment --refresh-dependencies
|
||||
|
||||
FROM gradle:8.10.2-jdk21 AS build
|
||||
WORKDIR /src
|
||||
COPY --from=cache /home/gradle/cache_home /home/gradle/.
|
||||
COPY --chown=gradle:gradle . /src/.
|
||||
RUN gradle clean && gradle wasmJsBrowserDistribution
|
||||
|
||||
FROM nginx:latest
|
||||
COPY --from=build /src/webApp/build/dist/wasmJs/productionExecutable /usr/share/nginx/html
|
BIN
shared/src/commonMain/composeResources/drawable/cordon_bleu.jpg
Normal file
BIN
shared/src/commonMain/composeResources/drawable/cordon_bleu.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 532 KiB |
BIN
shared/src/commonMain/composeResources/drawable/opor_ayam.jpg
Normal file
BIN
shared/src/commonMain/composeResources/drawable/opor_ayam.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 829 KiB |
|
@ -40,6 +40,7 @@ import view.BookShelf
|
|||
import view.FilterCard
|
||||
import view.HomeScreen
|
||||
import view.InputFieldState
|
||||
import view.MainDropDown
|
||||
import view.getFilteredRecipeList
|
||||
import view.getRecipeList
|
||||
|
||||
|
@ -50,6 +51,12 @@ enum class Theme {
|
|||
Dark
|
||||
}
|
||||
|
||||
enum class SortBy {
|
||||
Name,
|
||||
Time,
|
||||
Ingredients,
|
||||
}
|
||||
|
||||
enum class RecipeAppScreen {
|
||||
List, Details,
|
||||
}
|
||||
|
@ -64,6 +71,7 @@ fun App(
|
|||
|
||||
val navController = rememberNavController()
|
||||
var theme by remember { mutableStateOf(Theme.Auto) }
|
||||
var sortBy by remember { mutableStateOf(SortBy.Name) }
|
||||
|
||||
val onThemeToggle = {
|
||||
theme = when (theme) {
|
||||
|
@ -72,6 +80,15 @@ fun App(
|
|||
Theme.Dark -> Theme.Auto
|
||||
}
|
||||
}
|
||||
|
||||
val onSortToggle = {
|
||||
sortBy = when (sortBy) {
|
||||
SortBy.Name -> SortBy.Time
|
||||
SortBy.Time -> SortBy.Ingredients
|
||||
SortBy.Ingredients -> SortBy.Name
|
||||
}
|
||||
}
|
||||
|
||||
val isDarkTheme: Boolean? = when (theme) {
|
||||
Theme.Dark -> true
|
||||
Theme.Light -> false
|
||||
|
@ -87,6 +104,7 @@ fun App(
|
|||
val recipeTags by remember { mutableStateOf(mutableMapOf<String, TagType>()) }
|
||||
var book by remember { mutableStateOf("") }
|
||||
var returnAnyMatch by remember { mutableStateOf(false) }
|
||||
var descending by remember { mutableStateOf(false) }
|
||||
|
||||
for (recipe in getRecipeList()) {
|
||||
for (tag in recipe.tags) {
|
||||
|
@ -108,7 +126,14 @@ fun App(
|
|||
}
|
||||
}
|
||||
|
||||
val filteredItems = getFilteredRecipeList(tags, search, book, returnAnyMatch)
|
||||
val filteredItems = getFilteredRecipeList(
|
||||
tags = tags,
|
||||
search = search,
|
||||
lockTag = book,
|
||||
sortBy = sortBy,
|
||||
returnAny = returnAnyMatch,
|
||||
reverse = descending,
|
||||
)
|
||||
val recipeCount = getRecipeList().size
|
||||
var currentRecipe = getRecipeList().first()
|
||||
|
||||
|
@ -138,12 +163,16 @@ fun App(
|
|||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
MainDropDown(
|
||||
isLarge,
|
||||
returnAnyMatch,
|
||||
theme,
|
||||
isLarge = isLarge,
|
||||
andOr = returnAnyMatch,
|
||||
theme = theme,
|
||||
sortBy = sortBy,
|
||||
descending = descending,
|
||||
onClose = onClose,
|
||||
onBack = {navController.navigateUp()},
|
||||
onTag = {returnAnyMatch = !returnAnyMatch},
|
||||
onSortBy = { onSortToggle.invoke() },
|
||||
onDesc = {descending = !descending},
|
||||
onTheme = { onThemeToggle.invoke() },
|
||||
onRandom = {
|
||||
currentRecipe = filteredItems.random()
|
||||
|
@ -237,56 +266,4 @@ fun App(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MainDropDown(
|
||||
isLarge: Boolean,
|
||||
andOr: Boolean,
|
||||
theme: Theme,
|
||||
onTag: () -> Unit,
|
||||
onTheme: () -> Unit,
|
||||
onRandom: () -> Unit,
|
||||
onBack: () -> Unit,
|
||||
onClose: () -> Unit,
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(16.dp)
|
||||
) {
|
||||
IconButton(onClick = { expanded = !expanded }) {
|
||||
Icon(imageVector = Icons.Default.MoreVert, contentDescription = "More Options")
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(theme.name) },
|
||||
onClick = onTheme
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = {Text(if(andOr) "OR" else "AND")},
|
||||
onClick = onTag
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text("Random Filtered Recipe") },
|
||||
onClick = onRandom
|
||||
)
|
||||
if (isLarge) {
|
||||
|
||||
DropdownMenuItem(
|
||||
text = {Text("Go Back")},
|
||||
onClick = onBack
|
||||
)
|
||||
|
||||
DropdownMenuItem(
|
||||
text = { Text("Close app") },
|
||||
onClick = onClose
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,7 +31,11 @@ import androidx.compose.ui.unit.sp
|
|||
import model.Recipe
|
||||
|
||||
@Composable
|
||||
fun InstructionItem(recipe: Recipe, index: Int, slider: Float) {
|
||||
fun InstructionItem(
|
||||
recipe: Recipe,
|
||||
index: Int,
|
||||
count: Int,
|
||||
slider: Float) {
|
||||
Box(modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp)) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
|
@ -70,7 +74,7 @@ fun InstructionItem(recipe: Recipe, index: Int, slider: Float) {
|
|||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = "${index + 1}",
|
||||
text = "$count",
|
||||
style = MaterialTheme.typography.displayMedium.copy(
|
||||
lineHeightStyle = LineHeightStyle(
|
||||
alignment = LineHeightStyle.Alignment.Center,
|
||||
|
|
|
@ -49,6 +49,7 @@ import org.jetbrains.compose.resources.painterResource
|
|||
import sensor.Listener
|
||||
import sensor.SensorData
|
||||
import sensor.SensorManager
|
||||
import view.RecipeScaleSlider
|
||||
|
||||
|
||||
@OptIn(ExperimentalSharedTransitionApi::class)
|
||||
|
@ -110,9 +111,9 @@ fun RecipeDetailsLarge(
|
|||
modifier = Modifier.padding(top = 64.dp)
|
||||
) {
|
||||
recipeHeader(recipe, true, slider)
|
||||
SliderMinimalExample(
|
||||
RecipeScaleSlider(
|
||||
sliderPosition = slider,
|
||||
steps = 2,
|
||||
steps = if(reduce) 2 else 5,
|
||||
rangeEnd = if(reduce) 1f else 4f,
|
||||
rangeStart = if(reduce) .25f else 1f,
|
||||
reduce = reduce,
|
||||
|
@ -199,30 +200,3 @@ fun BackButton(goBack: () -> Unit) {
|
|||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun SliderMinimalExample(
|
||||
sliderPosition: Float,
|
||||
steps: Int,
|
||||
rangeStart: Float,
|
||||
rangeEnd: Float,
|
||||
reduce: Boolean,
|
||||
onClick: () -> Unit,
|
||||
onChange: (Float) -> Unit) {
|
||||
|
||||
Column {
|
||||
Slider(
|
||||
value = sliderPosition,
|
||||
steps = steps,
|
||||
valueRange = rangeStart..rangeEnd,
|
||||
onValueChange = { onChange(it) },
|
||||
modifier = Modifier.padding(start = 16.dp, end = 16.dp)
|
||||
)
|
||||
Row {
|
||||
Text(text = sliderPosition.toString().plus("x Servings"))
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Button(onClick = onClick) {
|
||||
Text(text = if (reduce) "Reducing" else "Increasing")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +1,33 @@
|
|||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
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.WindowInsets
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
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.layout.size
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
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.rotate
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
@ -45,17 +36,16 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
|||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.unit.Velocity
|
||||
import androidx.compose.ui.unit.dp
|
||||
import details.StepsAndDetails
|
||||
import details.ingredients
|
||||
import details.ingredientsHeader
|
||||
import details.recipeHeader
|
||||
import details.steps
|
||||
import details.stepsHeader
|
||||
import model.Recipe
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import sensor.Listener
|
||||
import sensor.SensorData
|
||||
import sensor.SensorManager
|
||||
import view.RecipeScaleSlider
|
||||
import kotlin.math.PI
|
||||
|
||||
|
||||
|
@ -93,7 +83,6 @@ fun RecipeDetailsSmall(
|
|||
consumed: Offset, available: Offset, source: NestedScrollSource
|
||||
): Offset {
|
||||
val delta = available.y
|
||||
imageRotation.value += ((delta * PI / 180) * 10).toInt()
|
||||
return super.onPostScroll(consumed, available, source)
|
||||
}
|
||||
|
||||
|
@ -145,9 +134,9 @@ fun RecipeDetailsSmall(
|
|||
}
|
||||
|
||||
item {
|
||||
SliderMinimalExample(
|
||||
RecipeScaleSlider(
|
||||
sliderPosition = slider,
|
||||
steps = 2,
|
||||
steps = if(reduce) 2 else 5,
|
||||
reduce = reduce,
|
||||
onClick = {
|
||||
reduce = !reduce
|
||||
|
|
|
@ -161,6 +161,7 @@ internal fun LazyListScope.steps(
|
|||
slider: Float
|
||||
)
|
||||
{
|
||||
var count = 1
|
||||
itemsIndexed(recipe.instructions) { index, value ->
|
||||
AnimateInEffect(
|
||||
recipe = recipe,
|
||||
|
@ -179,7 +180,9 @@ internal fun LazyListScope.steps(
|
|||
)
|
||||
}
|
||||
}else {
|
||||
InstructionItem(recipe, index, slider)}
|
||||
InstructionItem(recipe, index, count, slider)
|
||||
count++
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,7 +117,7 @@ val koreanList = listOf(
|
|||
|
||||
"HEADER-Fire Sauce",
|
||||
"3 Tbsp Gochugaru",
|
||||
"2 Alapenos",
|
||||
"2 Jalapenos",
|
||||
".5 Cup Korean Pear",
|
||||
".25 White Onion",
|
||||
"3 Tbsp Garlic, minced",
|
||||
|
|
|
@ -4,6 +4,7 @@ import model.Recipe
|
|||
import model.TagType
|
||||
import recipeappkmp.shared.generated.resources.Res
|
||||
import recipeappkmp.shared.generated.resources._10_strawberries
|
||||
import recipeappkmp.shared.generated.resources.opor_ayam
|
||||
import kotlin.time.Duration
|
||||
|
||||
val seaList = listOf(
|
||||
|
@ -34,5 +35,66 @@ val seaList = listOf(
|
|||
),
|
||||
servings = "About 1 Cup",
|
||||
image = Res.drawable._10_strawberries
|
||||
),
|
||||
|
||||
Recipe(
|
||||
title = "Opor Ayam",
|
||||
description = "Chicken with carmelised Onion in a rich coconut gravy.",
|
||||
prepTime = Duration.parse("8h"),
|
||||
cookTime = Duration.parse("40m"),
|
||||
servings = "Serves 4",
|
||||
ingredients = listOf(
|
||||
|
||||
"HEADER-Marinade",
|
||||
"1.5kg Protein of Choice",
|
||||
"2 Cloves Garlic",
|
||||
"8 Shallots",
|
||||
"1 cm piece Turmeric Root",
|
||||
".5 Tsp Black Pepper",
|
||||
"2 Tsp Coriander",
|
||||
"4 Candlenuts",
|
||||
".5 Tsp Fennel",
|
||||
".5 Tsp Cumin",
|
||||
"1.5 cm piece Ginger Root",
|
||||
"3 cm piece Galangal",
|
||||
|
||||
"HEADER-Gravy",
|
||||
"1 Stalk Lemon Grass",
|
||||
"1 Cinnamon Stick",
|
||||
"1 Star Anise",
|
||||
"2 Daun Salam [Bay Leaves]",
|
||||
"100 ml Thick Coconut Milk",
|
||||
"300 ml Thin Coconut Milk",
|
||||
"1 Tbsp Tamarind Juice",
|
||||
"3 Lime Leaves",
|
||||
|
||||
"HEADER-Finishing",
|
||||
"3 Shallots",
|
||||
"Salt",
|
||||
"1 Tsp Brown Sugar",
|
||||
),
|
||||
instructions = listOf(
|
||||
|
||||
"HEADER-Marinade",
|
||||
"Grind all of the Marinade ingredients with [1 Tbsp] of oil into a paste.",
|
||||
"Marinate Protein for several hours, up to overnight.",
|
||||
|
||||
"HEADER-Curry",
|
||||
"Fry Shallots [3] in a wok until brown and crispy. Drain from Oil.",
|
||||
"Add Protein to Wok and Fry until Firm.",
|
||||
"Add the Lemon Grass [1 Stalk], Cinnamon Stick [1 Stick], Star Anise [1], Daun Salam [2], and Thin Coconut Milk [100 ml] and Simmer for 15-20 Minutes",
|
||||
"Add Tamarind Juice [1 Tbsp] and Thick Coconut Milk [300 ml]. Cook another 10-15 minutes. Halfway through, add Salt, Brown Sugar [1 Tsp], and Lime Leaves [3]",
|
||||
"Serve Garnished with Crispy Shallots",
|
||||
),
|
||||
tags = mapOf(
|
||||
"Indonesian" to TagType.CUISINE,
|
||||
"SEA" to TagType.CUISINE,
|
||||
"Savory" to TagType.FLAVOUR,
|
||||
"Creamy" to TagType.FLAVOUR,
|
||||
"Curry" to TagType.TECHNIQUE,
|
||||
"Vegan" to TagType.CUISINE,
|
||||
"Entree" to TagType.COURSE,
|
||||
),
|
||||
image = Res.drawable.opor_ayam,
|
||||
)
|
||||
)
|
42
shared/src/commonMain/kotlin/model/Europe/FrenchData.kt
Normal file
42
shared/src/commonMain/kotlin/model/Europe/FrenchData.kt
Normal file
|
@ -0,0 +1,42 @@
|
|||
package model.Europe
|
||||
|
||||
import model.Recipe
|
||||
import model.TagType
|
||||
import recipeappkmp.shared.generated.resources.Res
|
||||
import recipeappkmp.shared.generated.resources.cordon_bleu
|
||||
import kotlin.time.Duration
|
||||
|
||||
val frenchList = listOf(
|
||||
Recipe(
|
||||
title = "Chicken Cordon Bleu",
|
||||
description = "Chicken Wrapped with Ham and Cheese, Breaded, and Baked",
|
||||
prepTime = Duration.parse("20m"),
|
||||
cookTime = Duration.parse("40m"),
|
||||
servings = "4 Large Servings",
|
||||
ingredients = listOf(
|
||||
"4 Chicken Breasts",
|
||||
".25 Tsp Salt",
|
||||
".125 Tsp Pepper",
|
||||
"6 Slices Swiss Cheese",
|
||||
"4 Slices Cooked Ham",
|
||||
".5 Cup Bread Crumbs",
|
||||
),
|
||||
instructions = listOf(
|
||||
"Preheat oven to 350F.",
|
||||
"Pound Chicken to 1/4 inch. Season with Salt and Pepper.",
|
||||
"Place 1 Piece of Swiss and 1 Slice of Ham on each Breast.",
|
||||
"Wrap, securing with Toothpicks.",
|
||||
"Coat with Breadcrumbs, then place each Wrap onto a baking dish.",
|
||||
"Bake for 30-35 minutes, then top each Wrap with 1/2 a slice of Swiss Cheese, then return to the oven for another 5 minutes.",
|
||||
"Remove Toothpicks and Serve.",
|
||||
|
||||
),
|
||||
tags = mapOf(
|
||||
"French" to TagType.CUISINE,
|
||||
"Carnivorous" to TagType.CUISINE,
|
||||
"Entree" to TagType.COURSE,
|
||||
"Baked" to TagType.TECHNIQUE,
|
||||
),
|
||||
image = Res.drawable.cordon_bleu,
|
||||
)
|
||||
)
|
|
@ -8,6 +8,7 @@ import model.Asia.indianList
|
|||
import model.Asia.japaneseList
|
||||
import model.Asia.koreanList
|
||||
import model.Asia.seaList
|
||||
import model.Europe.frenchList
|
||||
import model.Europe.greekList
|
||||
import model.Europe.irishList
|
||||
import model.Europe.italianList
|
||||
|
@ -27,6 +28,7 @@ object Globe {
|
|||
|
||||
private object EuropeRecipes {
|
||||
|
||||
private val frenchRecipes = frenchList
|
||||
private val irishRecipes = irishList
|
||||
private val italianRecipes = italianList
|
||||
private val greekRecipes = greekList
|
||||
|
@ -34,7 +36,8 @@ private object EuropeRecipes {
|
|||
fun getAllRecipes() : List<Recipe> {
|
||||
return italianRecipes +
|
||||
greekRecipes +
|
||||
irishRecipes
|
||||
irishRecipes +
|
||||
frenchRecipes
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ fun BookShelf(
|
|||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(if (isLarge) 6 else 2),
|
||||
state = listState,
|
||||
modifier = Modifier.width(if (isLarge) 600.dp else 350.dp)
|
||||
modifier = Modifier.width(if (isLarge) 800.dp else 350.dp)
|
||||
) {
|
||||
items(list.size) { item ->
|
||||
val tag = list[item]
|
||||
|
|
|
@ -37,9 +37,7 @@ fun FilterCard(
|
|||
|
||||
Dialog(
|
||||
onDismissRequest = {
|
||||
|
||||
onDismissRequest(activeTags)
|
||||
|
||||
},
|
||||
) {
|
||||
Card {
|
||||
|
@ -55,7 +53,7 @@ fun FilterCard(
|
|||
}
|
||||
}
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Adaptive(minSize = 106.dp)
|
||||
columns = GridCells.Adaptive(minSize = 110.dp)
|
||||
) {
|
||||
items(tags) { tag ->
|
||||
val active = activeTags.contains(tag)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package view
|
||||
|
||||
import SortBy
|
||||
import androidx.compose.runtime.Composable
|
||||
import model.Globe
|
||||
import model.Recipe
|
||||
|
@ -13,7 +14,9 @@ fun getFilteredRecipeList(
|
|||
tags : List<String>,
|
||||
search : String,
|
||||
lockTag : String,
|
||||
sortBy: SortBy,
|
||||
returnAny: Boolean,
|
||||
reverse: Boolean,
|
||||
) : List<Recipe> {
|
||||
val items = getRecipeList()
|
||||
|
||||
|
@ -35,7 +38,14 @@ fun getFilteredRecipeList(
|
|||
recipes = recipes.filter { it.tags.contains(lockTag)}
|
||||
}
|
||||
|
||||
recipes = recipes.sortedBy { it.title }
|
||||
recipes = when (sortBy){
|
||||
SortBy.Name -> recipes.sortedBy { recipe -> recipe.title }
|
||||
SortBy.Time -> recipes.sortedBy { recipe -> (recipe.prepTime + recipe.cookTime)}
|
||||
SortBy.Ingredients -> recipes.sortedBy { recipe -> recipe.ingredients.count()}
|
||||
}
|
||||
|
||||
if(reverse)
|
||||
recipes = recipes.reversed()
|
||||
|
||||
return recipes
|
||||
}
|
||||
|
|
93
shared/src/commonMain/kotlin/view/MainMenuDropdown.kt
Normal file
93
shared/src/commonMain/kotlin/view/MainMenuDropdown.kt
Normal file
|
@ -0,0 +1,93 @@
|
|||
package view
|
||||
|
||||
import SortBy
|
||||
import Theme
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
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 androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun MainDropDown(
|
||||
isLarge: Boolean,
|
||||
andOr: Boolean,
|
||||
descending: Boolean,
|
||||
theme: Theme,
|
||||
sortBy: SortBy,
|
||||
onTag: () -> Unit,
|
||||
onSortBy: () -> Unit,
|
||||
onDesc: () -> Unit,
|
||||
onTheme: () -> Unit,
|
||||
onRandom: () -> Unit,
|
||||
onBack: () -> Unit,
|
||||
onClose: () -> Unit,
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(16.dp)
|
||||
) {
|
||||
IconButton(onClick = { expanded = !expanded }) {
|
||||
Icon(imageVector = Icons.Default.MoreVert, contentDescription = "More Options")
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(theme.name) },
|
||||
onClick = onTheme
|
||||
)
|
||||
|
||||
HorizontalDivider()
|
||||
|
||||
DropdownMenuItem(
|
||||
text = { Text("Filter Style: ".plus(if(andOr) "OR" else "AND")) },
|
||||
onClick = onTag
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = "Sort By: ".plus(sortBy.name)) },
|
||||
onClick = onSortBy
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = "Sort Order: ".plus(if(descending)"DESC" else "ASC")) },
|
||||
onClick = onDesc
|
||||
)
|
||||
|
||||
HorizontalDivider()
|
||||
|
||||
DropdownMenuItem(
|
||||
text = { Text("Random Filtered Recipe") },
|
||||
onClick = onRandom
|
||||
)
|
||||
if (isLarge) {
|
||||
|
||||
HorizontalDivider()
|
||||
|
||||
DropdownMenuItem(
|
||||
text = { Text("Go Back") },
|
||||
onClick = onBack
|
||||
)
|
||||
|
||||
DropdownMenuItem(
|
||||
text = { Text("Close app") },
|
||||
onClick = onClose
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
40
shared/src/commonMain/kotlin/view/RecipeScaleSlider.kt
Normal file
40
shared/src/commonMain/kotlin/view/RecipeScaleSlider.kt
Normal file
|
@ -0,0 +1,40 @@
|
|||
package view
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun RecipeScaleSlider(
|
||||
sliderPosition: Float,
|
||||
steps: Int,
|
||||
rangeStart: Float,
|
||||
rangeEnd: Float,
|
||||
reduce: Boolean,
|
||||
onClick: () -> Unit,
|
||||
onChange: (Float) -> Unit) {
|
||||
|
||||
Column {
|
||||
Slider(
|
||||
value = sliderPosition,
|
||||
steps = steps,
|
||||
valueRange = rangeStart..rangeEnd,
|
||||
onValueChange = { onChange(it) },
|
||||
modifier = Modifier.padding(start = 16.dp, end = 16.dp)
|
||||
)
|
||||
Row {
|
||||
Text(text = sliderPosition.toString().plus("x Servings"))
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Button(onClick = onClick) {
|
||||
Text(text = if (reduce) "Reducing" else "Increasing")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue