diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 97e9628..586c1f5 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -58,6 +58,8 @@ kotlin { implementation(libs.androidx.lifecycle.runtime.compose) implementation(libs.material3) implementation(libs.androidx.navigation.compose) + implementation(libs.multiplatform.settings) + implementation(libs.multiplatform.settings.no.arg) } desktopMain.dependencies { implementation(compose.desktop.currentOs) diff --git a/composeApp/src/androidMain/kotlin/com/menagerie/bakers/isDebug.android.kt b/composeApp/src/androidMain/kotlin/com/menagerie/bakers/isDebug.android.kt new file mode 100644 index 0000000..2c9b113 --- /dev/null +++ b/composeApp/src/androidMain/kotlin/com/menagerie/bakers/isDebug.android.kt @@ -0,0 +1,6 @@ +package com.menagerie.bakers + +import com.russhwolf.settings.BuildConfig + +actual val isDebug: Boolean + get() = BuildConfig.DEBUG \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/com/menagerie/bakers/util/rememberClipboardController.android.kt b/composeApp/src/androidMain/kotlin/com/menagerie/bakers/util/rememberClipboardController.android.kt new file mode 100644 index 0000000..f0f915b --- /dev/null +++ b/composeApp/src/androidMain/kotlin/com/menagerie/bakers/util/rememberClipboardController.android.kt @@ -0,0 +1,22 @@ +package com.menagerie.bakers.util + +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext + +class AndroidClipboardController(private val context: Context) : ClipboardController { + override fun copyToClipboard(text: String) { + val clipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + val clip = ClipData.newPlainText("Copied Text", text) + clipboardManager.setPrimaryClip(clip) + } +} + +@Composable +actual fun rememberClipboardController(): ClipboardController { + val context = LocalContext.current + return remember(context) { AndroidClipboardController(context) } +} \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/com/menagerie/bakers/view/Settings.android.kt b/composeApp/src/androidMain/kotlin/com/menagerie/bakers/view/Settings.android.kt new file mode 100644 index 0000000..34cc637 --- /dev/null +++ b/composeApp/src/androidMain/kotlin/com/menagerie/bakers/view/Settings.android.kt @@ -0,0 +1,53 @@ +package com.menagerie.bakers.view + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.menagerie.bakers.SortBy +import com.menagerie.bakers.Theme +import com.menagerie.bakers.model.TTT +import com.menagerie.bakers.view.util.MainDropDown + +@Composable +actual fun SettingsMenu( + theme: Theme, + onTheme: () -> Unit, + animate: Boolean, + onAnim: () -> Unit, + helpUs: Boolean, + onHelpToggle: (Boolean) -> Unit, + ttt: TTT, + onTTTToggle: () -> Unit, + andOr: Boolean, + onAndOr: () -> Unit, + sortBy: SortBy, + onSortToggle: () -> Unit, + descending: Boolean, + onDesc: () -> Unit, + onRandom: () -> Unit, + onBack: () -> Unit, + onClear: () -> Unit, + discreet: Boolean, + onDiscreet: () -> Unit, +) { + MainDropDown( + modifier = Modifier, + andOr = andOr, + descending = descending, + theme = theme, + sortBy = sortBy, + helpUs = helpUs, + animate = animate, + ttt = ttt, + onHelp = onHelpToggle, + onTTTToggle = onTTTToggle, + onTag = onAndOr, + onSortBy = onSortToggle, + onDesc = onDesc, + onTheme = onTheme, + onAnim = onAnim, + onRandom = onRandom, + onBack = {}, + onDiscreet = onDiscreet, + discreet = discreet, + ) { } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/composeResources/drawable/almond_chicken.jpg b/composeApp/src/commonMain/composeResources/drawable/almond_chicken.jpg new file mode 100644 index 0000000..1ba9994 Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/almond_chicken.jpg differ diff --git a/composeApp/src/commonMain/composeResources/drawable/auto_mode.svg b/composeApp/src/commonMain/composeResources/drawable/auto_mode.svg new file mode 100644 index 0000000..cbc4c4e --- /dev/null +++ b/composeApp/src/commonMain/composeResources/drawable/auto_mode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/composeApp/src/commonMain/composeResources/drawable/butter_chicken.jpg b/composeApp/src/commonMain/composeResources/drawable/butter_chicken.jpg new file mode 100644 index 0000000..dcf7582 Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/butter_chicken.jpg differ diff --git a/composeApp/src/commonMain/composeResources/drawable/chicken_65.jpg b/composeApp/src/commonMain/composeResources/drawable/chicken_65.jpg new file mode 100644 index 0000000..41bb6dc Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/chicken_65.jpg differ diff --git a/composeApp/src/commonMain/composeResources/drawable/dark_mode.svg b/composeApp/src/commonMain/composeResources/drawable/dark_mode.svg new file mode 100644 index 0000000..8353210 --- /dev/null +++ b/composeApp/src/commonMain/composeResources/drawable/dark_mode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/composeApp/src/commonMain/composeResources/drawable/gai_yang.jpg b/composeApp/src/commonMain/composeResources/drawable/gai_yang.jpg new file mode 100644 index 0000000..f87109b Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/gai_yang.jpg differ diff --git a/composeApp/src/commonMain/composeResources/drawable/greek_chicken.jpg b/composeApp/src/commonMain/composeResources/drawable/greek_chicken.jpg new file mode 100644 index 0000000..dfe9c7f Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/greek_chicken.jpg differ diff --git a/composeApp/src/commonMain/composeResources/drawable/history.svg b/composeApp/src/commonMain/composeResources/drawable/history.svg new file mode 100644 index 0000000..906fae8 --- /dev/null +++ b/composeApp/src/commonMain/composeResources/drawable/history.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/composeApp/src/commonMain/composeResources/drawable/history_android.xml b/composeApp/src/commonMain/composeResources/drawable/history_android.xml new file mode 100644 index 0000000..1a9c4c6 --- /dev/null +++ b/composeApp/src/commonMain/composeResources/drawable/history_android.xml @@ -0,0 +1,9 @@ + + + diff --git a/composeApp/src/commonMain/composeResources/drawable/light_mode.svg b/composeApp/src/commonMain/composeResources/drawable/light_mode.svg new file mode 100644 index 0000000..f7ddbb4 --- /dev/null +++ b/composeApp/src/commonMain/composeResources/drawable/light_mode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/composeApp/src/commonMain/composeResources/drawable/orange_chicken.jpg b/composeApp/src/commonMain/composeResources/drawable/orange_chicken.jpg index ea38bfe..98048cb 100644 Binary files a/composeApp/src/commonMain/composeResources/drawable/orange_chicken.jpg and b/composeApp/src/commonMain/composeResources/drawable/orange_chicken.jpg differ diff --git a/composeApp/src/commonMain/composeResources/drawable/paprikash.jpg b/composeApp/src/commonMain/composeResources/drawable/paprikash.jpg new file mode 100644 index 0000000..691b9d4 Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/paprikash.jpg differ diff --git a/composeApp/src/commonMain/composeResources/drawable/shuffle.svg b/composeApp/src/commonMain/composeResources/drawable/shuffle.svg new file mode 100644 index 0000000..86b5bb0 --- /dev/null +++ b/composeApp/src/commonMain/composeResources/drawable/shuffle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/App.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/App.kt index f408cbc..ce9c4a1 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/App.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/App.kt @@ -7,10 +7,15 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width 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.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.automirrored.filled.ExitToApp +import androidx.compose.material.icons.filled.Settings import androidx.compose.material3.Button import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -31,7 +36,20 @@ import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument import bakersmenagerie.composeapp.generated.resources.Res +import bakersmenagerie.composeapp.generated.resources.auto_mode +import bakersmenagerie.composeapp.generated.resources.dark_mode +import bakersmenagerie.composeapp.generated.resources.history +import bakersmenagerie.composeapp.generated.resources.history_android +import bakersmenagerie.composeapp.generated.resources.light_mode +import bakersmenagerie.composeapp.generated.resources.shuffle import bakersmenagerie.composeapp.generated.resources.tune +import com.menagerie.bakers.SettingsKeys.ANIM_KEY +import com.menagerie.bakers.SettingsKeys.AON_KEY +import com.menagerie.bakers.SettingsKeys.DESC_KEY +import com.menagerie.bakers.SettingsKeys.DISCREET_KEY +import com.menagerie.bakers.SettingsKeys.SORT_BY_KEY +import com.menagerie.bakers.SettingsKeys.THEME_KEY +import com.menagerie.bakers.SettingsKeys.TTT_KEY import com.menagerie.bakers.ui.theme.MainTheme import com.menagerie.bakers.view.details.RecipeDetails import org.jetbrains.compose.resources.painterResource @@ -40,11 +58,13 @@ import com.menagerie.bakers.view.BookShelf import com.menagerie.bakers.view.util.FilterCard import com.menagerie.bakers.view.HomeScreen import com.menagerie.bakers.view.util.InputFieldState -import com.menagerie.bakers.view.util.MainDropDown import com.menagerie.bakers.view.util.getFilteredRecipeList import com.menagerie.bakers.view.util.getRecipeList import com.menagerie.bakers.model.Recipe +import com.menagerie.bakers.model.TTT import com.menagerie.bakers.model.TagType +import com.menagerie.bakers.view.SettingsMenu +import com.russhwolf.settings.Settings enum class Theme { @@ -60,7 +80,10 @@ enum class SortBy { } enum class RecipeAppScreen { - List, Details, + List, + History, + Details, + DetailHistory, } @OptIn(ExperimentalSharedTransitionApi::class) @@ -69,24 +92,23 @@ fun App( onClose: () -> Unit = {} ) { + //Grab an instance of the Settings object + val settings by remember { mutableStateOf(Settings()) } + + //used to navigate through the different compose screens val navController = rememberNavController() - var theme by remember { mutableStateOf(Theme.Auto) } - var sortBy by remember { mutableStateOf(SortBy.Name) } - val onThemeToggle = { - theme = when (theme) { - Theme.Auto -> Theme.Light - Theme.Light -> Theme.Dark - Theme.Dark -> Theme.Auto - } - } + //Grab and set Theme from Settings + val themeSetting by remember { mutableStateOf(settings.getStringOrNull(THEME_KEY)) } + var theme by remember { + mutableStateOf( - val onSortToggle = { - sortBy = when (sortBy) { - SortBy.Name -> SortBy.Time - SortBy.Time -> SortBy.Ingredients - SortBy.Ingredients -> SortBy.Name - } + when (themeSetting) { + Theme.Dark.name -> Theme.Dark + Theme.Light.name -> Theme.Light + else -> Theme.Auto + } + ) } val isDarkTheme: Boolean? = when (theme) { @@ -95,23 +117,119 @@ fun App( Theme.Auto -> null } + val onThemeToggle = { + theme = when (theme) { + Theme.Auto -> Theme.Light + Theme.Light -> Theme.Dark + Theme.Dark -> Theme.Auto + } + + when (theme) { + Theme.Auto -> settings.putString(THEME_KEY, Theme.Auto.name) + Theme.Light -> settings.putString(THEME_KEY, Theme.Light.name) + Theme.Dark -> settings.putString(THEME_KEY, Theme.Dark.name) + } + } + // END Theme + + + // Grab and set Sort Order from Settings + val sortBySetting by remember { mutableStateOf(settings.getStringOrNull(SORT_BY_KEY)) } + var sortBy by remember { + mutableStateOf( + when (sortBySetting) { + + SortBy.Name.name -> SortBy.Name + SortBy.Time.name -> SortBy.Time + SortBy.Ingredients.name -> SortBy.Ingredients + else -> SortBy.Name + } + ) + } + + val onSortToggle = { + sortBy = when (sortBy) { + SortBy.Name -> SortBy.Time + SortBy.Time -> SortBy.Ingredients + SortBy.Ingredients -> SortBy.Name + } + + when (sortBy) { + SortBy.Name -> settings.putString(SORT_BY_KEY, SortBy.Name.name) + SortBy.Time -> settings.putString(SORT_BY_KEY, SortBy.Time.name) + SortBy.Ingredients -> settings.putString(SORT_BY_KEY, SortBy.Ingredients.name) + } + } + // END SortBy + + + //Grab and set TTT Level from Settings + val tttSetting by remember { mutableStateOf(settings.getString(TTT_KEY, TTT.TESTED.name)) } + var tttBy by remember { + mutableStateOf( + when (tttSetting) { + TTT.TRIED.name -> TTT.TRIED + TTT.TESTED.name -> TTT.TESTED + TTT.TRUE.name -> TTT.TRUE + else -> TTT.TESTED + } + ) + } + + val onTTTToggle = { + tttBy = when (tttBy) { + TTT.TRIED -> TTT.TESTED + TTT.TESTED -> TTT.TRUE + TTT.TRUE -> TTT.TRIED + } + + when (tttBy) { + TTT.TRIED -> settings.putString(TTT_KEY, TTT.TRIED.name) + TTT.TESTED -> settings.putString(TTT_KEY, TTT.TESTED.name) + TTT.TRUE -> settings.putString(TTT_KEY, TTT.TRUE.name) + } + } + // END TTT + + //Grab and set And/Or/Not from Settings + val returnSetting by remember { mutableStateOf(settings.getBoolean(AON_KEY, false)) } + var returnAnyMatch by remember { mutableStateOf(returnSetting) } + //END AON + + //Grab and set Display Order from Settings + val descSetting by remember { mutableStateOf(settings.getBoolean(DESC_KEY, false)) } + var descending by remember { mutableStateOf(descSetting) } + //END Display Order + + //Grab and set Animation State from Settings + val animSetting by remember { mutableStateOf(settings.getBoolean(ANIM_KEY, true)) } + var animate by remember { mutableStateOf(animSetting) } + + val discreetSetting by remember {mutableStateOf(settings.getBoolean(DISCREET_KEY, false))} + var discreet by remember { mutableStateOf(discreetSetting) } + MainTheme(useDarkTheme = isDarkTheme ?: isSystemInDarkTheme()) { - var show by remember { mutableStateOf(false) } + + + var showFilter by remember { mutableStateOf(false) } + var menuBar by remember { mutableStateOf(false) } var searchBar by remember { mutableStateOf(false) } + var history by remember { mutableStateOf(false) } var search by remember { mutableStateOf("") } val tags = remember { mutableStateListOf() } val recipeTags by remember { mutableStateOf(mutableMapOf()) } var book by remember { mutableStateOf("") } - var returnAnyMatch by remember { mutableStateOf(false) } - var descending by remember { mutableStateOf(false) } val remove = remember { mutableStateListOf() } var helpUs by remember { mutableStateOf(false) } + val histogram = remember { mutableListOf() } + val filteredItems = getFilteredRecipeList( tags = tags, search = search, lockTag = book, sortBy = sortBy, + tttBy = tttBy, showMissing = helpUs, returnAny = returnAnyMatch, reverse = descending, @@ -126,29 +244,28 @@ fun App( } } - if (show) { + if (showFilter) { FilterCard( recipeTags = recipeTags, activeTags = tags, ) { - if(it.isEmpty()) - { + if (it.isEmpty()) { tags.clear() } - for(item in it) - if(tags.contains(item).not()) + for (item in it) + if (tags.contains(item).not()) tags.add(item) remove.clear() - for(item in tags) - if(it.contains(item).not()) + for (item in tags) + if (it.contains(item).not()) remove.add(item) tags.removeAll(remove) - show = false + showFilter = false } } @@ -160,64 +277,298 @@ fun App( currentRecipe = filteredItems.first() Scaffold { - Column { - if (searchBar) { - Row { - MainDropDown( - modifier = Modifier.align(Alignment.CenterVertically), - andOr = returnAnyMatch, - theme = theme, - sortBy = sortBy, - helpUs = helpUs, - descending = descending, - onClose = onClose, - onBack = {navController.navigateUp()}, - onTag = {returnAnyMatch = !returnAnyMatch}, - onSortBy = { onSortToggle.invoke() }, - onDesc = {descending = !descending}, - onTheme = { onThemeToggle.invoke() }, - onHelp = {helpUs = !helpUs}, - onRandom = { - currentRecipe = filteredItems.random() - navController.navigate(RecipeAppScreen.Details.name.plus("/${currentRecipe.title}")) - }, - ) - Spacer(modifier = Modifier.weight(1f)) - InputFieldState( - value = search, - label = "Search ".plus(book), - modifier = Modifier - .width(if (DisplayManager.size == Size.Large || DisplayManager.orientation == Orientation.Landscape) 400.dp else 250.dp) - .align(Alignment.CenterVertically) - ) { - search = it - } + Column { + when (DisplayManager.device) { + Device.Android -> + if (menuBar) + Column { + Row { + SettingsMenu( + andOr = returnAnyMatch, + theme = theme, + sortBy = sortBy, + ttt = tttBy, + helpUs = helpUs, + descending = descending, + animate = animate, + discreet = discreet, + onDiscreet = { + discreet = !discreet + settings.putBoolean(DISCREET_KEY, discreet) + }, + onAndOr = { + returnAnyMatch = !returnAnyMatch + settings.putBoolean(AON_KEY, returnAnyMatch) + }, + onSortToggle = { onSortToggle.invoke() }, + onDesc = { + descending = !descending + settings.putBoolean(DESC_KEY, descending) + }, + onAnim = { + animate = !animate + settings.putBoolean(ANIM_KEY, animate) + }, + onTheme = { onThemeToggle.invoke() }, + onHelpToggle = { helpUs = !helpUs }, + onTTTToggle = { onTTTToggle.invoke() }, + onRandom = { + currentRecipe = filteredItems.random() + navController.navigate( + RecipeAppScreen.Details.name.plus( + "/${currentRecipe.title}" + ) + ) + }, + onBack = {}, + onClear = {settings.clear()} + ) - if(DisplayManager.orientation == Orientation.Portrait) - Spacer(modifier = Modifier.weight(1f)) + Spacer(modifier = Modifier.weight(1f)) - IconButton(modifier = Modifier.align(Alignment.CenterVertically), onClick = { show = true }, - ) { - Icon(painter = - painterResource(Res.drawable.tune), "Filter") - } + if(searchBar) + InputFieldState( + value = search, + label = "Search ".plus(book), + modifier = Modifier + .width(if (DisplayManager.size == Size.Large || DisplayManager.orientation == Orientation.Landscape) 400.dp else 250.dp) + .align(Alignment.CenterVertically) + ) { + search = it + } - } - val listState = rememberLazyGridState() - LazyVerticalGrid( - state = listState, columns = GridCells.Adaptive(minSize = 125.dp) - ) - { - items(tags.size) { - Button(onClick = { tags.remove(tags[it]) }) { - Text(text = tags[it]) + if (DisplayManager.orientation == Orientation.Portrait) + Spacer(modifier = Modifier.weight(1f)) + + if(histogram.isNotEmpty() && searchBar) + { + IconButton( + onClick = { + navController.navigate(RecipeAppScreen.History.name) + }, + ) { + Icon(painter = painterResource(Res.drawable.history_android), "History") + } + } + + if(searchBar) + IconButton( + onClick = { showFilter = true }, + ) { + Icon( + painter = painterResource(Res.drawable.tune), "Filter" + ) + } + } + val listState = rememberLazyGridState() + + if(searchBar) + LazyVerticalGrid( + state = listState, + columns = GridCells.Adaptive(minSize = 125.dp) + ) + { + items(tags.size) { + Button(onClick = { tags.remove(tags[it]) }) { + Text(text = tags[it]) + } + } + } + } + + Device.Desktop -> + if (menuBar) + Column { + Row { + IconButton( + onClick = { navController.popBackStack() }, + content = { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "Back" + ) + } + ) + IconButton( + onClick = { navController.navigate("Settings") }, + content = { + Icon( + imageVector = Icons.Default.Settings, + contentDescription = "" + ) + } + ) + IconButton( + onClick = {onThemeToggle.invoke()}, + content = { + Icon( + painter = painterResource( + when(theme) { + Theme.Auto -> Res.drawable.auto_mode + Theme.Light -> Res.drawable.light_mode + Theme.Dark -> Res.drawable.dark_mode + } + ), + contentDescription = "theme" + ) + } + ) + + if(history) + IconButton( + onClick = { + currentRecipe = histogram.random() + navController.navigate( + RecipeAppScreen.DetailHistory.name.plus( + "/${currentRecipe.title}" + ) + ) + }, + content = { + Icon( + painter = painterResource(Res.drawable.shuffle), + contentDescription = "random" + ) + } + ) + else + IconButton( + onClick = { + currentRecipe = filteredItems.random() + navController.navigate( + RecipeAppScreen.Details.name.plus( + "/${currentRecipe.title}" + ) + ) + }, + content = { + Icon( + painter = painterResource(Res.drawable.shuffle), + contentDescription = "random" + ) + } + ) + + Spacer(modifier = Modifier.weight(1f)) + + if(searchBar) + InputFieldState( + value = search, + label = "Search ".plus(book), + modifier = Modifier + .width(if (DisplayManager.size == Size.Large || DisplayManager.orientation == Orientation.Landscape) 400.dp else 250.dp) + .align(Alignment.CenterVertically) + ) { + search = it + } + + if (DisplayManager.orientation == Orientation.Portrait) + Spacer(modifier = Modifier.weight(1f)) + + if(histogram.isNotEmpty() && searchBar) + { + IconButton( + onClick = { + navController.navigate(RecipeAppScreen.History.name) + }, + modifier = Modifier.align(Alignment.CenterVertically).padding(bottom = 8.dp) + ) { + Icon(painter = painterResource(Res.drawable.history), "History") + } + } + + if(searchBar) + IconButton( + onClick = { showFilter = true }, + modifier = Modifier.align(Alignment.CenterVertically).padding(bottom = 8.dp) + ) { + Icon( + painter = painterResource(Res.drawable.tune), "Filter", + ) + } + IconButton( + onClick = onClose, + modifier = Modifier.align(Alignment.CenterVertically).padding(bottom = 8.dp) + ) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ExitToApp, "Close", + ) + } + } + if(searchBar) + Row { + Spacer(modifier = Modifier.weight(1f)) + if (DisplayManager.orientation == Orientation.Landscape && (tags.isNotEmpty() || search.isNotEmpty() || book.isNotEmpty())) + Text( + text = "Showing ".plus(filteredItems.size) + .plus(" out of ") + .plus(recipeCount).plus(" recipes"), + ) + } + val listState = rememberLazyGridState() + if(searchBar) + LazyVerticalGrid( + state = listState, + columns = GridCells.Adaptive(minSize = 125.dp) + ) + { + items(tags.size) { + Button(onClick = { tags.remove(tags[it]) }) { + Text(text = tags[it]) + } + } + } + } + + Device.Web -> + if(menuBar) + Column { + Row { + IconButton( + onClick = { navController.popBackStack() }, + content = { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "Back" + ) + } + ) + IconButton( + onClick = { + currentRecipe = filteredItems.random() + navController.navigate( + RecipeAppScreen.Details.name.plus( + "/${currentRecipe.title}" + ) + ) + }, + content = { + Icon( + painter = painterResource(Res.drawable.shuffle), + contentDescription = "random" + ) + } + ) + IconButton( + onClick = {onThemeToggle.invoke()}, + content = { + Icon( + painter = painterResource( + when(theme) { + Theme.Auto -> Res.drawable.auto_mode + Theme.Light -> Res.drawable.light_mode + Theme.Dark -> Res.drawable.dark_mode + } + ), + contentDescription = "theme" + ) + } + ) } } - } - if(DisplayManager.orientation == Orientation.Landscape && (tags.isNotEmpty() || search.isNotEmpty() || book.isNotEmpty())) - Text("Showing ".plus(filteredItems.size).plus( " out of ").plus(recipeCount).plus(" recipes")) } + SharedTransitionLayout { NavHost( navController = navController, @@ -226,11 +577,11 @@ fun App( ) { composable(route = "Home") { - searchBar = false + menuBar = false HomeScreen( onClose = onClose, onGo = { - if(DisplayManager.device == Device.Web) + if (DisplayManager.device == Device.Web) navController.navigate(RecipeAppScreen.List.name) else navController.navigate("BookShelf") @@ -252,7 +603,8 @@ fun App( } } - searchBar = false + menuBar = false + history = false BookShelf( tags = shelfTags, onClick = { lockedTag -> @@ -261,44 +613,149 @@ fun App( search = "" book = lockedTag - if(book == "SURPRISE") { + if (book == "SURPRISE") { currentRecipe = filteredItems.random() navController.navigate(RecipeAppScreen.Details.name.plus("/${currentRecipe.title}")) - }else{ - navController.navigate(RecipeAppScreen.List.name) } + } else { + navController.navigate(RecipeAppScreen.List.name) + } } ) } composable(route = RecipeAppScreen.List.name) { - if(DisplayManager.device != Device.Web) - searchBar = true + menuBar = true + searchBar = true + history = false RecipesListScreen( items = filteredItems, + animate = animate, onClick = { recipe -> currentRecipe = recipe navController.navigate(RecipeAppScreen.Details.name.plus("/${recipe.title}")) }) } - composable(route = RecipeAppScreen.Details.name.plus("/{recipe}"), - arguments = listOf(navArgument("recipe"){ + + composable(route = RecipeAppScreen.History.name) { + menuBar = true + searchBar = false + history = true + + RecipesListScreen( + items = histogram, + animate = animate, + onClick = { recipe -> + currentRecipe = recipe + navController.navigate(RecipeAppScreen.DetailHistory.name.plus("/${recipe.title}")) + }) + } + + composable( + route = RecipeAppScreen.Details.name.plus("/{recipe}"), + arguments = listOf(navArgument("recipe") { type = NavType.StringType }) ) { args -> - searchBar = false - getRecipeList().find { it.title == args.arguments?.getString("recipe") }?.let { it1 -> - RecipeDetails( - navController = navController, - recipe = it1, - multipleRecipes = filteredItems.size > 1, - goForward = { + menuBar = false + history = false + getRecipeList().find { it.title == args.arguments?.getString("recipe") } + ?.let { it1 -> - val index = filteredItems.indexOf(it1) - val recipe = if(index < filteredItems.size - 1) filteredItems[index+1] else filteredItems.first() + if(histogram.contains(it1).not()) + histogram.add(it1) - navController.navigate(RecipeAppScreen.Details.name.plus("/${recipe.title}")) - }) - } + RecipeDetails( + navController = navController, + recipe = it1, + animate = animate, + discreet = discreet, + multipleRecipes = filteredItems.size > 1, + navTo = RecipeAppScreen.List.name, + goForward = { + + val index = filteredItems.indexOf(it1) + val recipe = + if (index < filteredItems.size - 1) filteredItems[index + 1] else filteredItems.first() + + navController.navigate( + RecipeAppScreen.Details.name.plus( + "/${recipe.title}" + ) + ) + }) + } + } + composable( + route = RecipeAppScreen.DetailHistory.name.plus("/{recipe}"), + arguments = listOf(navArgument("recipe") { + type = NavType.StringType + }) + ) { args -> + menuBar = false + history = true + getRecipeList().find { it.title == args.arguments?.getString("recipe") } + ?.let { it1 -> + + RecipeDetails( + navController = navController, + recipe = it1, + animate = animate, + discreet = discreet, + multipleRecipes = histogram.size > 1, + navTo = RecipeAppScreen.History.name, + goForward = { + + val index = histogram.indexOf(it1) + val recipe = + if (index < histogram.size - 1) histogram[index + 1] else histogram.first() + + navController.navigate( + RecipeAppScreen.DetailHistory.name.plus( + "/${recipe.title}" + ) + ) + }) + } + } + + composable( + route = "Settings" + ) { + menuBar = false + history = false + SettingsMenu( + theme = theme, + onTheme = { onThemeToggle.invoke() }, + animate = animate, + onAnim = { + animate = !animate + settings.putBoolean(ANIM_KEY, animate) + }, + helpUs = helpUs, + onHelpToggle = { helpUs = !helpUs }, + ttt = tttBy, + onTTTToggle = { onTTTToggle.invoke() }, + andOr = returnAnyMatch, + onAndOr = { + returnAnyMatch = !returnAnyMatch + settings.putBoolean(AON_KEY, returnAnyMatch) + }, + sortBy = sortBy, + onSortToggle = { onSortToggle.invoke() }, + descending = descending, + onDesc = { + descending = !descending + settings.putBoolean(DESC_KEY, descending) + }, + onRandom = {}, + onBack = { navController.popBackStack() }, + onClear = {settings.clear()}, + discreet = discreet, + onDiscreet = { + discreet = !discreet + settings.putBoolean(DISCREET_KEY, discreet) + } + ) } } } diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/SettingsKeys.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/SettingsKeys.kt new file mode 100644 index 0000000..cd2a3fc --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/SettingsKeys.kt @@ -0,0 +1,11 @@ +package com.menagerie.bakers + +object SettingsKeys { + const val THEME_KEY = "theme" + const val SORT_BY_KEY = "sortBy" + const val TTT_KEY = "ttt" + const val AON_KEY = "aon" + const val DESC_KEY = "desc" + const val ANIM_KEY = "animate" + const val DISCREET_KEY = "discreet" +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/isDebug.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/isDebug.kt new file mode 100644 index 0000000..d73a4da --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/isDebug.kt @@ -0,0 +1,3 @@ +package com.menagerie.bakers + +expect val isDebug: Boolean \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/Recipe.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/Recipe.kt index 3c24e19..babd72f 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/Recipe.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/Recipe.kt @@ -14,6 +14,13 @@ enum class TagType { PROTEIN, } +//For internal use and display purposes only (see get Recipe) +enum class TTT { + TRIED, //We've picked up a new recipe! + TESTED, //We've made this recipe several times + TRUE, //We've made this recipe a dozen times +} + data class Recipe( val title: String = "PLACEHOLDER", val description: String = "PLEASE DON'T FORGET ABOUT ME", @@ -26,5 +33,8 @@ data class Recipe( val image: DrawableResource = Res.drawable._10_strawberries, val linkedRecipes : List = listOf(), var bgColor: Color = Color.White, + var favourite: Boolean = false, + var iMadeThis: Boolean = false, + var ttt: TTT = TTT.TRIED ) diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/Tips.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/Tips.kt index ec6f0f3..0309f9b 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/Tips.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/Tips.kt @@ -1,8 +1,12 @@ package com.menagerie.bakers.model val tipsTricksAndHelpers = listOf( - "REMINDER-All Protein Cook Times refer to their Original Protein (usually Chicken).", + "REMINDER-All Protein Cook Times and Marinade Times refer to their Original Protein (usually Chicken).", + "REMINDER-When Marinading Tofu or Paneer, be sure not to leave them for too long, or they will fall apart in the marinade. (Overnight Marinades are not recommended).", "TIP-Long Term Marinades can be done overnight, but most can also be done the morning of!", + "TIP-A mesh strainer or colander can help with shaking off access coatings.", + "TIP-Parsley is a great substitute for Cilantro!", + "TRICK-Use Tongs to transfer long Pasta straight from the pot to the sauce; the extra pasta water will help the sauce stick!", ) @@ -24,6 +28,7 @@ val imperialToMetric = listOf( //TODO : Regex for converting F to C and replacing in text, just needs a direction and the formula °C = (°F − 32) × 5/9 or °F = (°C × 9/5) + 32 // uses a lookahead to find numbers in the instructions set with F or C as a suffix, replace with formula output and alternate suffix + //Temperature //fun fToC() {} diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/africa/Kenyan.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/africa/Kenyan.kt index 57429cc..cf6d864 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/africa/Kenyan.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/africa/Kenyan.kt @@ -5,6 +5,7 @@ import com.menagerie.bakers.model.TagType import kotlin.time.Duration import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources.kuku_no_nazi +import com.menagerie.bakers.model.TTT val kenyanList = listOf( Recipe( @@ -14,36 +15,39 @@ val kenyanList = listOf( cookTime = Duration.parse("45m"), servings = "Serves 4-6", ingredients = listOf( - "3 cloves Garlic", + "3 Cloves Garlic", "2 Lemons, divided", "2.5 Tsp Diamond Crystal or 1.25 Tsp Morton Kosher Salt, divided, plus more", "0.25 Tsp Kashmiri Chile Powder", - "2-3 lb. Skinless, Boneless Chicken Thighs (about 8 large)", - "1 medium Onion", - "1 plum Tomato", - "1-2 Green Thai Chiles", - "0.25 cup Cilantro Leaves with tender stems, plus more for serving", + "2.5 lbs Chicken Thighs, Skinless, Boneless", + "1 medium Onions", + "1 Roma Tomatoes", + "2 Green Thai Chiles", + "0.25 Cups Cilantro Leaves", "2 Tbsp Extra-Virgin Olive Oil", "0.25 Tsp Ground Coriander", "0.25 Tsp Ground Cumin", "0.125 Tsp Ground Turmeric", - "1 13.5-oz. can Unsweetened Coconut Milk", - "0.25 cup Heavy Cream", + "13.5 Oz Unsweetened Coconut Milk", + "0.25 Cups Heavy Cream", "Basmati Rice and/or Crusty Bread (for serving)" ), instructions = listOf( - "Finely grate Garlic [3 cloves] into a large bowl with a Microplane. Cut 1 Lemon in half and squeeze juice through your hand or a fine-mesh sieve into bowl; discard seeds. Mix in Salt [1 Tsp Diamond Crystal or 0.5 Tsp Morton] and Kashmiri Chile Powder [0.25 Tsp]. Add Chicken Thighs [2-3 lb] and toss to evenly coat. Cover bowl and let sit at room temperature 30 minutes.", - "Meanwhile, make the curry base. Coarsely chop Onion [1], Tomato [1], Green Thai Chiles [1-2], and Cilantro Leaves [0.25 cup]. Transfer to a blender or food processor and blend or process until smooth.", + "HEADER-Marinade", + "Finely grate Garlic [3 Cloves]. Cut Lemons [1] in half and squeeze juice through a fine-mesh sieve. Mix in Salt [1 Tsp] and Kashmiri Chile Powder [0.25 Tsp]. ", + "Add Chicken Thighs [2.5 lb] and toss to evenly coat. Cover bowl and let sit at room temperature 30 minutes.", - "Heat broiler. Heat Extra-Virgin Olive Oil [2 Tbsp] in a high-sided skillet or large pot over medium. Add Ground Coriander [0.25 Tsp], Ground Cumin [0.25 Tsp], and Ground Turmeric [0.125 Tsp]. Cook, stirring, until fragrant, about 1 minute. Pour in purée and add Salt [1.5 Tsp Diamond Crystal or 0.75 Tsp Morton]. Stir to combine and cook, stirring occasionally, until raw onion smell subsides and curry is paste-like in consistency, 15–20 minutes.", + "HEADER-Curry", + "Coarsely chop Onions [1], Tomatoes [1], Green Thai Chiles [2], and Cilantro Leaves [0.25 Cups]. Transfer to a blender or food processor and blend or process until smooth.", + "Heat broiler. Heat Extra-Virgin Olive Oil [2 Tbsp] in a high-sided skillet over medium. Add Ground Coriander [0.25 Tsp], Ground Cumin [0.25 Tsp], and Ground Turmeric [0.125 Tsp]. Cook, stirring, until fragrant, about 1 minute.", + "Pour in purée and add Salt [1.5 Tsp Diamond Crystal or 0.75 Tsp Morton]. Stir to combine and cook, stirring occasionally, until raw onion smell subsides and curry is paste-like in consistency, 15–20 minutes.", + "HEADER-Chicken", "Arrange Chicken on a foil-lined rimmed baking sheet and broil until cooked through, charred in spots, and a thermometer inserted into the thickest parts registers 165°F (74°C), 17–20 minutes.", - - "While the Chicken is cooking, shake Coconut Milk [1 13.5-oz. can] to ensure coconut cream is incorporated, then add Coconut Milk to curry and stir well to combine. Curry should be pale yellow. Bring to a gentle simmer and cook until warm and slightly thickened, 5–10 minutes.", - - "Once Chicken is finished, add Chicken and any juices accumulated on baking sheet to curry and reduce heat to low; mix well to combine. Stirring constantly to prevent curry from breaking, dribble in Heavy Cream [0.25 cup]. Taste and season with more Salt if needed.", - + "While the Chicken is cooking, shake Coconut Milk [1 13.5-oz. can] to ensure coconut cream is incorporated, then add Coconut Milk to curry and stir well to combine. Curry should be pale yellow.", + "Bring to a gentle simmer and cook until warm and slightly thickened, 5–10 minutes.", + "Once Chicken is finished, add Chicken and any juices accumulated on baking sheet to curry and reduce heat to low; mix well to combine. Stirring constantly to prevent curry from breaking, dribble in Heavy Cream [0.25 Cups]. Taste and season with more Salt if needed.", "Cut remaining Lemon into wedges. Serve Kuku Na Nazi with Basmati Rice and/or some Crusty Bread and Lemon wedges for squeezing over. Top with additional Cilantro to taste." ), tags = mapOf( @@ -61,6 +65,7 @@ val kenyanList = listOf( "Garlic" to TagType.FLAVOUR, "Herby" to TagType.FLAVOUR, ), - image = Res.drawable.kuku_no_nazi, // Replace with your image resource + image = Res.drawable.kuku_no_nazi, + ttt = TTT.TESTED ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/africa/SengaleseData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/africa/SengaleseData.kt index 7104bc5..10d969f 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/africa/SengaleseData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/africa/SengaleseData.kt @@ -4,6 +4,7 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources.yassa +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val sengaleseList = listOf( @@ -21,13 +22,13 @@ val sengaleseList = listOf( ".5 Green Chili, Rough Chopped", "15g Ginger, Grated", "1 Scotch Bonnet", - ".25 Cup Parsley", - "Juice of 2 Lemons", + ".25 Cups Parsley", + "3 Tbsp Lemon Juice", "1 Tbsp Dijon Mustard", - "1.5 lbs Protein of Choice", + "1.5 lbs Protein of Choice (Originally Chicken)", "HEADER-Curry", - "2 Onions, thin Sliced", + "2 Onions, Thin Sliced", "3 Tbsp Oil", "2 Tbsp Red Wine Vinegar", "1 Bay Leaf", @@ -36,7 +37,7 @@ val sengaleseList = listOf( "HEADER-Marinade and Bake", "Add all the Marinade Ingredients except the Protein to a Blender. Pulse until smooth, and season with Salt as needed.", - "Marinade the Protein overnight (8 hours is really all you need, so I tend to do this the morning of rather than the night before).", + "Marinade the Protein overnight.", "Heat an Oven to 400F. Shake off the Protein, reserving the Marinade, and Bake for about 45 minutes (or until cooked through and Golden Brown).", "HEADER-Curry", @@ -55,6 +56,7 @@ val sengaleseList = listOf( "Curry" to TagType.TECHNIQUE, "Spicy" to TagType.FLAVOUR ), - image = Res.drawable.yassa , + image = Res.drawable.yassa, + ttt = TTT.TRUE ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/AmericanData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/AmericanData.kt index c1bf558..23382ba 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/AmericanData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/AmericanData.kt @@ -10,6 +10,7 @@ import bakersmenagerie.composeapp.generated.resources.bagels import bakersmenagerie.composeapp.generated.resources.chicken_and_dumplings import bakersmenagerie.composeapp.generated.resources.chicken_rochester import bakersmenagerie.composeapp.generated.resources.midnight_garlic_noodles +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val americanList = listOf( @@ -18,19 +19,19 @@ val americanList = listOf( description = "Southern Fried Chicken served on a Buttermilk Waffle, drenched in a hot Honey Butter.", ingredients = listOf( "8 Chicken Breasts", - "4 Waffles", + "8 Waffles", "HEADER-Buttermilk Brine", "2 Cups (480 mL) Buttermilk", "1 Tbsp Kosher Salt", - ".5 Tbsp Garlic Powder", - ".5 Tbsp Onion Powder", + "0.5 Tbsp Garlic Powder", + "0.5 Tbsp Onion Powder", "1 Tbsp Hot Sauce or Chili Powder", "1 Tsp Smoked Paprika", "HEADER-Flour Crust", "3 Cups (384 g) Flour", - ".33 Cup (43 g) Cornstarch", + "0.33 Cup (43 g) Cornstarch", "2 Tsp Baking Powder", "2 Tsp Garlic Powder", "2 Tsp Onion Powder", @@ -38,25 +39,30 @@ val americanList = listOf( "2 Tsp freshly cracked Black Pepper", "HEADER-Spicy Honey Butter", - ".25 Cup (85 g)Honey", - ".5 Tsp Chili Powder", + "0.25 Cups (85 g) Honey", + "0.5 Tsp Chili Powder", "4 Tbsp (57 g) Unsalted Butter", - ".5 Tsp Kosher Salt", + "0.5 Tsp Kosher Salt", ), instructions = listOf( - "Whisk the Buttermilk [2 Cups], Kosher Salt [1 Tbsp], Garlic Powder [.5 Tbsp], Onion Powder [.5 Tbsp], Hot Sauce [1 Tbsp], and Smoked Paprika" + + + "HEADER-Brine", + "Whisk the Buttermilk [2 Cups], Kosher Salt [1 Tbsp], Garlic Powder [0.5 Tbsp], Onion Powder [0.5 Tbsp], Hot Sauce [1 Tbsp], and Smoked Paprika" + " [1 Tsp] together in a large mixing bowl.", - "Add the Chicken Breast [8] to the bowl, making sure every piece is covered in the Brine. Cover the bowl and let the Chicken marinate in the " + - "Buttermilk Brine from 1 hour to overnight in the fridge.", + "Add the Chicken Breast [8] to the bowl, making sure every piece is covered in the Brine.", + "Cover the bowl and let the Chicken marinate in the Buttermilk Brine from 1 hour to overnight in the fridge.", + + "HEADER-Coat & Fry", "In a dutch oven pot, heat up about half the pot's worth of Vegetable Oil. Allow the Oil to reach 350 degrees F.", - "While the Oil is heating up, in a mixing bowl whisk together Flour [3 Cups], Cornstarch [.333 Cup], Baking Powder [2 Tsp], and Seasonings. Take " + - "each Chicken piece from the Brine and dredge into the seasoned Flour. Thoroughly coat the Chicken all over, then let rest on a plate for " + + "In a mixing bowl whisk together Flour [3 Cups], Cornstarch [0.33 Cups], Baking Powder [2 Tsp], and Seasonings.", + "Take each Chicken piece from the Brine and dredge into the seasoned Flour. Thoroughly coat the Chicken all over, then let rest on a plate for " + "five minutes before frying.", "Fry the Chicken in the hot Oil (no more than about 4 per batch) until golden brown, crispy, and cooked through completely, about 8-9 minutes.", "Carefully take the Chicken out of the oil and place them on a baking sheet fitted with a wire rack and let cool slightly before serving. Repeat " + "until all the Chicken is fried.", - "In a small saucepan, melt butter over medium heat with honey, chili powder, and kosher salt. Whisk well until the mixture is incorporated and " + - "homogenized.", + + "HEADER-Finish & Serve", + "In a small saucepan, melt Butter [4 Tbsp] over medium heat with Honey [0.25 Cups], Chili Powder [0.5 Tsp], and Salt [ 0.5 Tsp]. Whisk well.", "Lower the temperature to 'warm/low' heat and keep for serving. [Make sure to keep warm, as sauce will solidify very quickly]", "Make the Belgian Waffles and serve the Chicken on top of the waffles, then drizzle generously with Spicy Honey Butter Sauce.", ), @@ -72,7 +78,8 @@ val americanList = listOf( image = Res.drawable.Chicken_And_Waffles, cookTime = Duration.parse("20m"), prepTime = Duration.parse("8h"), - servings = "Serves 4", + servings = "Serves 6", + ttt = TTT.TESTED, ), Recipe( @@ -113,7 +120,8 @@ val americanList = listOf( "Vegetarian" to TagType.PROTEIN, ), image = Res.drawable._10_strawberries, - servings = "Makes Pasta for 4" + servings = "Makes Pasta for 4", + ttt = TTT.TRUE, ), Recipe( @@ -121,7 +129,7 @@ val americanList = listOf( description = "Garlicky, Oily, Rich Umami Noodles", ingredients = listOf( "Sea Salt", - "12 Ounces Wheat Pasta", + "12 oz Wheat Pasta", "2 Tbsp Burnt Miso", "15 Cloves Garlic Confit", "2 Tbsp Garlic Oil", @@ -130,11 +138,11 @@ val americanList = listOf( "Parmesan Cheese", ), instructions = listOf( - "Cook Pasta [12 Ounces] to al dente", + "Cook Pasta [12 oz] to al dente", "Run Burnt Miso [2 Tbsp], Garlic [15 Cloves], and Garlic Oil [1 Tbsp] in blender until smooth.", "Add Butter [1 Tbsp] and [.25 Cups] of Pasta Water, blend again.", "Heat Garlic Oil [1 Tbsp] in a skillet. Add the Garlic-Miso Sauce from above. Use tongs to transfer Pasta directly to the skillet.", - "Season with Fleur de Sel and cover with Parmesan Cheese", + "Season with Fleur de Sel and cover with Parmesan Cheese.", ), tags = mapOf( "American" to TagType.CUISINE, @@ -148,6 +156,7 @@ val americanList = listOf( cookTime = Duration.parse("15m"), image = Res.drawable.midnight_garlic_noodles, servings = "Makes 2 Bowls", + ttt = TTT.TESTED, linkedRecipes = listOf( burntMiso ) @@ -165,16 +174,16 @@ val americanList = listOf( "1 Tbsp Olive Oil", "2 lbs Chicken Breast", "5 Tbsp Butter", - "1 Yellow Onion, diced", - "1 Cup Carrot, diced", - "2 Sticks Celery, diced", + "1 Cups Yellow Onion, Diced", + "1 Cups Carrot, Diced", + "1 Cups Celery, Diced", "3 Cloves Garlic", "1 Tsp Worcestershire Sauce", "1 Tsp Hot Sauce", - ".33 Cup Flour", + ".33 Cups Flour", "4.5 Cups Chicken Broth", "1.5 Cups Half and Half", - ".75 Cup Peas", + ".75 Cups Peas", "HEADER-Seasonings", "1 Tsp Onion Powder", @@ -191,18 +200,18 @@ val americanList = listOf( "1 Tsp Salt", ".5 Tsp Garlic Powder", "2 Tsp Sugar", - ".75 Cup Cold Sour Cream", - ".25 Cup Cold Milk", + ".75 Cups Sour Cream, Cold", + ".25 Cups Cold Milk", "4 Tbsp Butter, Melted", ), instructions = listOf( "HEADER-Prep", - "Cook the Chicken however you prefer. Season to taste and shred.", + "Boil the Chicken. Season to taste and shred.", "Combine All from Seasonings and Set Aside", "HEADER-Soup", - "Melt the Butter [5 Tbsp] in a large pot. Add the Onions, Carrots, and Celery and cook for about 5 minutes.", + "Melt the Butter [5 Tbsp] in a large pot. Add the Onions [1 Cups], Carrots [1 Cups], and Celery [1 Cups] and cook for about 5 minutes.", "Add the Garlic [3 Cloves], Worcestershire Sauce [1 Tsp], Hot Sauce [1 Tsp], and the Seasonings, and cook for another minute.", "Add the Flour [.33 Cups] and toss to coat. Cook for another 2 minutes.", "Add the Chicken Broth [4.5 Cups] and stir thoroughly. Add the Half and Half [1.5 Cups].", @@ -211,7 +220,7 @@ val americanList = listOf( "HEADER-Dumplings", "Combine Cake Flour [2 Cups], Baking Powder [2 Tsp], Salt [1 Tsp], Garlic Powder[.5 Tsp], and Sugar[2 Tsp] in a bowl.", "Add Milk [.25 Cups], Sour Cream [.75 Cups], and Melted Butter [4 Tbsp] to the bowl and fold into a light dough.", - "(At this point, you should add the Chicken into the Soup.)", + "At this point, you should add the Chicken into the Soup.", "Using a Scoop, take a ball of Dumpling Dough and drop it into the Soup. Ladle a bit of liquid over each.", "Cover and Simmer for 15 minutes, or until everything is cooked through.", ), @@ -223,6 +232,7 @@ val americanList = listOf( "Carnivorous" to TagType.PROTEIN, ), image = Res.drawable.chicken_and_dumplings, + ttt = TTT.TRIED ), Recipe( @@ -263,7 +273,8 @@ val americanList = listOf( "Savory" to TagType.FLAVOUR, ), image = Res.drawable.SCPBP, - linkedRecipes = SCPBP + linkedRecipes = SCPBP, + ttt = TTT.TRIED, ), Recipe( @@ -275,17 +286,17 @@ val americanList = listOf( ingredients = listOf( "HEADER-Dough", - "1.5 (360 ml) Cups Warm Water", + "1.5 Cups (360 ml) Warm Water", "2.75 Tsp Active Yeast (1 Packet)", - "4 Cups (520g) Bread Flour", + "4 Cups (520 g) Bread Flour", "1 Tbsp Brown Sugar", "2 Tsp Salt", "Olive Oil to Coat", - "1 Egg White, to wash", + "1 Egg Whites, to wash", "HEADER-Water Bath", "2 Quarts Water", - ".25 Cup (85g) Honey", + "0.25 Cups (85g) Honey", "HEADER-Topping", "Everything Seasoning", @@ -308,6 +319,7 @@ val americanList = listOf( ), image = Res.drawable.bagels, linkedRecipes = everythingSeasoning, + ttt = TTT.TRUE ), Recipe( @@ -348,6 +360,7 @@ val americanList = listOf( linkedRecipes = listOf( remouladeSauce ), + ttt = TTT.TESTED, ), Recipe( @@ -359,21 +372,21 @@ val americanList = listOf( ingredients = listOf( "HEADER-Chicken", "4 Chicken Breasts (8 Chicken Cutlets)", - "1 large Egg", + "1 large Eggs", "1 Tbsp Milk", "0.25 Tsp Salt", "0.25 Tsp Pepper", - "0.5 cup All-Purpose Flour", + "0.5 Cups All-Purpose Flour", "1 Tbsp Unsalted Butter", "1 Tbsp Olive Oil", "HEADER-Sauce", "4 Tbsp Unsalted Butter, divided", - "0.25 cup Minced Sweet Onion", + "0.25 Cups Minced Sweet Onion", "2 Tbsp All-Purpose Flour", - "0.5 cup Dry White Wine", - "0.25 cup Fresh Squeezed Lemon Juice (about 2 juicy lemons)", - "2 cups Low-Sodium Chicken Broth (or Chicken Stock)", + "0.5 Cups Dry White Wine", + "0.25 Cups Lemon Juice, fresh Squeezed", + "2 Cups Chicken Broth", "Salt and Pepper to taste", "Minced Fresh Parsley Leaves, for garnish", "Sliced Lemon, for garnish" @@ -381,15 +394,15 @@ val americanList = listOf( instructions = listOf( "HEADER-Chicken", "In a shallow bowl, whisk together the Egg [1] and Milk [1 Tbsp]. Set aside.", - "Combine the Salt [0.25 Tsp], Pepper [0.25 Tsp], and Flour [0.5 cup] in a separate shallow bowl and place next to the egg wash. Line a baking sheet with paper towels and set aside.", - "In a large skillet, heat 2 Tbsp Butter and 2 Tbsp Olive Oil over medium heat until the butter is melted and the foaming stops.", - "Using tongs, dredge the Chicken Cutlets in the Flour mixture, shaking off the excess. Dip the Chicken in the Egg mixture, allowing the extra egg to drip back into the bowl. Transfer to the Flour once again, turning to coat. Shake off the extra Flour and place in the hot skillet.", + "Combine the Salt [0.25 Tsp], Pepper [0.25 Tsp], and Flour [0.5 Cups] in a separate shallow bowl and place next to the egg wash. Line a baking sheet with paper towels and set aside.", + "In a large skillet, heat 2 Tbsp Butter and 2 Tbsp Olive Oil over medium heat until the Butter is melted and the foaming stops.", + "Using tongs, dredge the Chicken Cutlets in the Flour mixture, shaking off the excess. Dip the Chicken in the Egg mixture, allowing the extra Egg to drip back into the bowl. Transfer to the Flour once again, turning to coat. Shake off the extra Flour and place in the hot skillet.", "Cook 2 or 3 Cutlets at a time, turning once, until the Chicken is well browned, about 3 minutes on each side. Transfer to the prepared paper-towel lined baking sheet. Repeat, adding more Butter and Olive Oil if needed until all Chicken is cooked. Set Chicken aside. Discard the grease and wipe out the skillet with clean paper towels.", "HEADER-Sauce", - "Add 3 Tbsp Butter to the now empty skillet over medium heat. Add the Minced Onion [0.25 cup] and cook, stirring occasionally, until soft.", - "Add 2 Tbsp Flour and stir for 2 minutes. Add the Wine [0.5 cup], Lemon Juice [0.25 cup], and Chicken Broth [2 cups]. Increase the temperature to medium-high and bring to a boil, stirring constantly.", - "Reduce the heat to medium and cook the Sauce, stirring frequently, until it is reduced to about 1.5 cups and slightly thickened, about 10 minutes.", + "Add Butter [3 Tbsp] to the now empty skillet over medium heat. Add the Minced Onion [0.25 Cups] and cook, stirring occasionally, until soft.", + "Add Flour [2 Tbsp] and stir for 2 minutes. Add the Wine [0.5 Cups], Lemon Juice [0.25 Cups], and Chicken Broth [2 Cups]. Increase the temperature to medium-high and bring to a boil, stirring constantly.", + "Reduce the heat to medium and cook the Sauce, stirring frequently, until it is reduced to about [1.5 Cups] and slightly thickened, about 10 minutes.", "Pour the Sauce through a fine mesh sieve to remove the onions if desired. Return the Sauce to the pan and reduce the heat to low. Add the last 1 Tbsp of Butter to the Sauce. Stir gently until melted. Check the seasoning and add Salt and Pepper as needed. The Lemon flavor will be intense.", "Reserve Half the Sauce for Pasta.", "Add the Chicken Cutlets to the Sauce and heat gently for 4 to 5 minutes, turning once, or until heated through. Top the Chicken with sautéed Lemon slices and garnish with minced Parsley and plenty of fresh ground Black Pepper.", @@ -409,7 +422,8 @@ val americanList = listOf( "Carnivorous" to TagType.PROTEIN, "Herby" to TagType.FLAVOUR, ), - image = Res.drawable.chicken_rochester, // Replace with your image resource + image = Res.drawable.chicken_rochester, + ttt = TTT.TRUE, ), Recipe( @@ -460,6 +474,7 @@ val americanList = listOf( "Bread" to TagType.COURSE, ), image = Res.drawable._10_strawberries, // Replace with your image resource + ttt = TTT.TESTED, ), Recipe( @@ -497,5 +512,6 @@ val americanList = listOf( "Vegetarian" to TagType.PROTEIN, ), image = Res.drawable._10_strawberries, // Replace with your image resource + ttt = TTT.TESTED ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/BrazilianData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/BrazilianData.kt index 9cfa6d5..5d662b1 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/BrazilianData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/BrazilianData.kt @@ -4,12 +4,13 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources.coxhinas +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val brazilianList = listOf( Recipe( title = "Coxinha", - description = "Brazilian style croquettes; shredded chicken battered and fried.", + description = "Brazilian style croquettes; Shredded chicken battered and fried.", prepTime = Duration.parse("2h"), cookTime = Duration.parse("1h"), servings = "Serves 8 to 12 People", @@ -18,15 +19,16 @@ val brazilianList = listOf( "HEADER-Boiled Chicken", "600g Chicken", "5 Cups Chicken Broth", - "1 Carrot", - "2 Onions, halved", + "1 Carrots", + "1 Onions, halved", "2 Bay Leaves", "HEADER-Filling", "2 Tbsp Butter", + "1 Onion, Halved", "2 Cloves Garlic", - "Juice of 1 Lime", - "1 Cup Cream Cheese", + "1.5 Tbsp Lime Juice", + "1 Cups Cream Cheese", "HEADER-Batter", "3 Cups Flour", @@ -35,13 +37,19 @@ val brazilianList = listOf( "3 Cups Bread Crumbs", ), instructions = listOf( - "Cover Chicken with the Broth [5 Cups]. Add [1] Carrot, [1] Onion, and [2] Bay Leaves.", + + "HEADER-Chicken Boil", + "Cover Chicken with the Broth [5 Cups]. Add Carrots [1], Onions [1], and Bay Leaves [2].", "Boil until Chicken is cooked through. Pull and set aside, straining and reserving the Broth.", - "Saute the second Onion and the Garlic [2 Cloves] in Butter [2 Tbsp].", + + "HEADER-Make Fillings", + "Saute the Onions [1] and the Garlic [2 Cloves] in Butter [2 Tbsp].", "Shred the Chicken. Mix in Lime Juice and Cream Cheese [1 Cup], and the Garlic-Onion Mixture.", "Combine strained Broth [3 Cups] with Flour [3 Cups], Oil [2 Tsp], Salt and Pepper.", "In a pan over Medium heat, reduce the dough mixture until dried ever so slightly, pulling away from the walls of the pan.", "Chill the Chicken Mixture and the Dough for at least an hour, up to overnight.", + + "HEADER-Fry", "Once Chilled, make the Coxinhas. Take a Golf ball sized piece of dough, flattened into a round. Fill with about 1 Tbsp of filling", "Wrap up the sides into a teardrop, using a small amount of Milk or Water to seal the dough shut.", "Dip the Coxinha in beaten Egg Mixture, then roll in Breadcrumbs.", @@ -58,5 +66,6 @@ val brazilianList = listOf( "Croquette" to TagType.TECHNIQUE ), image = Res.drawable.coxhinas, + ttt = TTT.TRIED, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/BurntMiso.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/BurntMiso.kt index 098edc3..20453cc 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/BurntMiso.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/BurntMiso.kt @@ -4,6 +4,7 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources.burnt_miso +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val burntMiso = Recipe( @@ -29,5 +30,6 @@ tags = mapOf( "Baked" to TagType.TECHNIQUE, "Vegan" to TagType.PROTEIN, ), -image = Res.drawable.burnt_miso +image = Res.drawable.burnt_miso, + ttt = TTT.TESTED ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/EverythingSeasoning.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/EverythingSeasoning.kt index fcb7f7d..bc39040 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/EverythingSeasoning.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/EverythingSeasoning.kt @@ -4,6 +4,7 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources._10_strawberries +import com.menagerie.bakers.model.TTT import kotlin.time.Duration @@ -32,5 +33,6 @@ val everythingSeasoning = listOf( "Savory" to TagType.FLAVOUR, ), image = Res.drawable._10_strawberries, + ttt = TTT.TESTED ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/JamaicanData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/JamaicanData.kt index 6875733..f42a14e 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/JamaicanData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/JamaicanData.kt @@ -4,6 +4,7 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources.jerk +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val jamaicanList = listOf( @@ -14,21 +15,21 @@ val jamaicanList = listOf( cookTime = Duration.ZERO, // No cooking involved servings = "Makes about 2 cups", ingredients = listOf( - "4-6 Scotch Bonnet Peppers, chopped", - "1 Small Red Onion, chopped", - "4-6 Garlic Cloves, chopped", - "4 Stalks Scallions, end trimmed", - "0.25 Cup Soy Sauce", - "0.25 Cup Vinegar (White Vinegar or Apple Cider Vinegar)", + "6 Scotch Bonnet Peppers, Chopped", + "1 Small Red Onions, Chopped", + "6 Garlic Cloves, Chopped", + "4 Stalks Scallions, ends trimmed", + "0.25 Cups Soy Sauce", + "0.25 Cups Apple Cider Vinegar", "2 Tbsp Olive Oil", - "0.25 Cup Lime Juice (from half a Lime)", - "1 Tbsp Freshly Grated Ginger", + "0.25 Cups Lime Juice", + "1 Tbsp Ginger, Grated", "2 Tbsp Brown Sugar", "1 Tsp Nutmeg", "1 Tsp Allspice", "1 Tsp Cinnamon", "1 Tsp Dried Thyme", - "Salt and Pepper, to taste" + "Salt to taste" ), instructions = listOf( "Combine all ingredients in a food processor, Blend. Adjust Soy [0.25 Cup], Vinegar [0.25 Cup], and Oil [2 Tbsp] ratios accordingly for consistency." @@ -40,6 +41,7 @@ val jamaicanList = listOf( "Savory" to TagType.FLAVOUR, "Vegan" to TagType.PROTEIN, ), - image = Res.drawable.jerk // Replace with your image resource + image = Res.drawable.jerk, + ttt = TTT.TRUE, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/MexicanData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/MexicanData.kt index 31b30b7..78d1621 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/MexicanData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/MexicanData.kt @@ -5,6 +5,7 @@ import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources._10_strawberries import bakersmenagerie.composeapp.generated.resources.tinga +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val mexicanList = listOf( @@ -44,20 +45,21 @@ val mexicanList = listOf( "Creamy" to TagType.FLAVOUR, "Savory" to TagType.FLAVOUR ), - image = Res.drawable._10_strawberries + image = Res.drawable._10_strawberries, + ttt = TTT.TESTED ), Recipe( title = "Chicken Tinga", - description = "Shredded chicken in a smoky chipotle tomato sauce.", + description = "Shredded Chicken in a Smoky Chipotle Tomato sauce.", ingredients = listOf( - "3-4 medium Chicken breasts", - "4-5 Tbsp Oil (olive oil)", - "1-2 large Onions (sliced)", - "4-5 medium Roma Tomatoes (or Smoked tomato)", - "1 can Chipotle chiles in adobo (7oz)", - "2-3 cloves Garlic", - "1.5 Tsp Salt (or to taste)", + "4 Chicken Breasts", + "5 Tbsp Oil (olive oil)", + "1.5 Onions (sliced)", + "5 Roma Tomatoes", + "1 Can Chipotle chiles in adobo (7oz)", + "2-3 Cloves Garlic", + "1.5 Tsp Salt", "0.25 Tsp Mexican Oregano", "0.25 Tsp Dried Thyme", "0.25 Tsp Dried Marjoram", @@ -66,12 +68,12 @@ val mexicanList = listOf( "Small, thick cut slices of Toast" ), instructions = listOf( - "Bring a pot of salty water to a boil and add the Chicken breasts. Let the Chicken simmer until cooked through. Skim the foam as it boils.", - "While the Chicken cooks, place the Tomatoes [4-5 medium] in a medium saucepan, cover with water, bring to a simmer and cook for 8-10 minutes, until soft.", - "Slice the Onions [1-2 large] thinly. Heat the Oil [4-5 Tbsp] in a large pan and add the Onions. Cook until soft and translucent for 5-6 minutes.", - "In a blender, throw the Tomatoes [4-5 medium], Garlic [2-3 cloves], Salt [1.5 Tsp], pepper [0.25 Tsp], and 2-3 Chipotle chiles. Blend.", - "Taste the salsa for Salt and pepper and adjust.", - "Pour the salsa over Onions [1-2 large]. Add oregano [0.25 Tsp], marjoram [0.25 Tsp], thyme [0.25 Tsp], and pepper [0.25 Tsp]. Simmer the sauce for 7-8 minutes, stirring occasionally.", + "Bring a pot of salty water to a boil and add the Chicken Breasts. Let the Chicken simmer until cooked through. Skim the foam as it boils.", + "While the Chicken cooks, place the Tomatoes [5] in a medium saucepan, cover with water, bring to a simmer and cook for 8-10 minutes, until soft.", + "Slice the Onions [1.5] thinly. Heat the Oil [5 Tbsp] in a large pan and add the Onions. Cook until soft and translucent for 5-6 minutes.", + "In a blender, throw the Tomatoes [5], Garlic [3 Cloves], Salt [1.5 Tsp], pepper [0.25 Tsp], and Chipotle chiles in their sauce [1 Can]. Blend.", + "Taste the Salsa for Salt and adjust.", + "Pour the Salsa over Onions [1.5]. Add Oregano [0.25 Tsp], Marjoram [0.25 Tsp], Thyme [0.25 Tsp], and Pepper [0.25 Tsp]. Simmer the sauce for 7-8 minutes, stirring occasionally.", "Take the Chicken out of the broth, and shred the meat with two forks. Add it to the sauce and mix well.", "Serve over fresh, hot toast, with a layer of Refried beans." ), @@ -86,6 +88,7 @@ val mexicanList = listOf( "Carnivorous" to TagType.PROTEIN ), image = Res.drawable.tinga, - servings = "Serves 4-6" + servings = "Serves 5", + ttt = TTT.TESTED, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/PeruvianData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/PeruvianData.kt index d1061b1..fe5a817 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/PeruvianData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/PeruvianData.kt @@ -4,27 +4,36 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources.aji_de_gallina +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val peruvianList = listOf( Recipe( - title = "Aji de Gallina", - description = "A Peruvian stew made with aji amarillo paste, giving it a rich yellow colour. Served with walnuts, black olives, and potatoes.", + title = "Ají de Gallina", + description = "A Peruvian stew made with Ají Amarillo paste, giving it a rich yellow colour. Served with Walnuts, Black Olives, and Potatoes.", prepTime = Duration.parse("30m"), cookTime = Duration.parse("30m"), servings = "Serves 5", ingredients = listOf( + + "1.5 lbs Protein of Choice (Originally Chicken)", "4 Yellow Potatoes", + + "HEADER-Thickener", "4 Slices White Bread", - ".75 Cup Evaporated Milk (Not Dry Milk)", - "1.5 lbs Protein of Choice", + ".75 Cups Evaporated Milk (Not Dry Milk)", + + + "HEADER-Sauce", "4 Cups Stock", - "4 Yellow Aji Peppers", - ".5 Cup Vegetable Oil", + "4 Yellow Ají Peppers", + ".5 Cups Vegetable Oil", "2 Cloves Garlic, Minced", - "1 Large Onion, fine Chopped", + "1 Large Onion, finely Chopped", "3 Tbsp Walnuts, Chopped", "3 Tbsp Parmesan, Grated", + + "HEADER-To Serve", "3 Cups White Rice, Cooked", "2 Hard Boiled Eggs, Quartered", "10 Black Olives", @@ -33,11 +42,15 @@ val peruvianList = listOf( "Cook Potatoes [4] until tender. Cool, Peel, Quarter, and Set Aside.", "Place White Bread [4 Slices] in a bowl. Pour Evaporated Milk [.75 Cups] over to soak. Set Aside.", "Boil and Shred the Protein, if applicable. Reserve Stock.", - "Blend Yellow Peppers [4] with Vegetable Oil [.5 Cup] until Smooth. Transfer to a saucepan.", - "Add the Garlic [2 Cloves] and Onion [1] to the saucepan. Cook until soft.", + + "HEADER-Sauce", + "Blend Yellow Peppers [4] with Vegetable Oil [.5 Cups] until Smooth. Transfer to a saucepan.", + "Add the Garlic [2 Cloves] and Onions [1] to the saucepan. Cook until soft.", "Take the Soaked Bread, Walnuts [3 Tbsp], Parmesan [3 Tbsp], and Blend until Smooth. Use more Milk, or the Stock, if needed.", "Add the Onion Mixture to the Blender with the Bread Mixture and Blend.", - "Return the Mixture to the saucepan and add [1.5 Cups] Stock. Bring to a low simmer and add the Protein.", + + "HEADER-Finish & Serve", + "Return the Mixture to the saucepan and add Stock [1.5 Cups]. Bring to a low simmer and add the Protein.", "Serve a portion with 1/2 Cup of Rice, some Potatoes, a Hard Boiled Egg Quarter, and Black Olives.", ), tags = mapOf( @@ -50,5 +63,6 @@ val peruvianList = listOf( "Savory" to TagType.FLAVOUR, ), image = Res.drawable.aji_de_gallina, + ttt = TTT.TRIED, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/RemouladeSauce.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/RemouladeSauce.kt index d2eb97f..d8885e8 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/RemouladeSauce.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/RemouladeSauce.kt @@ -4,6 +4,7 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources._10_strawberries +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val remouladeSauce = Recipe( @@ -41,4 +42,5 @@ val remouladeSauce = Recipe( "Condiment" to TagType.COURSE ), image = Res.drawable._10_strawberries, + ttt = TTT.TESTED, ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/SpicyChickenPretzelBaconPub.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/SpicyChickenPretzelBaconPub.kt index 248e54d..6d04ab5 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/SpicyChickenPretzelBaconPub.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/americas/SpicyChickenPretzelBaconPub.kt @@ -4,6 +4,7 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources.SCPBP +import com.menagerie.bakers.model.TTT import kotlin.time.Duration @@ -15,14 +16,14 @@ val SCPBP = listOf( cookTime = Duration.parse("15m"), servings = "Makes 6 Buns", ingredients = listOf( - "1.25 Cup Water, 110F", + "1.25 Cups Water, 110F", "1 Packet / 2.25 Tsp Active Dry Yeast", "1 Tsp Sugar", "3 Tbsp Butter, melted, cooled", "3.5 Cups Flour", "2 Tsp Salt", - ".5 Cup Baking Soda", - ".5 Tbsp Olive Oil" + "0.5 Cups Baking Soda", + "0.5 Tbsp Olive Oil" ), instructions = listOf( "In a Stand Mixer Bowl, Mix Together Water [1.25 Cup], Yeast [2.25 Tsp], and Sugar [1 Tsp]. Let Stand until Foamy, about 5 minutes.", @@ -31,7 +32,7 @@ val SCPBP = listOf( "Knead the Dough with the hook on medium for another 5 minutes.", "Transfer the Dough to an Oiled Bowl and let rise for 1 hour.", "Punch the Dough. Knead for another 2 minutes, then divide into [6] Equal Portions. Shape into a Bun, then cover and let rise another 30 minutes", - "Preheat the Oven to 425F. Bring a Quart of Water for every [.5 Cup] of Baking Soda to a Boil.", + "Preheat the Oven to 425F. Bring a Quart of Water for every 0.5 Cups of Baking Soda to a Boil.", "Bathe the Pretzels 30s per side, then arrange on a parchment lined baking tray. Score the top of each.", "Top with Course Salt (optional) and Bake for 10-15 minutes.", @@ -44,28 +45,29 @@ val SCPBP = listOf( "Baked" to TagType.TECHNIQUE, ), image = Res.drawable.SCPBP, + ttt = TTT.TRIED ), Recipe( title = "Spicy Chicken Cutlets", description = "Spicy, Breaded, American style Chicken Cutlet.", - prepTime = Duration.parse("4h"), + prepTime = Duration.parse("4h 10m"), cookTime = Duration.parse("10m"), servings = "Makes 6 Cutlets", ingredients = listOf( "6 Chicken Cutlets", - ".75 Cups Buttermilk", + "0.75 Cups Buttermilk", "1.5 Tbsp Tabasco", - ".75 Cup Breadcrumbs", - ".75 Cup Crushed Cornflakes", - ".75 Tsp Paprika", - ".5 Tsp Cayenne", - ".75 Tsp Salt", - ".75 Tsp Pepper", + "0.75 Cups Breadcrumbs", + "0.75 Cups Crushed Cornflakes", + "0.75 Tsp Paprika", + "0.5 Tsp Cayenne", + "0.75 Tsp Salt", + "0.75 Tsp Pepper", "Oil to Fry", ), instructions = listOf( - "Soak Chicken [6] in Buttermilk [.75 Cups] and Tabasco [1.5 Tbsp] for 4 hours.", - "Mix Breadcrumbs [.75 Cup], Cornflakes [.75 Cup], Paprika [.75 Tsp], Cayenne [.5 Tsp], Salt [.75 Tsp], and Pepper [.75 Tsp] in a large bowl", + "Soak Chicken [6] in Buttermilk [0.75 Cups] and Tabasco [1.5 Tbsp] for 4 hours.", + "Mix Breadcrumbs [0.75 Cup], Cornflakes [0.75 Cup], Paprika [0.75 Tsp], Cayenne [0.5 Tsp], Salt [0.75 Tsp], and Pepper [.75 Tsp] in a large bowl", "Drain Chicken and Dredge in the Breadcrumb Mixture. Return to Buttermilk briefly, then Cover again in Breadcrumb Mixture.", "Heat 2 Tbsp of Oil in a large skillet. Fry Chicken in a single layer about 5 minutes per side.", ), @@ -77,6 +79,7 @@ val SCPBP = listOf( "Savory" to TagType.FLAVOUR, ), image = Res.drawable.SCPBP, + ttt = TTT.TRIED, ), Recipe( title = "Beer Cheese", @@ -86,7 +89,7 @@ val SCPBP = listOf( servings = "Makes about 4 Cups", ingredients = listOf( "4 Tbsp Butter", - "1 Small Onion, fine diced", + "1 Small Onion, finely Diced", "4 Tbsp Flour", "2 Cups Light Beer", "1.5 Cups Heavy Cream", @@ -99,7 +102,7 @@ val SCPBP = listOf( "Melt Butter [4 Tbsp] in a large saucepan over medium. Add Onion [1] and cook until softened, 2-3 minutes.", "Add Flour [4 Tbsp] and stir to a Roux. Let it start to Brown, about 2 minutes.", "Whisk in Beer [2 Cups] until Smooth.", - "Simmer out the alcohol, about 5 minutes.", + "Simmer out the Alcohol, about 5 minutes.", "Add Cream [1.5 Cups] and Garlic [2 Cloves], and stir frequently as sauce thickens, about 10 minutes.", "Remove from heat, season to taste, and stir in the Cheddar [6 oz] and Swiss [6oz] until completely melted.", ), @@ -114,6 +117,7 @@ val SCPBP = listOf( "Tangy" to TagType.FLAVOUR, ), image = Res.drawable.SCPBP, + ttt = TTT.TRIED, ), Recipe( title = "Onion Tangles", @@ -130,11 +134,11 @@ val SCPBP = listOf( "3 cups Oil, for Frying", ), instructions = listOf( - "Heat Frying Oil", - "Cut Onions [2 Cups] into Crescents", + "Heat Frying Oil.", + "Cut Onions [2 Cups] into Crescents.", "Soak Crescents in Buttermilk [1.25 Cups] for 10 minutes, tossing regularly.", "Drain the Buttermilk and add Flour [1.5 Cups], Salt [.5 Tsp], Pepper, tossing Onions until coated.", - "Fry Battered Onions in batches until Golden Brown, about 5-7 minutes" + "Fry Battered Onions in batches until Golden Brown, about 5-7 minutes." ), tags = mapOf( "American" to TagType.CUISINE, @@ -143,5 +147,6 @@ val SCPBP = listOf( "Savory" to TagType.FLAVOUR ), image = Res.drawable.SCPBP, + ttt = TTT.TRIED, ), ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/ChineseData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/ChineseData.kt index 532703c..17cab19 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/ChineseData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/ChineseData.kt @@ -4,6 +4,7 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources._10_strawberries +import bakersmenagerie.composeapp.generated.resources.almond_chicken import bakersmenagerie.composeapp.generated.resources.burnt_garlic_chicken import bakersmenagerie.composeapp.generated.resources.chilli_chicken import bakersmenagerie.composeapp.generated.resources.kung_pao @@ -12,6 +13,7 @@ import bakersmenagerie.composeapp.generated.resources.san_bei_ji import bakersmenagerie.composeapp.generated.resources.sesame import bakersmenagerie.composeapp.generated.resources.taiwanese_popcorn_chicken import bakersmenagerie.composeapp.generated.resources.tso +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val chineseList = listOf( @@ -53,7 +55,8 @@ val chineseList = listOf( "Savory" to TagType.FLAVOUR, "Vegetarian" to TagType.PROTEIN ), - image = Res.drawable._10_strawberries + image = Res.drawable._10_strawberries, + ttt = TTT.TESTED ), Recipe( @@ -72,20 +75,20 @@ val chineseList = listOf( "1 Tsp Sesame Oil", "3 Tbsp Brown Sugar", "1 Tbsp Cornstarch", - ".75 Cup Chicken Broth", + "0.75 Cups Chicken Broth", "HEADER-Chicken", "600g Protein, cut into bite sized pieces", "1 Tsp Ginger", "1 Tsp Garlic", - "1 Cup Cornstarch", - "1-3 Cups Oil for Frying", + "1 Cups Cornstarch", + "1.5 Cups Oil for Frying", "HEADER-Stir Fry Sauce", "2 Tbsp Oil", "2 Tsp Ginger", "2 Cloves Garlic", - ".5 Tsp Red Chilli Flakes", + "0.5 Tsp Red Chilli Flakes", "HEADER-Garnishes", "Sesame Seeds", @@ -93,14 +96,14 @@ val chineseList = listOf( ), instructions = listOf( "HEADER-Marinade and Sauce", - "Mix Soy [3 Tbsp], Hoisin [1 Tbsp], Vinegar [1 Tbsp], Chilli [2 Tsp], and Sesame Oil [1 Tsp]", + "Mix Soy [3 Tbsp], Hoisin [1 Tbsp], Vinegar [1 Tbsp], Chilli [2 Tsp], and Sesame Oil [1 Tsp].", "Take [2 Tbsp] of the Marinade to mix with the Protein. Add the Ginger [1 Tsp] and Garlic [1 Tsp] and Marinate for 30 minutes.", - "For the rest of the Sauce, add Brown Sugar [3 Tbsp] and Cornstarch [1 Tbsp]. Mix, and then add Chicken Broth [.75 Cup]", + "For the rest of the Sauce, add Brown Sugar [3 Tbsp] and Cornstarch [1 Tbsp]. Mix, and then add Chicken Broth [0.75 Cups]", "HEADER-Protein Fry", - "Add Cornstarch [1 Cup] into the Marinade and toss to coat. Make sure to separate and fully coat each piece." + - " Shake off the excess. A colander or mesh strainer can help.", - "Heat Oil to 350-370F", + "Add Cornstarch [1 Cups] into the Marinade and toss to coat. Make sure to separate and fully coat each piece." + + " Shake off the excess.", + "Heat Oil to 350F", "Fry Protein until cooked through, and golden brown on the outside", "HEADER-Stir Fry", @@ -117,6 +120,7 @@ val chineseList = listOf( "Deep Fried" to TagType.TECHNIQUE, ), image = Res.drawable.tso, + ttt = TTT.TRIED, ), Recipe( @@ -128,19 +132,19 @@ val chineseList = listOf( ingredients = listOf( "HEADER-Marinade", - "1 Egg White", + "1 Egg Whites", "2 Tbsp Dark Soy", "2 Tbsp Shaoxing", "2 Tbsp Eighty Proof Vodka", - ".25 Tsp Baking Soda", + "0.25 Tsp Baking Soda", "3 Tbsp Cornstarch", - "1 lb Protein of Choice, cut into bite sized pieces", + "1 lbs Protein of Choice, cut into bite sized pieces", "HEADER-Coating", - ".5 Cup Flour", - ".5 Cup Cornstarch", - ".5 Tsp Baking Powder", - ".5 Tsp Salt", + "0.5 Cups Flour", + "0.5 Cups Cornstarch", + "0.5 Tsp Baking Powder", + "0.5 Tsp Salt", "HEADER-Sauce", "3 Tbsp Dark Soy", @@ -167,7 +171,7 @@ val chineseList = listOf( "To the other half, add Baking Soda [.25 Tsp] and Cornstarch [3 Tbsp]. Add Protein [1 lb] and coat thoroughly. Cover and Set Aside.", "HEADER-Coating", - "Combine Flour [.5 Cup], Cornstarch [.5 Cup], Baking Powder [.5 Tsp], and Salt [.5 Tsp]. Add the reserved Half of the Marinade." + + "Combine Flour [.5 Cup], Cornstarch [0.5 Cups], Baking Powder [.5 Tsp], and Salt [.5 Tsp]. Add the reserved Half of the Marinade." + " Expect Coarse, Mealy clumps.", "At this point, begin Heating the Deep Frying Oil, about 350F.", @@ -195,6 +199,7 @@ val chineseList = listOf( "Nutty" to TagType.FLAVOUR ), image = Res.drawable.sesame, + ttt = TTT.TRIED ), Recipe( @@ -215,7 +220,7 @@ val chineseList = listOf( "2.5 Tbsp (31g) Shaoxing Wine", "HEADER-Marinade", - "2 lbs Protein of Choice, bite sized", + "2 lbs Protein of Choice, bite sized (Originally Chicken)", "1 Tsp (4g) Corn Starch", "Pinch of White Pepper", "2 Tbsp (36g) Soy Sauce", @@ -223,19 +228,21 @@ val chineseList = listOf( "HEADER-Stir Fry", "3.5 tablespoons (53g) Vegetable Oil", - ".25 cup (48g) Raw Peanuts", + "0.25 cup (48g) Raw Peanuts", "8 dried Chilies", - ".25 bunch Scallions", - "1-inch knob Ginger, minced", - "8 cloves Garlic, minced and divided", - ".25 Tsp, (1g) ground Sichuan Peppercorn", - "Additional Sliced Scallion for garnishing", - "Additional Peanuts, crushed for garnishing", + "3 Stalks Scallions", + "1 inch knob Ginger, Minced", + "8 Cloves Garlic, Minced", + ".25 Tsp, (1g) Sichuan Peppercorn, Ground", + + "HEADER-Garnish", + "Additional Sliced Scallion", + "Additional Peanuts, Crushed", ), instructions = listOf( "HEADER-Sauce", - "Combine all ingredients in a medium bowl and Set Aside.", + "Combine all ingredients in a bowl and Set Aside.", "HEADER-Stir Fry", "Combine Protein [2 lb] with Cornstarch [1 Tsp], White Pepper, and toss to coat. Add Soy Sauce [2 Tbsp], Shaoxing [1 Tbsp], mix and let Marinate overnight.", @@ -258,11 +265,12 @@ val chineseList = listOf( ), image = Res.drawable.kung_pao, servings = "Serves 4", + ttt = TTT.TESTED ), Recipe( title = "Orange Chicken", - description = "Another American-Chinese dish. This time, bits of battered and fried chicken are served with a orange flavored glaze.", + description = "Another American-Chinese dish. This time, bits of battered and fried Chicken are served with a Orange-Soy glaze.", prepTime = Duration.parse("15m"), cookTime = Duration.parse("20m"), servings = "Serves 5", @@ -270,31 +278,31 @@ val chineseList = listOf( "HEADER-Protein", "2 lbs Protein, bite-sized", "3 Eggs, whisked", - ".33 Cup Cornstarch", - ".33 Cup Flour", + "0.33 Cups Cornstarch", + "0.33 Cups Flour", "Salt", "Oil For Frying", "HEADER-Orange Sauce", - "1 Cup Orange Juice", - ".5 Cup Sugar", + "1 Cups Orange Juice", + "0.33 Cups Sugar", "2 Tbsp Rice Vinegar", "2 Tbsp Soy Sauce", - ".25 Tsp Ginger", - ".25 Tsp Garlic Powder", - ".5 Tsp Red Chili Flakes", - "Orange Zest", + "1 Tsp Orange Zest, grated", + "0.5 Tsp Red Chili Flakes", + "0.25 Tsp Garlic Powder", + "0.25 Tsp Ginger", "1 Tbsp Cornstarch", ), instructions = listOf( "HEADER-Orange Sauce", - "Add Orange Juice [1 Cup], Sugar [.5 Cup], Vinegar [2 Tbsp], Soy [2 Tbsp], Ginger [.25 Tsp], Garlic [.25 Tsp], and Chili Flakes [.5 Tsp] to a pot." + + "Add Orange Juice [1 Cup], Sugar [0.33 Cup], Vinegar [2 Tbsp], Soy [2 Tbsp], Ginger [0.25 Tsp], Garlic [0.25 Tsp], and Chili Flakes [0.5 Tsp] to a pot." + " Heat over medium for about 3 minutes", - "Combine Cornstarch [1 Tbsp] with Water [2 Tbsp] to form a paste. Add to Sauce and stir until it thickens. Remove from heat and add Orange Zest [].", + "Combine Cornstarch [1 Tbsp] with Water [2 Tbsp] to form a paste. Add to Sauce and stir until it thickens. Remove from heat and add Orange Zest [0.5 Tsp].", "HEADER-Stir Fry", "Heat Oil to 350F", - "Mix Flour [.33 Cup] and Cornstarch [.33 Cup] in a shallow bowl with Salt.", + "Mix Flour [0.33 Cups] and Cornstarch [0.33 Cups] in a shallow bowl with Salt.", "Dredge Protein in Eggs, then Flour Mixture.", "Fry Protein in Batches until Golden Brown and Cooked through", "Toss Protein in Orange Sauce and Serve", @@ -309,6 +317,7 @@ val chineseList = listOf( "Savory" to TagType.FLAVOUR, ), image = Res.drawable.orange_chicken, + ttt = TTT.TRIED ), Recipe( @@ -318,7 +327,7 @@ val chineseList = listOf( cookTime = Duration.parse("15m"), servings = "Serves 3", ingredients = listOf( - "1 lb Protein of Choice", + "1 lbs Protein of Choice", "1 Tbsp Baking Soda", "2 Tbsp Toasted Sesame Oil", "2 in Piece of Ginger, Grated", @@ -343,6 +352,7 @@ val chineseList = listOf( "Adaptable" to TagType.PROTEIN, ), image = Res.drawable.san_bei_ji, + ttt = TTT.TESTED, linkedRecipes = listOf( kecapManis //Kecap ), @@ -411,53 +421,58 @@ val chineseList = listOf( "Carnivorous" to TagType.PROTEIN, "Herby" to TagType.FLAVOUR, ), - image = Res.drawable.taiwanese_popcorn_chicken, // Replace with your image resource + image = Res.drawable.taiwanese_popcorn_chicken, + ttt = TTT.TRIED ), Recipe( title = "Schezwan Burnt Garlic Chicken", - description = "Crispy Chicken pieces tossed in a spicy Schezwan burnt garlic sauce with colorful bell peppers and spring onions.", + description = "Crispy Chicken pieces tossed in a spicy Schezwan burnt Garlic sauce with colorful Bell Peppers and Scallions.", prepTime = Duration.parse("2h 15m"), // 1-2 hours marinade + 15 mins prep cookTime = Duration.parse("20m"), - servings = "Serves 4", + servings = "Serves 3", ingredients = listOf( + "HEADER-Protein & Marination", "250 gms Protein of Choice (originally boneless chicken)", "2-3 Tbsp Soy Sauce (for marination)", - "1 Tsp Green Chilly Sauce (for marination)", + "1 Tsp Green Chilli Sauce (for marination)", "0.25 Tsp Pepper Powder (for marination)", "Salt (for marination)", - "1 Egg", - "2 Tbsp Cornflour", - "2 Tbsp All Purpose Flour", + "1 Eggs", + "2 Tbsp Cornstarch", + "2 Tbsp Flour", - "HEADER-Sauce & Veggies", - "8-10 cloves Garlic (finely chopped)", - "1 Onion (chopped)", - "4-5 cloves Garlic", - "3-4 Red Whole Chilies", + "HEADER-Garlic Oil", + "5 cloves Garlic", + "4 Red Whole Chilies", + "2 Tbsp High Heat Oil", + + "HEADER-Sauce", + "10 Cloves Garlic (finely chopped)", + "1 Onions (chopped)", "1 Tbsp Ginger (finely chopped)", "1 Green Chilly", "2 Tbsp Schezwan Chutney", - "2-3 Tbsp Soy Sauce", - "Vinegar", + "3 Tbsp Soy Sauce", + "1 Tbsp Vinegar", "0.5 Tsp Sugar", "1 Tbsp Cornflour (in 1 cup water)", - "1 Tsp Red Chilly Sauce", - "1 Tsp Green Chilly Sauce", - "0.5 cup Spring Onions (greens)", - "0.5 cup Red Bell Pepper (cubed)", - "0.5 cup Green Capsicum (cubed)", - "0.5 cup Yellow Bell Pepper (cubed)", - "0.125 Tsp Pepper Powder", - "Spring Onions (bulbs, halved)", + "1 Tsp Red Chilli Sauce", + "1 Tsp Green Chilli Sauce", - "HEADER-Frying", - "Oil / Butter" + + "HEADER-Stir Fry", + "0.5 Cups Scallions (greens)", + "Scallions (bulbs, halved)", + "0.5 Cups Red Bell Pepper (cubed)", + "0.5 Cups Green Capsicum (cubed)", + "0.5 Cups Yellow Bell Pepper (cubed)", + "0.125 Tsp Pepper Powder", ), instructions = listOf( "HEADER-Marination", - "Clean, wash, and chop Protein [250 gms] into thick pieces and marinate with Soy Sauce [2-3 Tbsp], Green Chilly Sauce [1 Tsp], Pepper Powder [0.25 Tsp], and Salt for 1-2 hours.", + "Chop Protein [250 gms] into thick pieces and marinate with Soy Sauce [2-3 Tbsp], Green Chilli Sauce [1 Tsp], Pepper Powder [0.25 Tsp], and Salt for 1-2 hours.", "HEADER-Fry Protein", "In a kadhai, heat sufficient Oil for deep frying.", @@ -489,7 +504,8 @@ val chineseList = listOf( "Savory" to TagType.FLAVOUR, "Adaptable" to TagType.PROTEIN, ), - image = Res.drawable.burnt_garlic_chicken + image = Res.drawable.burnt_garlic_chicken, + ttt = TTT.TRIED, ), Recipe( @@ -499,56 +515,57 @@ val chineseList = listOf( cookTime = Duration.parse("20m"), servings = "Serves 4", ingredients = listOf( - "1.5 lbs Boneless Chicken (preferably dark meat)", + "1.5 lbs Boneless Chicken Thighs", "0.5 Green Pepper", - "0.5 Onion", + "0.5 Onions", "2 Tbsp Garlic-Ginger-Onion Mix (reserved from marinade)", "HEADER-Chicken Marinade", - "0.5 Small Onion", - "3-4 Slices Ginger", - "2-3 Cloves Garlic", + "0.5 White Onions", + "4 Slices Ginger", + "3 Cloves Garlic", "1 Tsp Black Pepper", - "0.5 Tbsp Chilli Powder (or Cayenne Pepper)", + "0.5 Tbsp Chilli Powder", "1.5 Tbsp Soy Sauce", "3-4 Tbsp Water", "6-7 Tbsp Corn Starch (mix this in with the Chicken after marinating, right before deep frying)", "HEADER-Sauce", - "5-6 Green Chilli (or Green Thai Chillis)", - "1.5 Tbsp Dark Soy", + "6 Thai Green Chillis", + "1.5 Tbsp Kecap Manis", "2.5 Tbsp Soy Sauce", "1 Tbsp Rice Vinegar", "1 Tbsp Honey", "2 Tsp Corn Starch (mixed with 4 Tsp of Water)", - "1.5 Tsp Chilli Powder (or Cayenne Pepper)", - "0.5 Cup Water" + "1.5 Tsp Chilli Powder", + "0.5 Cups Water" ), instructions = listOf( - "HEADER-Preparation", - "With a food processor, Blitz the Ginger [3-4 Slices], Garlic [2-3 Cloves] and half a Small Onion [0.5] until it is a fine paste. Reserve 2 tablespoons of this for Browning the Onions [0.5] and Green Peppers [0.5] later.", - "Cut up the Chicken [1.5 lbs] into small bite-sized 1 inch pieces and Marinate it in a bowl with the Ginger-Garlic-Onion paste, Soy Sauce [1.5 Tbsp], Chilli Powder [0.5 Tbsp], Black Pepper [1 Tsp], and Water [3-4 Tbsp]. (Do not add the Corn Starch yet. We will add that right before we deep fry the Chicken.) Marinate in the fridge for 1 hour or overnight.", + "HEADER-Prep", + "With a food processor, Blitz the Ginger [4 Slices], Garlic [3 Cloves] and Onions [0.5] until it is a fine paste. Reserve 2 tablespoons of this for Browning the Onions [0.5] and Green Peppers [0.5] later.", + "Cut up the Chicken [1.5 lbs] into small bite-sized 1 inch pieces and Marinate it in a bowl with the Ginger-Garlic-Onion paste, Kecap Manis [1.5 Tbsp], Chilli Powder [0.5 Tbsp], Black Pepper [1 Tsp], and Water [3-4 Tbsp]. (Do not add the Corn Starch yet. We will add that right before we deep fry the Chicken.) Marinate in the fridge for 1 hour.", "Chop the Green Peppers [0.5] and remaining Onion [0.5] into bite-sized pieces and set aside.", - "HEADER-Making the Sauce", + "HEADER-Sauce", "Chop up the Chillis [5-6] in the slices (keep the seeds) and add it to a small bowl.", "Add in the rest of the ingredients in the sauce ingredient list except the Corn Starch [2 Tsp].", - "In a small bowl, mix 2 teaspoons of Corn Starch [2 Tsp] with 4 teaspoons of cold Water [4 Tsp], then add it to the sauce and stir to combine.", + "In a small bowl, mix Corn Starch [2 Tsp] with Cold Water [4 Tsp], then add it to the sauce and stir to combine.", "Set the sauce aside.", - "HEADER-Putting it Together", + "HEADER-Deep Fry", "Add Corn Starch [6-7 Tbsp] to the Chicken and mix until combined and Chicken is coated lightly.", "In a wok, frying pan or deep fryer set the oil to 350F (177C).", - "When the oil is hot, add the Chicken into the oil to Cook in batches (careful not to over crowd the oil, which can drop the oil temperature).", - "Cook the Chicken for about 5-6 minutes and set aside on a plate with paper towel or newspaper when it is done.", - "In a wok or frying pan, set the stove to medium to medium high heat and add 2 tablespoons of oil.", - "When the oil is hot, add in the Ginger-Garlic-Onion mix [2 Tbsp] that was reserved from preparation and Cook it until it is toasty and brown. Approximately 1-2 minutes. Careful not to burn it.", + "When the oil is hot, add the Chicken into the oil to Cook in batches.", + "Cook the Chicken for about 5-6 minutes and set aside on a plate with paper towel.", + + "HEADER-Stir Fry", + "In a wok, set the stove medium high heat and add 2 tablespoons of oil.", + "When the oil is hot, add in the Ginger-Garlic-Onion mix [2 Tbsp] that was reserved from preparation and Cook it until it is toasty and brown. Approximately 1-2 minutes.", "Add in the Onions [0.5] and Green Pepper [0.5] chunks and Cook it for about 2 minutes. We want to keep the veggies somewhat crisp still, so do not overcook the Peppers.", "Give the sauce a quick stir (the Corn Starch likes to settle at the bottom) and add it to the pan.", "Keep stirring the sauce until it thickens and becomes thick.", "Once the sauce has thickened, turn off the heat.", "Add in Chicken and mix everything together until the Chicken is coated with the sauce.", - "Enjoy it with some rice!" ), tags = mapOf( "Chinese-Indian" to TagType.CUISINE, @@ -558,7 +575,11 @@ val chineseList = listOf( "Savory" to TagType.FLAVOUR, "Carnivorous" to TagType.PROTEIN, ), - image = Res.drawable.chilli_chicken // Replace with your image resource + image = Res.drawable.chilli_chicken, + linkedRecipes = listOf( + kecapManis + ), + ttt = TTT.TRUE ), Recipe( @@ -624,6 +645,7 @@ val chineseList = listOf( "Entree" to TagType.COURSE, "Carnivorous" to TagType.PROTEIN ), - image = Res.drawable._10_strawberries, + image = Res.drawable.almond_chicken, + ttt = TTT.TRIED, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/IndianData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/IndianData.kt index 87e342f..9215dec 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/IndianData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/IndianData.kt @@ -4,6 +4,9 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources._10_strawberries +import bakersmenagerie.composeapp.generated.resources.butter_chicken +import bakersmenagerie.composeapp.generated.resources.chicken_65 +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val indianList = listOf( @@ -58,21 +61,22 @@ val indianList = listOf( prepTime = Duration.parse("15m"), cookTime = Duration.parse("15m"), servings = "Makes 4 Wraps", - image = Res.drawable._10_strawberries + image = Res.drawable._10_strawberries, + ttt = TTT.TESTED ), Recipe( title = "Butter Chicken", description = "Creamy and aromatic chicken pieces in a rich tomato and cream sauce.", - prepTime = Duration.parse("1h 15m"), // 30 mins to 1 hour marinade + 15 mins prep + prepTime = Duration.parse("8h 15m"), // 30 mins to 1 hour marinade + 15 mins prep cookTime = Duration.parse("40m"), servings = "Serves 4-6", ingredients = listOf( "HEADER-Protein Marinade", - "28 oz (800g) Protein of Choice (cut into bite-sized pieces)", - "0.5 cup Plain Yogurt", - "1.5 Tbsp Minced Garlic", - "1 Tbsp Minced Ginger (or finely grated)", + "28 oz (800g) Protein of Choice\n (cut into bite-sized pieces)", + "0.5 Cups Cream Cheese, Softened", + "1.5 Tbsp Garlic, Minced", + "1 Tbsp Ginger, Grated", "2 Tsp Garam Masala", "1 Tsp Turmeric", "1 Tsp Ground Cumin", @@ -81,32 +85,33 @@ val indianList = listOf( "HEADER-Sauce", "2 Tbsp Olive Oil", - "2 Tbsp Ghee (or 1 Tbsp Butter + 1 Tbsp Oil)", - "1 large Onion (sliced or chopped)", - "1.5 Tbsp Garlic (minced)", - "1 Tbsp Ginger (minced or finely grated)", + "2 Tbsp Ghee", + "1 large Onions, Chopped", + "1.5 Tbsp Garlic, Minced", + "1 Tbsp Ginger, Grated", "1.5 Tsp Ground Cumin", "1.5 Tsp Garam Masala", "1 Tsp Ground Coriander", - "14 oz (400 g) Crushed Tomatoes", - "1 Tsp Red Chili Powder (adjust to your taste preference)", - "1.25 Tsp Salt (or to taste)", - "1 cup Heavy or Thickened Cream (or evaporated milk)", + "14 oz (400 g) Crushed Smoked Tomatoes", + "1 Tsp Red Chili Powder", + "1.25 Tsp Salt", + "1 Cups Heavy Cream", "1 Tbsp Sugar", - "0.5 Tsp Kasoori Methi (or dried fenugreek leaves)" + "0.5 Tsp Kasoori Methi", ), instructions = listOf( "HEADER-Marinade", "In a bowl, combine Protein [28 oz] with all of the ingredients for the Protein Marinade; let marinate for 30 minutes to an hour (or overnight if time allows).", "HEADER-Fry Protein", - "Heat Olive Oil [2 Tbsp] in a large skillet or pot over medium-high heat. When sizzling, add Protein pieces in batches of two or three, making sure not to crowd the pan. Fry until browned for about 3 minutes on each side. Set aside and keep warm. (You will finish cooking the Protein in the sauce.)", + "Heat Olive Oil [2 Tbsp] in a large skillet or pot over medium-high heat. When sizzling, add Protein pieces in batches.", + "Fry until browned for about 3 minutes on each side. Set aside and keep warm. (You will finish cooking the Protein in the sauce.)", "HEADER-Make Sauce", "Heat Ghee [2 Tbsp] in the same pan. Fry the Onions [1] until they start to sweat (about 6 minutes) while scraping up any browned bits stuck on the bottom of the pan.", "Add Garlic [1.5 Tbsp] and Ginger [1 Tbsp] and sauté for 1 minute until fragrant, then add Ground Coriander [1 Tsp], Cumin [1.5 Tsp], and Garam Masala [1.5 Tsp]. Let cook for about 20 seconds until fragrant, while stirring occasionally.", "Add Crushed Tomatoes [14 oz], Chili Powder [1 Tsp], and Salt [1.25 Tsp]. Let simmer for about 10-15 minutes, stirring occasionally until sauce thickens and becomes a deep brown-red color.", - "Remove from heat, scoop mixture into a blender and blend until smooth. You may need to add a couple tablespoons of water to help it blend (up to 0.25 cup). Work in batches depending on the size of your blender.", + "Remove from heat, scoop mixture into a blender and blend until smooth. You may need to add a couple tablespoons of water to help it blend.", "HEADER-Finish & Serve", "Pour the puréed sauce back into the pan. Stir the Cream [1 cup], Sugar [1 Tbsp], and crushed Kasoori Methi [0.5 Tsp] through the sauce. Add the Protein with juices back into the pan and cook for an additional 8-10 minutes until Protein is cooked through and the sauce is thick and bubbling." @@ -124,19 +129,20 @@ val indianList = listOf( "Garlic" to TagType.FLAVOUR, "Ginger" to TagType.FLAVOUR, ), - image = Res.drawable._10_strawberries, // Replace with your image resource + image = Res.drawable.butter_chicken, + ttt = TTT.TRUE ), Recipe( title = "Chicken 65", - description = "Spicy, crispy Chicken 65: Indian fried chicken marinated in Curd and spices, then tempered with Garlic, Ginger, and Chillies.", + description = "Spicy, crispy Chicken 65: Indian fried chicken marinated in Curd and Spices, then tempered with Garlic, Ginger, and Chillies.", prepTime = Duration.parse("8h"), cookTime = Duration.parse("20m"), servings = "Serves 4", listOf( "HEADER-Chicken Marinade", "500 Grams Chicken Thighs, boneless, skinless, cut into approx 0.5 inch small cubes", - "0.25 Cup Curd", + "0.25 Cups Curd", "1 Tbsp Ginger Garlic Paste", "0.25 Tsp Turmeric Powder", "1 Tsp Kashmiri Red Chilli Powder", @@ -144,15 +150,16 @@ val indianList = listOf( "0.5 Tsp Jeera Powder", "1 Tsp Sugar", "0.75 Tsp Salt", - "2 Sprigs Curry Leaves, chopped", + "2 Sprigs Curry Leaves, Chopped", "2 Tbsp Rice Flour", - "3 Tbsp Corn Flour", + "3 Tbsp Corn Starch", "Oil, for frying", + "HEADER-Chicken 65 Fry", "1 Tbsp Oil", - "1 Tbsp Garlic, finely chopped", - "1 Tbsp Ginger, finely chopped", - "5 Green Chillies, halved", + "1 Tbsp Garlic, Finely Chopped", + "1 Tbsp Ginger, Finely Chopped", + "5 Green Chillies, Halved", "1 Tsp Red Chilli Powder", "2 Sprigs Curry Leaves" ), @@ -174,6 +181,7 @@ val indianList = listOf( "Appetizer" to TagType.COURSE, "Carnivorous" to TagType.PROTEIN ), - image = Res.drawable._10_strawberries, + image = Res.drawable.chicken_65, + ttt = TTT.TRIED, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/JapaneseData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/JapaneseData.kt index 6fc9149..0956b27 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/JapaneseData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/JapaneseData.kt @@ -5,6 +5,7 @@ import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources.karaage import bakersmenagerie.composeapp.generated.resources.teriyaki +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val japaneseList = listOf( @@ -12,6 +13,8 @@ val japaneseList = listOf( title = "Teriyaki", description = "Protein grilled with a glaze of Soy Sauce, Mirin, and Sugar.", ingredients = listOf( + + "HEADER-Marinade", "2 lbs Protein of Choice, cut to size", "3.5 Tbsp Mirin", "3.5 Tbsp Soy Sauce", @@ -20,6 +23,8 @@ val japaneseList = listOf( "1 Tsp Ginger", "1.5 Tsp Sesame Oil", "1 Tbsp Cornstarch", + + "HEADER-Fry", "2 Tbsp Oil", ), instructions = listOf( @@ -44,6 +49,7 @@ val japaneseList = listOf( prepTime = Duration.parse("2h 15m"), servings = "Serves 4 people", image = Res.drawable.teriyaki, + ttt = TTT.TESTED, linkedRecipes = listOf( kecapManis, //Kecap Manis ) @@ -57,32 +63,32 @@ val japaneseList = listOf( servings = "Serves 4", ingredients = listOf( "HEADER-Marinade", - "1.5 Tsp grated fresh Ginger, with its juice", - "6 cloves Garlic", + "1.5 Tsp Ginger, Grated", + "6 Cloves Garlic", "2 Tbsp Dry Sake", "3 Tbsp Soy Sauce", "2 Tsp Sugar", - "1 lb Protein of Choice (originally Chicken Breasts)", + "1 lbs Protein of Choice (Originally Chicken)", "HEADER-Coating", - "1 cup Potato Starch (Katakuriko)", + "1 Cups Potato Starch", "0.25 Tsp Fine Sea Salt", "0.5 Tsp Black Pepper", "HEADER-Frying", - "Flying Oil (Vegetable, Canola, Peanut, etc.)" + "Frying Oil" ), instructions = listOf( "HEADER-Marinade", - "In a shallow baking dish large enough to hold the Protein, combine Ginger [1.5 Tsp], Garlic [6 cloves], Sake [2 Tbsp], Soy Sauce [3 Tbsp], and Sugar [2 Tsp]. Toss Protein pieces [1 lb] in marinade to coat. Cover and refrigerate for 1 day.", + "In a shallow baking dish large enough to hold the Protein, combine Ginger [1.5 Tsp], Garlic [6 Cloves], Sake [2 Tbsp], Soy Sauce [3 Tbsp], and Sugar [2 Tsp]. Toss Protein pieces [1 lb] in marinade to coat. Cover and refrigerate for 1 day.", "HEADER-First Fry", "Heat Oil in a fryer to 350°F (175°C).", "While the oil heats: In a bowl, combine Potato Starch [1 cup], Salt [0.25 Tsp], and Pepper [0.5 Tsp]. Coat the Protein.", - "Gently shake off excess Potato Starch before cooking each piece of Protein. Fry 3 or 4 pieces at a time, keeping oil temperature above 300°F (150°C). Fry until Protein is cooked through. Remove from oil using a wire-mesh spoon or long chopsticks, and cool on newsprint or paper towels.", + "Gently shake off excess Potato Starch before cooking each piece of Protein. Fry until cooked through, in small batches. Remove from oil and drain on paper towels.", "HEADER-Second Fry", - "When all the Protein has been fried once, increase the oil’s temperature to 375°F (190°C). Fry Protein pieces a second time, until the crust is deep golden brown, about 1 minute. Drain on newsprint or paper towels. This second frying makes the coating stay extra crisp, even if you don’t serve it immediately." + "When all the Protein has been fried once, increase the oil’s temperature to 375°F (190°C). Fry Protein pieces a second time, until the crust is deep golden brown, about 1 minute. Drain on paper towels. This second frying makes the coating stay extra crisp, even if you don’t serve it immediately." ), tags = mapOf( "Japanese" to TagType.CUISINE, @@ -93,6 +99,7 @@ val japaneseList = listOf( "Ginger" to TagType.FLAVOUR, "Adaptable" to TagType.PROTEIN, ), - image = Res.drawable.karaage, // Replace with your image resource + image = Res.drawable.karaage, + ttt = TTT.TESTED, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/KecapManis.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/KecapManis.kt index 4b60782..bdbf089 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/KecapManis.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/KecapManis.kt @@ -4,6 +4,7 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources.kecap_manis +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val kecapManis = Recipe( @@ -12,17 +13,17 @@ val kecapManis = Recipe( prepTime = Duration.parse("5h"), cookTime = Duration.parse("15m"), ingredients = listOf( - "1 Cup Soy Sauce", - "1.25 Cup Coconut Sugar", + "1 Cups Soy Sauce", + "1.25 Cups Coconut Sugar", "1 Tbsp Molasses", "6 Cloves Garlic", - "2 inch Piece Fresh Ginger", + "2 Inch Piece Fresh Ginger", "2 Whole Star Anise", - "2 Whole Clove", + "2 Whole Cloves", ), instructions = listOf( "Place all ingredients in a small saucepan and bring to a boil. Reduce the heat to medium-low and simmer uncovered, stirring frequently, until the Sugar is dissolved and Sauce begins to thicken, 10-15 minutes.", - "Turn off the heat, cover and let cool completely with the spices, garlic and ginger still in it so they can continue to release their flavors. Once cool, discard the pieces, pour the sauce into an airtight jar and store in the fridge. It will keep for several weeks", + "Turn off the heat, cover and let cool completely with the spices, garlic and ginger still in it so they can continue to release their flavors. Once cool, strain into an airtight jar and store in the fridge. It will keep for several weeks.", ), tags = mapOf( "SEA" to TagType.CUISINE, @@ -37,5 +38,6 @@ val kecapManis = Recipe( "Condiment" to TagType.COURSE ), servings = "About 1 Cup", - image = Res.drawable.kecap_manis + image = Res.drawable.kecap_manis, + ttt = TTT.TRUE ) diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/KoreanData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/KoreanData.kt index beb7139..e7a85cf 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/KoreanData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/KoreanData.kt @@ -7,21 +7,26 @@ import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources._10_strawberries import bakersmenagerie.composeapp.generated.resources.dakkochi import bakersmenagerie.composeapp.generated.resources.oi_muchim +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val koreanList = listOf( Recipe( title = "Oi Muchim | Spicy Cucumber Salad", - description = "Cucumbers tossed in vinegar and chili spices.", + description = "Cucumbers tossed in Vinegar and Chili Spices.", ingredients = listOf( - "1 Cucumber", + + "HEADER-Brine", + "1 Cucumbers", "1 Tsp Salt", + + "HEADER-Season", "1 Tbsp Gochugaru", - "1 Tbsp Scallion, chopped", + "1 Tbsp Scallions, chopped", "1 Tsp Garlic, minced", "1 Tsp Vinegar", - "1/2 Tsp Sugar", - "1 tsp Sesame Seeds", + "0.5 Tsp Sugar", + "1 Tsp Sesame Seeds", "1 Tsp Sesame Oil", ), instructions = listOf( @@ -39,6 +44,7 @@ val koreanList = listOf( "Nutty" to TagType.FLAVOUR, "Tossed" to TagType.TECHNIQUE ), + ttt = TTT.TRUE, image = Res.drawable.oi_muchim, cookTime = Duration.ZERO, prepTime = Duration.parse("30m"), @@ -76,6 +82,7 @@ val koreanList = listOf( "Condiment" to TagType.COURSE ), image = Res.drawable._10_strawberries, + ttt = TTT.TESTED, cookTime = Duration.ZERO, prepTime = Duration.parse("10m") ), @@ -115,6 +122,7 @@ val koreanList = listOf( "Nutty" to TagType.FLAVOUR ), image = Res.drawable._10_strawberries, + ttt = TTT.TRUE, cookTime = Duration.parse("30m"), prepTime = Duration.parse("8h") ), @@ -137,8 +145,8 @@ val koreanList = listOf( "HEADER-Fire Sauce", "3 Tbsp Gochugaru", "2 Jalapenos", - ".5 Cup Korean Pear", - ".25 White Onion", + ".5 Cups Korean Pear", + ".25 White Onions", "3 Tbsp Garlic, minced", "2 Tbsp Soy Sauce", "1 Tsp Spicy Yellow Mustard", @@ -146,7 +154,7 @@ val koreanList = listOf( "1 Tbsp Honey", ), instructions = listOf( - "Cut the Protein into Bite-sized pieces", + "Cut the Protein into Bite-sized pieces.", "In a bowl, mix Soy [2 Tbsp], Sugar [1 Tbsp], Honey [1 Tbsp], Rice Wine [2 Tbsp], and Black Pepper. Toss the Protein in this mixture; marinate for 30m.", "Puree all the Fire Sauce ingredients together in a blender. Set Aside.", "Heat a wok over medium heat, cooking Protein to just underdone in batches as needed.", @@ -168,43 +176,43 @@ val koreanList = listOf( prepTime = Duration.parse("40m"), cookTime = Duration.parse("15m"), image = Res.drawable.Buldak, + ttt = TTT.TESTED, servings = "Serves 2-3", ), Recipe( - title = "Dakkochi (Korean Chicken Skewers)", + title = "Dakkochi | Korean Chicken Skewers", description = "Sweet, spicy, and savory Korean Chicken skewers with Green Onions, grilled and basted with a Gochujang sauce.", prepTime = Duration.parse("45m"), // 30 mins soak + 15 mins prep cookTime = Duration.parse("15m"), servings = "Serves 6", ingredients = listOf( - "900 g Chicken Breast (boneless, skinless, cubed)", - "290 g Green Onion (cut into 4-5 cm / 1.5-2 inch lengths)", + "900 g Chicken Breast, bite sized", + "290 g Green Onion, long slices", "2 Tbsp Rice Wine", - "Fine Sea Salt (to taste)", - "Freshly Ground Black Pepper (to taste)", + "Fine Sea Salt", "Cooking Oil Spray", "HEADER-Spicy Gochujang Sauce", - "0.25 cup Tomato Sauce / Ketchup", - "2 Tbsp Gochujang (Korean chili paste)", + "0.25 Cups Sriracha Ketchup", + "2 Tbsp Gochujang", "2 Tbsp Honey", "2 Tbsp Dark Brown Sugar", "1 Tbsp Soy Sauce", "2 Tsp Sesame Oil", - "0.5 Tsp Minced Garlic" + "0.5 Tsp Garlic, Minced" ), instructions = listOf( "HEADER-Prepare Skewers", "Immerse wooden skewers in water for 30 minutes.", - "Place Chicken pieces [900 g] in a bowl. Add Rice Wine [2 Tbsp], Salt, and Pepper. Mix well. Set aside for 5 minutes.", - "Remove skewers from water and wipe dry. Thread Chicken and Green Onion [290 g] pieces onto skewers, alternating. Pack tightly. You should have 12 skewers (25cm / 9.8 inch).", + "Place Chicken pieces [900 g] in a bowl. Add Rice Wine [2 Tbsp] and Salt. Mix well. Set aside until skewers are ready.", + "Remove skewers from water and wipe dry. Thread Chicken and Green Onion [290 g] pieces onto skewers, alternating. Pack tightly.", "HEADER-Make Gochujang Sauce", - "Combine Tomato Sauce [0.25 cup], Gochujang [2 Tbsp], Honey [2 Tbsp], Brown Sugar [2 Tbsp], Soy Sauce [1 Tbsp], Sesame Oil [2 Tsp], and Garlic [0.5 Tsp] in a bowl. Mix well.", + "Combine Sriracha Ketchup [0.25 cup], Gochujang [2 Tbsp], Honey [2 Tbsp], Brown Sugar [2 Tbsp], Soy Sauce [1 Tbsp], Sesame Oil [2 Tsp], and Garlic [0.5 Tsp] in a bowl. Mix well.", "HEADER-Cook Skewers", - "Spray Cooking Oil on a grill, skillet, or sheet pan. Place skewers and cook over medium-high heat. After 3 minutes, turn skewers and brush with Gochujang Sauce.", + "Prep a grill. Place skewers and cook over medium-high heat. After 3 minutes, turn skewers and brush with Gochujang Sauce.", "After 2 minutes, reduce heat to medium, turn skewers, and brush with sauce again. Reduce heat to low.", "Continue turning and brushing skewers until Chicken is cooked through and charred to your liking. Serve immediately." ), @@ -218,6 +226,7 @@ val koreanList = listOf( "Sweet" to TagType.FLAVOUR, "Carnivorous" to TagType.PROTEIN, ), - image = Res.drawable.dakkochi, // Replace with your image resource + image = Res.drawable.dakkochi, + ttt = TTT.TESTED, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/LaoData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/LaoData.kt index 2315f13..9b38972 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/LaoData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/LaoData.kt @@ -1,9 +1,10 @@ package com.menagerie.bakers.model.asia -import com.menagerie.bakers.model.Recipe -import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res -import bakersmenagerie.composeapp.generated.resources._10_strawberries +import bakersmenagerie.composeapp.generated.resources.gai_yang +import com.menagerie.bakers.model.Recipe +import com.menagerie.bakers.model.TTT +import com.menagerie.bakers.model.TagType import kotlin.time.Duration val laoList = listOf( @@ -19,41 +20,43 @@ val laoList = listOf( "HEADER-Marinade", "1.5 Tsp White Peppercorns", - "2 Tsp Toasted Coriander Seeds", - "1 stalk Lemongrass, bottom half only, thinly sliced", - "5 cloves Garlic", + "2 Tsp Coriander Seeds, Toasted", + "1 Stalk Lemongrass, bottom half only, thinly sliced", + "5 Cloves Garlic", "3 Tbsp Soy Sauce", "3 Tbsp Fish Sauce", "1 Tbsp Black Soy Sauce", "1 Tbsp Sugar", - "0.5 Cup Water", + "0.5 Cups Water", "2 Tbsp Vegetable Oil", "HEADER-Dipping Sauce - Nam Jim Jeaw", - "2 Tbsp Thai Tamarind Paste, store bought or homemade", - "1 Tbsp Palm Sugar, finely chopped, or light brown sugar", + "2 Tbsp Thai Tamarind Paste", + "1 Tbsp Palm Sugar, Finely Chopped", "1 Tbsp Fish Sauce", "1 Tbsp Lime Juice", "Chili Flakes, to taste", - "1 Tbsp Shallots, finely chopped", - "1 Tbsp Green Onion, chopped", - "3 sprigs Cilantro, chopped", + "1 Tbsp Shallots, Finely Chopped", + "1 Tbsp Green Onion, Chopped", + "3 sprigs Cilantro, Chopped", "1 Tbsp Toasted Rice Powder" ), listOf( "HEADER-Marinade", - "Grind White Peppercorns [1.5 Tsp] and Coriander Seeds [2 Tsp] into a powder. Add Lemongrass [1 stalk] and Garlic [5 cloves] and pound into a paste. Transfer to a bowl. Add Soy Sauce [3 Tbsp], Fish Sauce [3 Tbsp], Black Soy Sauce [1 Tbsp], Sugar [1 Tbsp], Water [0.5 Cup], and Vegetable Oil [2 Tbsp]. Stir to dissolve Sugar.", + "Grind White Peppercorns [1.5 Tsp] and Coriander Seeds [2 Tsp] into a powder. Add Lemongrass [1 stalk] and Garlic [5 cloves] and pound into a paste.", + "Transfer to a bowl. Add Soy Sauce [3 Tbsp], Fish Sauce [3 Tbsp], Black Soy Sauce [1 Tbsp], Sugar [1 Tbsp], Water [0.5 Cup], and Vegetable Oil [2 Tbsp]. Stir to dissolve Sugar.", "Split Chicken Breast [1 whole] into halves, separate Chicken Legs [2] into thighs and drumsticks, and trim excess thigh skin.", "Place Chicken in a bag or dish, pour Marinade over, and ensure all pieces are coated. Marinate for 2 hours or overnight, flipping halfway.", + "HEADER-Dipping Sauce - Nam Jim Jeaw", "Toast raw rice in a dry skillet until dark brown. Cool, then grind into Toasted Rice Powder [1 Tbsp].", "Combine Thai Tamarind Paste [2 Tbsp], Fish Sauce [1 Tbsp], Lime Juice [1 Tbsp], and Palm Sugar [1 Tbsp]. Stir until Sugar dissolves.", "Add Chili Flakes and Shallots [1 Tbsp]. Just before serving, stir in Green Onions [1 Tbsp], Cilantro [3 sprigs], and Toasted Rice Powder [1 Tbsp].", + "HEADER-Grilling", "Bring Chicken to room temperature 45 minutes before cooking. Preheat grill to medium.", "Place Chicken skin-side up on grill (use cooler spots to prevent burning).", "Reduce heat to low-medium. Cook with lid closed, flipping every 5 minutes, 18-30 minutes total.", - "Use a meat thermometer: Chicken Breast to 160°F (72°C), drums/thighs to 175°F (80°C)." ), tags = mapOf( "Laotian" to TagType.CUISINE, @@ -64,6 +67,7 @@ val laoList = listOf( "Carnivorous" to TagType.PROTEIN, "Entree" to TagType.COURSE ), - image = Res.drawable._10_strawberries, + image = Res.drawable.gai_yang, + ttt = TTT.TRIED, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/SEAData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/SEAData.kt index 0888435..d2f0928 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/SEAData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/SEAData.kt @@ -7,19 +7,20 @@ import bakersmenagerie.composeapp.generated.resources.ayam_kecap import bakersmenagerie.composeapp.generated.resources.inasal import bakersmenagerie.composeapp.generated.resources.opor_ayam import bakersmenagerie.composeapp.generated.resources.satay +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val seaList = listOf( Recipe( title = "Opor Ayam", - description = "Chicken with carmelised Onion in a rich coconut gravy.", + 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", + "1.5 kg Protein of Choice (Originally Chicken)", "2 Cloves Garlic", "8 Shallots", "1 cm piece Turmeric Root", @@ -74,32 +75,33 @@ val seaList = listOf( "Simmered" to TagType.TECHNIQUE ), image = Res.drawable.opor_ayam, + ttt = TTT.TESTED, ), Recipe( title = "Ayam Kecap", description = "Indonesian Sweet Soy Chicken", ingredients = listOf( - "800g Protein of Choice (boneless or with bones, cut into pieces)", + "800g Protein of Choice (Originally Chicken)", "3 Tbsp Tamarind juice", "1 Tsp Salt (for marinade)", - "2 medium Onions (sliced)", - "2 Cloves Garlic (finely sliced)", - "2 Red or green chillies (sliced diagonally)", + "2 medium Onions, Sliced", + "2 Cloves Garlic, finely Sliced", + "2 Red or green chillies, Sliced", "0.5 Tsp Coarse black pepper", - "0.33 Cup Kecap Manis (sweet soy sauce)", + "0.33 Cup Kecap Manis", "Cooking Oil" ), instructions = listOf( - "Marinate the Protein with Tamarind juice [3 tbsp] and Salt [1 tsp]. Pierce the meat with a skewer or fork. Set aside for 30 minutes.", + "Marinate the Protein with Tamarind juice [3 tbsp] and Salt [1 tsp]. if using, pierce Meat with a skewer or fork. Set aside for 30 minutes.", "Heat oil in a wok or frying pan. Deep-fry or steam-fry the Protein until cooked.", - "For steam-frying, Heat [2 tbsp] oil and fry Protein until opaque. Cover and steam-cook until done (12-25 minutes depending on bone-in/boneless). Set aside.", - "Fry Onions [2 medium] in [4-5 tbsp] oil until light golden. Add Garlic [2 cloves] and chillies [2]. Fry for 3 minutes.", + "For steam-frying, Heat [2 tbsp] oil and fry Protein until opaque. Cover and steam-cook until done (15 minutes). Set aside.", + "Fry Onions [2 medium] in oil [4-5 tbsp] until light golden. Add Garlic [2 cloves] and chillies [2]. Fry for 3 minutes.", "Add Kecap Manis [0.33 cup], black pepper [0.5 tsp], and Salt [1 tsp]. Cook for 3-5 minutes until sauce bubbles.", "Add fried Protein. Stir until coated with sauce. Simmer for 3 minutes. Turn off heat." ), prepTime = Duration.parse("30m"), - cookTime = Duration.parse("35m"), + cookTime = Duration.parse("30m"), tags = mapOf( "Indonesian" to TagType.CUISINE, "Entree" to TagType.COURSE, @@ -115,50 +117,51 @@ val seaList = listOf( ), image = Res.drawable.ayam_kecap, servings = "Serves 4", + ttt = TTT.TESTED, linkedRecipes = listOf( kecapManis, //Kecap Manis ) ), Recipe( title = "Chicken Satay", - description = "Indonesian grilled chicken skewers marinated in coconut milk and spices, served with a creamy peanut sauce.", - prepTime = Duration.parse("2h 15m"), // 2 hours marinade + 15 min prep + description = "Indonesian grilled Chicken skewers marinated in Coconut Milk and Spices, served with a creamy Peanut Sauce.", + prepTime = Duration.parse("8h 15m"), // 2 hours marinade + 15 min prep cookTime = Duration.parse("15m"), servings = "Serves 6-8", ingredients = listOf( "HEADER-Chicken Satay", - "0.25 cup Coconut Milk", - "2 Tbsp Reduced Sodium Soy Sauce", + "0.25 Cups Coconut Milk", + "2 Tbsp Soy Sauce", "2.5 Tsp Yellow Curry Powder", "1.5 Tsp Turmeric", - "3 cloves Garlic, minced", - "1 Tbsp freshly grated Ginger", + "3 Cloves Garlic, Minced", + "1 Tbsp Ginger, Grated", "1 Tbsp Brown Sugar", "1 Tbsp Fish Sauce", - "2 pounds boneless, skinless Chicken Thighs, cut into 1-inch chunks", + "2 lbs boneless, skinless Chicken Thighs, cut into 1-inch chunks", "1 Tbsp Canola Oil", - "Kosher Salt and freshly ground Black Pepper, to taste", + "Salt", "HEADER-Peanut Sauce", "3 Tbsp Creamy Peanut Butter", "1 Tbsp Kecap Manis", "4 Tbsp Lime Juice", "3 Tsp Brown Sugar", - "2.5 Tbsp Chili Garlic Sauce, or more, to taste", + "2.5 Tbsp Chili Garlic Sauce", "1 Tsp freshly grated Ginger", "2-3 Tbsp Water (for consistency)" ), instructions = listOf( "HEADER-Peanut Sauce", - "In a small bowl, whisk together Peanut Butter [3 Tbsp], Kecap Manis [1 Tbsp], Lime Juice [4 Tbsp], Brown Sugar [3 Tsp], Chili Garlic Sauce [2.5 Tbsp], and Ginger [1 Tsp].", + "Whisk together Peanut Butter [3 Tbsp], Kecap Manis [1 Tbsp], Lime Juice [4 Tbsp], Brown Sugar [3 Tsp], Chili Garlic Sauce [2.5 Tbsp], and Ginger [1 Tsp].", "Whisk in Water [2-3 Tbsp] until desired consistency is reached; set aside.", "HEADER-Chicken Marinade", - "In a medium bowl, combine Coconut Milk [0.25 cup], Soy Sauce [2 Tbsp], Curry Powder [2.5 Tsp], Turmeric [1.5 Tsp], Garlic [3 cloves], Ginger [1 Tbsp], Brown Sugar [1 Tbsp], and Fish Sauce [1 Tbsp].", - "In a gallon size Ziploc bag or large bowl, combine Chicken [2 pounds] and Coconut Milk mixture; marinate for at least 2 hours to overnight, turning the bag occasionally.", + "Combine Coconut Milk [0.25 Cups], Soy Sauce [2 Tbsp], Curry Powder [2.5 Tsp], Turmeric [1.5 Tsp], Garlic [3 Cloves], Ginger [1 Tbsp], Brown Sugar [1 Tbsp], and Fish Sauce [1 Tbsp].", + "Combine Chicken [2 pounds] and Coconut Milk mixture; marinate overnight, turning occasionally.", "HEADER-Cooking", - "Drain the Chicken from the marinade, discarding the marinade.", + "Drain the Chicken from the Marinade, discarding the Marinade.", "Preheat grill to medium-high heat. Thread Chicken onto skewers. Brush with Canola Oil [1 Tbsp]; season with Salt and Pepper, to taste.", "Add skewers to grill, and cook, turning occasionally, until the Chicken is completely cooked through, reaching an internal temperature of 165 degrees F, about 12-15 minutes. [alternatively, bake on the skewer, then broil, or just broil].", @@ -180,7 +183,8 @@ val seaList = listOf( "Sauce" to TagType.TECHNIQUE, "Condiment" to TagType.COURSE, ), - image = Res.drawable.satay, // Replace with your image resource + image = Res.drawable.satay, + ttt = TTT.TRUE, linkedRecipes = listOf( kecapManis, //Kecap Manis ), @@ -196,24 +200,24 @@ val seaList = listOf( "1 lbs Chicken, cut into serving pieces", "1 Tbsp Ginger, minced", "1 Tbsp Garlic, minced", - "0.33 Cup Lemongrass, chopped", - "0.5 Cup Coconut Vinegar", - "0.25 Cup Lemon or Calamansi Juice", + "0.33 Cups Lemongrass, chopped", + "0.5 Cups Coconut Vinegar", + "0.25 Cups Lemon Juice", "0.5 Tbsp Salt", - "0.125 Cup Brown Sugar", - "0.5 Cup Lemon Soda", + "0.125 Cups Brown Sugar", + "0.5 Cups Lemon Soda", "0.25 Tbsp Ground Black Pepper", "HEADER-Basting Sauce", - "1.5 Tbsp Annatto Oil [See Annatto Substitute]", - "0.25 Cup Margarine, softened", + "1.5 Tbsp Annatto Oil", + "0.25 Cups Margarine, softened", "0.125 Tsp Salt", - "0.5 Tsp Lemon or Calamansi Juice" + "0.5 Tsp Lemon Juice" ), instructions = listOf( - "In a freezer bag or large bowl, combine Chicken [1 lbs], Lemongrass [0.33 Cup], Salt [0.5 Tbsp], Ground Black Pepper [0.25 Tbsp], Ginger [1 Tbsp], Garlic [1 Tbsp], Brown Sugar [0.125 Cup], Coconut Vinegar [0.5 Cup], Lemon Soda [0.5 Cup], and Lemon Juice [0.25 Cup].", + "Combine Chicken [1 lbs], Lemongrass [0.33 Cups], Salt [0.5 Tbsp], Ground Black Pepper [0.25 Tbsp], Ginger [1 Tbsp], Garlic [1 Tbsp], Brown Sugar [0.125 Cups], Coconut Vinegar [0.5 Cups], Lemon Soda [0.5 Cups], and Lemon Juice [0.25 Cups].", "Stir or shake the mixture until every ingredient is well incorporated. Marinade for 1 to 3 hours.", - "In a bowl, combine Margarine [0.25 Cup], Annatto Oil [1.5 Tbsp], Salt [0.125 Tsp], and Lemon Juice [0.5 Tsp] then stir. Set aside.", + "In a bowl, combine Margarine [0.25 Cups], Annatto Oil [1.5 Tbsp], Salt [0.125 Tsp], and Lemon Juice [0.5 Tsp] then stir. Set aside.", "Grill the Chicken while basting generous amount of the Margarine mixture.", "Transfer the grilled Chicken to a serving plate.", "Serve with Sinamak. [Recipe included]" @@ -227,6 +231,7 @@ val seaList = listOf( "Carnivorous" to TagType.PROTEIN, ), image = Res.drawable.inasal, + ttt = TTT.TESTED, linkedRecipes = listOf(sinamak) ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/Sinamak.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/Sinamak.kt index 22b6e39..2678861 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/Sinamak.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/asia/Sinamak.kt @@ -4,10 +4,11 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources._10_strawberries +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val sinamak = Recipe( - title = "Sinamak [Filipino]", + title = "Sinamak", description = "A spicy Filipino condiment made with Cane Vinegar, Siling Labuyo [Red Chili], Ginger, and other spices. Best served with grilled or fried dishes.", prepTime = Duration.parse("10m"), cookTime = Duration.ZERO, // No cooking involved @@ -34,5 +35,6 @@ val sinamak = Recipe( "Tangy" to TagType.FLAVOUR, "Vegan" to TagType.PROTEIN, ), - image = Res.drawable._10_strawberries // Replace with your image resource + image = Res.drawable._10_strawberries, + ttt = TTT.TRIED ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/FrenchData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/FrenchData.kt index 6c5fb02..4faf2c0 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/FrenchData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/FrenchData.kt @@ -4,6 +4,7 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources.cordon_bleu +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val frenchList = listOf( @@ -16,10 +17,10 @@ val frenchList = listOf( ingredients = listOf( "4 Chicken Breasts", ".25 Tsp Salt", - ".125 Tsp Pepper", + "0.125 Tsp Pepper", "6 Slices Swiss Cheese", "4 Slices Cooked Ham", - ".5 Cup Bread Crumbs", + "0.5 Cups Bread Crumbs", ), instructions = listOf( "Preheat oven to 350F.", @@ -42,5 +43,6 @@ val frenchList = listOf( "Breaded" to TagType.TECHNIQUE ), image = Res.drawable.cordon_bleu, + ttt = TTT.TRIED, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Georgian.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Georgian.kt index 68883fe..f78d37c 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Georgian.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Georgian.kt @@ -4,6 +4,7 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources.shkmeruli +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val georgianList = listOf( @@ -12,23 +13,25 @@ val georgianList = listOf( description = "Georgian chicken dish cooked in a creamy garlic sauce, known for its rich and flavorful broth.", prepTime = Duration.parse("15m"), cookTime = Duration.parse("45m"), - servings = "Serves 4-6", + servings = "Serves 5", ingredients = listOf( - "2 pounds skin-on Chicken Breast, Legs, and Thighs", + "2 lbs Chicken Breast, Legs, and Thighs, skin-on", "1 Tbsp Salt", - "3 Tbsp Clarified Butter or Ghee", - "0.25 cup All-Purpose Flour", - "0.25 cup Rice Flour (can be substituted with All-Purpose Flour)", + "3 Tbsp Ghee", + "0.25 Cups All-Purpose Flour", + "0.25 Cups Rice Flour", "5 Tbsp Large Garlic Cloves (minced)", - "1.5 cups Whole Milk", + "1.5 Cups Whole Milk", "1 Tsp Khmeli Suneli Spice Blend", "Freshly Ground Black Pepper (to taste)" ), instructions = listOf( "Pat dry the Chicken pieces and generously season with Salt [1 Tbsp].", - "Melt 2 Tbsp of Clarified Butter in a medium-large heavy-bottomed pan or deep skillet. Cast iron or Dutch oven works best for this. Heat the Clarified Butter until shimmering.", - "Mix the Rice Flour [0.25 cup] and All-Purpose Flour [0.25 cup] in a shallow bowl. Dredge the Chicken pieces in Flour and transfer to the hot skillet. Fry on both sides until the skin is golden brown and crispy, about 5 minutes per side. When the first batch is done, remove from the pan and continue with the rest of the Chicken.", - "When all the pieces are fried, wipe the pan clean and melt the remaining 1 Tbsp of Clarified Butter. Add Garlic [5 Tbsp] and cook, stirring, for 20 seconds. Pour in the Whole Milk [1.5 cups] and bring to a simmer. Mix in the Khmeli Suneli Spice Blend [1 Tsp], if using. Lower the heat to medium-low and add the fried Chicken pieces. Simmer for 25 minutes until the Chicken is tender and cooked through. If needed, season with more Salt and Freshly Ground Black Pepper." + "Melt Ghee [2 Tbsp] in a heavy-bottomed pan or deep skillet. Heat the Ghee until shimmering.", + "Mix the Rice Flour [0.25 Cups] and All-Purpose Flour [0.25 Cups] in a shallow bowl. Dredge the Chicken pieces in Flour and transfer to the hot skillet. Fry on both sides until the skin is golden brown and crispy, about 5 minutes per side. When the first batch is done, remove from the pan and continue with the rest of the Chicken.", + "When all the pieces are fried, wipe the pan clean and melt the remaining Ghee [1 Tbsp]. Add Garlic [5 Tbsp] and cook, stirring, for 20 seconds.", + "Pour in the Whole Milk [1.5 cups] and bring to a simmer. Mix in the Khmeli Suneli Spice Blend [1 Tsp]. Lower the heat to medium-low and add the fried Chicken pieces.", + "Simmer for 25 minutes until the Chicken is tender and cooked through. If needed, season with more Salt and Freshly Ground Black Pepper." ), tags = mapOf( "Georgian" to TagType.CUISINE, @@ -40,6 +43,7 @@ val georgianList = listOf( "Creamy" to TagType.FLAVOUR, "Carnivorous" to TagType.PROTEIN, ), - image = Res.drawable.shkmeruli, // Replace with your image resource + image = Res.drawable.shkmeruli, + ttt = TTT.TRIED, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Greek.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Greek.kt index f064830..81e8a21 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Greek.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Greek.kt @@ -1,10 +1,11 @@ package com.menagerie.bakers.model.europe -import com.menagerie.bakers.model.Recipe -import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res -import bakersmenagerie.composeapp.generated.resources._10_strawberries +import bakersmenagerie.composeapp.generated.resources.greek_chicken import bakersmenagerie.composeapp.generated.resources.gyros +import com.menagerie.bakers.model.Recipe +import com.menagerie.bakers.model.TTT +import com.menagerie.bakers.model.TagType import kotlin.time.Duration val greekList = listOf( @@ -15,15 +16,15 @@ val greekList = listOf( "HEADER-Gyros", "2 Pieces of Pita Bread", - "10-12 Ounces Protein of Choice", - "3 Oz Arugula", - "1 Plum Tomato, sliced", + "12 oz Protein of Choice", + "3 oz Arugula", + "1 Plum Tomatoes, sliced", "Salt & Pepper to Taste", "HEADER-Tahini Sauce", - "2 Oz Sour Cream", - "2 Oz Tahini", - "1 Lemon", + "2 oz Sour Cream", + "2 oz Tahini", + "1 Lemons", "1 Tbsp Garlic, Minced", "HEADER-Pickled Shallots", @@ -51,23 +52,24 @@ val greekList = listOf( servings = "Makes 2 Gyros", prepTime = Duration.parse("30m"), cookTime = Duration.parse("30m"), - image = Res.drawable.gyros + image = Res.drawable.gyros, + ttt = TTT.TRUE, ), Recipe( title = "Greek Balsamic Glazed Chicken", - description = "Strips of Chicken Breast grilled with a rich and tangy balsamic glaze.", + description = "Strips of Chicken Breast grilled with a rich and tangy Balsamic glaze.", ingredients = listOf( "2 Chicken Breasts", - ".25 Cup Olive Oil", - ".25 Cup Golden Balsamic", - ".125 Cup Garlic-Mustard", + "0.25 Cups Olive Oil", + "0.25 Cups Golden Balsamic", + "0.125 Cup Garlic-Mustard", "1.5 Tbsp Balsamic Glaze", - "3 Cloves Garlic, minced", + "3 Cloves Garlic, Minced", "Juice of 1 Lemon", - "1 Tbsp each Tarragon, Rosemary, Thyme, chopped", + "1 Tbsp EACH Tarragon, Rosemary, Thyme, Chopped", "2 Tsp Salt", - ".5 Tsp Black Pepper" + "0.5 Tsp Black Pepper" ), instructions = listOf( "Mix all ingredients together. Marinate for 4hs, up to overnight.", @@ -87,6 +89,7 @@ val greekList = listOf( servings = "Serves 3 to 4", cookTime = Duration.parse("20m"), prepTime = Duration.parse("4h"), - image = Res.drawable._10_strawberries + image = Res.drawable.greek_chicken, + ttt = TTT.TRUE, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Hungarian.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Hungarian.kt index 9b2ad6f..bb296b5 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Hungarian.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Hungarian.kt @@ -1,39 +1,40 @@ package com.menagerie.bakers.model.europe -import com.menagerie.bakers.model.Recipe -import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res -import bakersmenagerie.composeapp.generated.resources._10_strawberries +import bakersmenagerie.composeapp.generated.resources.paprikash +import com.menagerie.bakers.model.Recipe +import com.menagerie.bakers.model.TTT +import com.menagerie.bakers.model.TagType import kotlin.time.Duration val hungarianList = listOf( Recipe( title = "Paprikash", - description = "A classic Hungarian stew with tender chicken in a rich paprika-infused sour cream sauce.", + description = "A classic Hungarian stew with tender Chicken in a rich Paprika-infused Sour Cream sauce.", prepTime = Duration.parse("20m"), cookTime = Duration.parse("1h 10m"), servings = "Serves 4-6", ingredients = listOf( "2 Tbsp Pork Lard", - "3 pounds Chicken Pieces (bone-in, skin-on)", + "3 lbs Chicken Pieces (bone-in, skin-on)", "2 medium Yellow Onions (very finely chopped)", "2 cloves Garlic (finely minced)", "2 Roma Tomatoes (seeds removed, very finely diced)", "1 Hungarian Bell Pepper (diced, optional)", - "3-4 Tbsp Hungarian Paprika", - "2 cups Chicken Broth", + "3.5 Tbsp Hungarian Paprika", + "2 Cups Chicken Broth", "1.5 Tsp Sea Salt", "0.5 Tsp Freshly Ground Black Pepper", "3 Tbsp All-Purpose Flour", - "0.75 cup Full Fat Sour Cream (room temperature)", - "0.25 cup Heavy Whipping Cream" + "0.75 Cups Full Fat Sour Cream (room temperature)", + "0.25 Cups Heavy Whipping Cream" ), instructions = listOf( - "Heat the Pork Lard [2 Tbsp] in a heavy pot and brown the Chicken Pieces [3 pounds] on all sides. Transfer the Chicken to a plate.", + "Heat the Pork Lard [2 Tbsp] in a heavy pot and brown the Chicken Pieces [3 lbs] on all sides. Transfer the Chicken to a plate.", "In the same oil, add the Yellow Onions [2 medium] and fry until golden brown. Add the Garlic [2 cloves] and Tomatoes [2 Roma] (and Bell Pepper [1] if using) and fry another 2-3 minutes.", - "Remove the pot from the heat and stir in the Hungarian Paprika [3-4 Tbsp], Sea Salt [1.5 Tsp], and Black Pepper [0.5 Tsp].", + "Remove the pot from the heat and stir in the Hungarian Paprika [3.5 Tbsp], Sea Salt [1.5 Tsp], and Black Pepper [0.5 Tsp].", "Return the Chicken to the pot and place it back over the heat. Pour in the Chicken Broth [2 cups]. The Chicken should be mostly covered. Bring it to a boil. Cover, reduce the heat to medium-low, and simmer for 40 minutes. Remove the Chicken and transfer to a plate.", - "In a small bowl, stir the All-Purpose Flour [3 Tbsp] into the Sour Cream [0.75 cup] and Heavy Whipping Cream [0.25 cup] mixture to form a smooth paste. Stir the Cream mixture into the sauce, whisking constantly to prevent lumps. Bring it to a simmer for a couple of minutes until the sauce is thickened. Add Sea Salt and Black Pepper to taste.", + "In a small bowl, stir the All-Purpose Flour [3 Tbsp] into the Sour Cream [0.75 Cups] and Heavy Whipping Cream [0.25 Cups] mixture to form a smooth paste. Stir the Cream mixture into the sauce, whisking constantly to prevent lumps. Bring it to a simmer for a couple of minutes until the sauce is thickened. Add Sea Salt and Black Pepper to taste.", "Return the Chicken to the sauce and simmer to heat through.", "Serve the Chicken Paprikash with Hungarian Nokedli." ), @@ -48,6 +49,7 @@ val hungarianList = listOf( "Creamy" to TagType.FLAVOUR, "Carnivorous" to TagType.PROTEIN, ), - image = Res.drawable._10_strawberries, // Replace with your image resource + image = Res.drawable.paprikash, + ttt = TTT.TRIED, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/IrishData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/IrishData.kt index b309793..c3451ef 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/IrishData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/IrishData.kt @@ -4,12 +4,13 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources.spiceBag +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val irishList = listOf( Recipe( title = "Spice Bag", - description = "Irish-Chinese Takeaway Dish of Chicken, Chips, and Veg in a bag with salt and chili spice.", + description = "Irish-Chinese Takeaway Dish of Chicken, Chips, and Veg in a bag with Salt and Chili spice.", prepTime = Duration.parse("15m"), cookTime = Duration.parse("15m"), servings = "Makes 10 Bags", @@ -19,8 +20,8 @@ val irishList = listOf( "2 Kg Chicken Pieces", "4 Star Anise", "Juice of 2 Lemon", - "10 Beaten Eggs", - "200g Potato Flour", + "5 Beaten Eggs", + "250g Potato Flour", "Oil for Frying", "Salt", @@ -33,7 +34,7 @@ val irishList = listOf( "2 Shallots", "Salt", - "HEADER-Spice Mix", + "HEADER-Spice Mix (Make Ahead)", "2 Tbsp Course Salt", "1 Tsp White Pepper", "1 Tsp Five Spice Powder", @@ -41,8 +42,8 @@ val irishList = listOf( "4 Red Chillies, Fine Diced", ), instructions = listOf( - "Mix Egg Wash [10 Eggs], with Lemon Juice [1 Lemon], and ground Star Anise [4]. Coat the Chicken in this wash.", - "Toss the Chicken in the Potato Flour, shaking off the excess.", + "Mix Egg Wash [5 Eggs], with Lemon Juice [1 Lemon], and ground Star Anise [4]. Coat the Chicken in this wash.", + "Toss the Chicken in the Potato Flour [250g], shaking off the excess.", "Deep Fry Chicken at 360F for about 6 minutes", "Deep Fry The Chips.", "Fry Veg in a Wok. Add half the Spice Mix and toss to coat.", @@ -62,5 +63,6 @@ val irishList = listOf( "Street Food" to TagType.CUISINE ), image = Res.drawable.spiceBag, + ttt = TTT.TRIED, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/ItalianData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/ItalianData.kt index 59d2726..9a5ed86 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/ItalianData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/ItalianData.kt @@ -8,6 +8,7 @@ import bakersmenagerie.composeapp.generated.resources._10_strawberries import bakersmenagerie.composeapp.generated.resources.assassins_pasta import bakersmenagerie.composeapp.generated.resources.cacciatore import bakersmenagerie.composeapp.generated.resources.chicken_parmesan +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val italianList = listOf( @@ -19,19 +20,19 @@ val italianList = listOf( servings = "1 Batch", ingredients = listOf( "1 Bunch of Fresh Basil", - ".5 Cup to .75 Cup of fresh Mozzarella Cheese, hand shredded", - ".25 Cup Minced Garlic", - "Smoked Paprika", - ".25 Tsp Cayenne Powder", - "Salt and Pepper to taste", - "Olive Oil [as needed for consistency]", - "Garlic oil, for taste", - "White Wine, Fruity [such as layer cake]", - "2 caps of Lemon Juice", + "0.5 Cups Mozzarella Cheese, hand shredded", + "0.25 Cups Garlic, Minced", + "0.5 Tsp Smoked Paprika", + "0.25 Tsp Cayenne Powder", + "Salt to taste", + "Garlic Olive Oil [as needed for consistency]", + "2 Tbsp White Wine, Semi-Sweet", + "2 Tsp of Lemon Juice", ), instructions = listOf( - "Shred Basil in a blender, slowly adding Oil until it blends smooth", - "Add in Cheese, Garlic, and Spices, blend, adding more Oil as needed" + "Shred Basil [1 Bunch] in a blender, slowly adding Garlic Oil until it blends smooth", + "Add Wine [2 Tbsp] and Mozzarella [0.5 Cups] and blend again.", + "Add in Garlic [0.25 Cups], Paprika [0.5 Tsp], Cayenne [0.25 Tsp], and Lemon Juice [2 Tbsp], blend, adding more Oil as needed." ), tags = mapOf( "Italian" to TagType.CUISINE, @@ -41,6 +42,7 @@ val italianList = listOf( "Tangy" to TagType.FLAVOUR, ), image = Res.drawable.Pesto, + ttt = TTT.TRUE, ), Recipe( @@ -51,21 +53,25 @@ val italianList = listOf( servings = "Makes 4 Cutlets", ingredients = listOf( "2 Large Chicken Breasts", - ".5 Cup Flour", + + "HEADER-Breading", + "0.5 Cups Flour", "1 Tsp Salt", - ".5 Tsp Pepper", + "0.5 Tsp Pepper", "2 Eggs, Beaten", - ".5 Cup Panko", - ".5 Cup Parmesan, grated", + "0.5 Cups Panko", + "0.5 Cups Parmesan, grated", + + "HEADER-Finishing", "2 Tbsp Olive Oil", "24 Oz Marinara Sauce", - "1.5 Cup Shredded Mozzarella Cheese", + "1.5 Cups Shredded Mozzarella Cheese", "1 Tbsp Fresh Basil Leaves, Chopped", ), instructions = listOf( "Heat the Oven to 425F", "Slice the Chicken Breasts [2] in half lengthwise to make [4] Cutlets", - "Stir together Flour [.5 Cup], Salt [1 Tsp], Pepper [.5 Tsp]. In another bowl, Stir together Panko [.5 Cup] and Parmesan [.5 Cup]", + "Stir together Flour [0.5 Cups], Salt [1 Tsp], Pepper [0.5 Tsp]. In another bowl, Stir together Panko [0.5 Cups] and Parmesan [0.5 Cups]", "Coat Chicken in Flour Mixture, then Beaten Eggs, then Panko-Parm Mixture. Heat Olive Oil [2 Tbsp] in a shallow pan and saute the Chicken 3-4 min" + " per side, until Golden Brown", "Pour Half the Marinara [12 Oz] into a 9x13 Casserole Dish. Arrange Cutlets in a single layer. Slather each with the rest of the Marinara [12 Oz] then" + @@ -81,6 +87,7 @@ val italianList = listOf( "Creamy" to TagType.FLAVOUR ), image = Res.drawable.chicken_parmesan, + ttt = TTT.TESTED, ), Recipe( @@ -91,13 +98,13 @@ val italianList = listOf( servings = "Serves 4", ingredients = listOf( "4 Cups Water", - "1 (28 Oz) Can Tomato Puree", + "28 oz Tomato Puree", "2 Tbsp Tomato Paste", "1 Tsp Salt", "2 Tbsp Olive Oil", "3 Cloves Garlic", "1 Tsp Red Pepper Flakes", - "16 Oz Spaghetti", + "16 oz Spaghetti", ), instructions = listOf( "Add Water [4 Cups] to a medium saucepan and bring to a boil. Add about 1/3rd of the Tomato Puree [9 oz] and the Tomato Paste [2 Tbsp]. " + @@ -120,10 +127,11 @@ val italianList = listOf( "Burnt" to TagType.FLAVOUR, ), image = Res.drawable.assassins_pasta, + ttt = TTT.TESTED, ), Recipe( title = "Cacio e Pepe", - description = "A simple yet flavorful Italian pasta dish with Pecorino Romano cheese and black pepper.", + description = "A simple yet flavorful Italian pasta dish with Pecorino Romano Cheese and Black Pepper.", prepTime = Duration.parse("5m"), cookTime = Duration.parse("20m"), servings = "Serves 4", @@ -156,10 +164,11 @@ val italianList = listOf( "Tossed" to TagType.TECHNIQUE, ), image = Res.drawable._10_strawberries, // Replace with your image resource + ttt = TTT.TRIED ), Recipe( title = "Chicken Cacciatore", - description = "A hearty Italian stew with bone-in Chicken Thighs, Mushrooms, Onions, and Bell Peppers in a rich tomato and wine sauce.", + description = "A hearty Italian stew with bone-in Chicken Thighs, Mushrooms, Onions, and Bell Peppers in a rich Tomato and Wine sauce.", prepTime = Duration.parse("20m"), cookTime = Duration.parse("45m"), servings = "Serves 4-6", @@ -183,10 +192,14 @@ val italianList = listOf( "1 Large Red Bell Pepper, ribs and seeds removed, chopped" ), instructions = listOf( - "Heat a large Dutch oven or skillet over medium heat. Add the Olive Oil [1 Tbsp]. Season the Chicken pieces with Salt and Pepper. Add half the Chicken and Cook, skin side down, until crisp and browned. Turn the pieces over and Cook another 5 minutes. Remove to a plate and continue Browning in small batches until all Chicken is browned. Reserve 1 tablespoon of the drippings in the pan.", + "Heat a large Dutch oven or skillet over medium heat. Add the Olive Oil [1 Tbsp].", + "Season the Chicken pieces with Salt and Pepper. Add half the Chicken and Cook, skin side down, until crisp and browned.", + "Turn the pieces over and Cook another 5 minutes. Remove to a plate and continue Browning in small batches until all Chicken is browned. Reserve [1 Tbsp] of the drippings in the pan.", "Add the Onions [1 Large], Mushrooms [8 Ounces] and a pinch of Salt to the pan with the reserved drippings. Cook over medium-high heat until the vegetables begin to brown and the moisture evaporates.", - "Add the Garlic [3 Cloves] and Red Pepper Flakes [0.5 Tsp] to the pan and sauté until fragrant, about 30 seconds. Stir in the Flour [2 Tbsp] and continuing Cooking and stirring for 1 more minute. Add the Wine [1 Cup], Tomatoes [14.5 Ounce], Tomato Paste [2 Tbsp], Bay Leaves [3], Parmesan Rind [1], Thyme [1 Tbsp or 1 Tsp], Oregano [1 Tsp] and Red Bell Pepper [1 Large].", - "Remove the skin from the Chicken and discard. Add the skinless Chicken pieces to the pan, pressing them down into the sauce so they are covered. Bring to a boil, cover and reduce the heat to low. Simmer until the Chicken is tender, about 40-45 minutes. Halfway through cooking, move the Chicken pieces around and/or turn them over to ensure even cooking.", + "Add the Garlic [3 Cloves] and Red Pepper Flakes [0.5 Tsp] to the pan and sauté until fragrant, about 30 seconds. Stir in the Flour [2 Tbsp] and continuing Cooking and stirring for 1 more minute.", + "Add the Wine [1 Cup], Tomatoes [14.5 Ounce], Tomato Paste [2 Tbsp], Bay Leaves [3], Parmesan Rind [1], Thyme [1 Tbsp or 1 Tsp], Oregano [1 Tsp] and Red Bell Pepper [1 Large].", + "Remove the skin from the Chicken and discard. Add the skinless Chicken pieces to the pan, pressing them down into the sauce so they are covered. ", + "Bring to a boil, cover and reduce the heat to low. Simmer until the Chicken is tender, about 40-45 minutes. Halfway through cooking, move the Chicken pieces around and/or turn them over to ensure even cooking.", "Remove the Bay Leaves [3] and Parmesan Rind [1] and discard. Check seasoning and add Salt and Pepper if needed. Garnish with fresh chopped Parsley leaves. Serve over hot cooked Spaghetti or Polenta." ), tags = mapOf( @@ -197,6 +210,7 @@ val italianList = listOf( "Herby" to TagType.FLAVOUR, "Carnivorous" to TagType.PROTEIN, ), - image = Res.drawable.cacciatore + image = Res.drawable.cacciatore, + ttt = TTT.TRIED, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Romanian.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Romanian.kt index ec3a1af..7972f80 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Romanian.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/europe/Romanian.kt @@ -4,6 +4,7 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources.ostropel +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val romanianList = listOf( @@ -15,9 +16,9 @@ val romanianList = listOf( servings = "Serves 4-6", ingredients = listOf( "1 kg Chicken Legs (skin-on, bone-in, or mix with boneless)", - "1 medium Onion", - "1 head Garlic", - "2-3 Tbsp Oil", + "1 medium Onions", + "1 Head Garlic", + "2.5 Tbsp Oil", "Salt", "Pepper", "100 ml Dry White Wine", @@ -25,8 +26,8 @@ val romanianList = listOf( "A handful of chopped Green Parsley" ), instructions = listOf( - "Prepare the Ingredients: Chop the Onion [1 medium] and roughly chop half of the Garlic [1 head, about 5 cloves]. Slice the remaining Garlic [5 cloves].", - "Fry the Chicken: In a large pan, heat Oil [2-3 Tbsp] over high heat. Season Chicken Legs [1 kg] with Salt and Pepper. Fry the Chicken until golden brown on both sides, about 8-10 minutes. Do not overcrowd the pan.", + "Prepare the Ingredients: Chop the Onion [1 medium] and roughly chop half of the Garlic [0.5 Head, about 5 Cloves]. Slice the remaining Garlic [5 cloves].", + "Fry the Chicken: In a large pan, heat Oil [2.5 Tbsp] over high heat. Season Chicken Legs [1 kg] with Salt and Pepper. Fry the Chicken until golden brown on both sides, about 8-10 minutes. Do not overcrowd the pan.", "Sauté Onions and Garlic: Do not remove the Chicken. Add chopped Onion and half of the chopped Garlic to the pan. Season with a pinch of Salt. Reduce heat to medium-low and sauté until the Onion is translucent, about 5 minutes.", "Deglaze with Wine: Pour Dry White Wine [100 ml] into the pan and cook for 2-3 minutes until the alcohol evaporates.", "Add Tomatoes: Add Canned Tomatoes [400 g] or Fresh Summer Tomatoes [600 g] (peeled and diced if desired) and Hot Water [200 ml] to the pan. If the sauce is too acidic, add a pinch of Sugar.", @@ -46,6 +47,7 @@ val romanianList = listOf( "Carnivorous" to TagType.PROTEIN, "Herby" to TagType.FLAVOUR, ), - image = Res.drawable.ostropel + image = Res.drawable.ostropel, + ttt = TTT.TRIED, ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/middleEast/PalestineData.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/middleEast/PalestineData.kt index 17c49de..f431f99 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/middleEast/PalestineData.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/model/middleEast/PalestineData.kt @@ -4,21 +4,22 @@ import com.menagerie.bakers.model.Recipe import com.menagerie.bakers.model.TagType import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources.mussakhan +import com.menagerie.bakers.model.TTT import kotlin.time.Duration val palestineList = listOf( Recipe( title = "Musakhan", - description = "Chicken and Onions on a flatbread drenched in Oil, Sumac, and Almonds.", + description = "Chicken and Onions on a Flatbread drenched in Oil, Sumac, and Almonds.", ingredients = listOf( "HEADER-Chicken Boil", - "1 Whole Large Chicken, precut into ~6 pieces", + "1 Whole Large Chickens, precut into ~6 pieces", "5 Cardamom Pods", "1 Tbsp Salt", "HEADER-Onions", - "600ml Olive Oil", + "600 ml Olive Oil", "12-14 Onions, Chopped", "1 Tsp Cumin, ground", "Black Pepper and Cinnamon, to Taste", @@ -26,15 +27,15 @@ val palestineList = listOf( "HEADER-To Serve", "150g Sumac", "6 Flatbreads", - ".5 Cup Pine Nuts", - ".75 Cup Almonds, sliced", + "0.5 Cups Pine Nuts", + "0.75 Cups Almonds, sliced", ), instructions = listOf( - "Boil the Chicken in water with [[5] Cardamom Pods and [[1 Tbsp] of Salt.", - "Heat Olive Oil in a large pan and saute Onions with Cumin [[1 Tsp], Black Pepper, Cinnamon, and [[1 Tbsp] Salt.", + "Boil the Chicken in water with [5] Cardamom Pods and [1 Tbsp] of Salt.", + "Heat Olive Oil in a large pan and saute Onions with Cumin [1 Tsp], Black Pepper, Cinnamon, and [1 Tbsp] Salt.", "Preheat oven to 475F/240C", "Arrange Chicken on a baking tray. Cover with some Onion, sprinkle with Sumac, and bake for 5 minutes or until browned.", - "To Serve, slather Flatbreads with onions, scatter the rest of the Sumac along with all the Nuts [[.5 Cup] and Almonds [[.75 Cup].", + "To Serve, slather Flatbreads with Onions, scatter the rest of the Sumac along with all the Nuts [.5 Cups] and Almonds [.75 Cups].", "Eat with your hands." ), tags = mapOf( @@ -52,6 +53,7 @@ val palestineList = listOf( prepTime = Duration.parse("20m"), cookTime = Duration.parse("1h 15m"), servings = "Serves 6 to 8 People", - image = Res.drawable.mussakhan + image = Res.drawable.mussakhan, + ttt = TTT.TRUE ) ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/util/ClipboardController.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/util/ClipboardController.kt new file mode 100644 index 0000000..6b9b6b4 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/util/ClipboardController.kt @@ -0,0 +1,5 @@ +package com.menagerie.bakers.util + +interface ClipboardController { + fun copyToClipboard(text: String) +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/util/rememberClipboardController.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/util/rememberClipboardController.kt new file mode 100644 index 0000000..2f30e38 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/util/rememberClipboardController.kt @@ -0,0 +1,6 @@ +package com.menagerie.bakers.util + +import androidx.compose.runtime.Composable + +@Composable +expect fun rememberClipboardController(): ClipboardController \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/Bookshelf.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/Bookshelf.kt index 2a595cb..c92bd20 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/Bookshelf.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/Bookshelf.kt @@ -42,7 +42,7 @@ fun BookShelf( Column( modifier = Modifier - .padding(top = 10.dp) + .padding(top = 10.dp, start = 20.dp, end = 20.dp) .align(Alignment.Center), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/Settings.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/Settings.kt new file mode 100644 index 0000000..28aac5d --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/Settings.kt @@ -0,0 +1,29 @@ +package com.menagerie.bakers.view + +import androidx.compose.runtime.Composable +import com.menagerie.bakers.SortBy +import com.menagerie.bakers.Theme +import com.menagerie.bakers.model.TTT + +@Composable +expect fun SettingsMenu( + theme: Theme, + onTheme: () -> Unit, + animate: Boolean, + onAnim: () -> Unit, + helpUs: Boolean, + onHelpToggle: (Boolean) -> Unit, + ttt: TTT, + onTTTToggle: () -> Unit, + andOr: Boolean, + onAndOr: () -> Unit, + sortBy: SortBy, + onSortToggle: () -> Unit, + descending: Boolean, + onDesc: () -> Unit, + onRandom: () -> Unit, + onBack: () -> Unit, + onClear: () -> Unit, + discreet: Boolean, + onDiscreet: () -> Unit, +) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/AnimateInEffect.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/AnimateInEffect.kt index f33ab85..6000c90 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/AnimateInEffect.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/AnimateInEffect.kt @@ -16,37 +16,43 @@ import com.menagerie.bakers.model.Recipe fun AnimateInEffect( intervalStart: Float = 0f, content: @Composable () -> Unit, - recipe: Recipe + recipe: Recipe, + animate: Boolean, ) { - val visibility = remember { Animatable(0f) } - val offset = remember { Animatable(30f) } - LaunchedEffect(recipe) { - delay((intervalStart * 1000).toLong()) - visibility.animateTo( - targetValue = 1f, - animationSpec = tween( - durationMillis = 300, - easing = LinearEasing - ) - ) - } - LaunchedEffect(recipe) { - delay((intervalStart * 1000).toLong()) - delay(intervalStart.toLong()) - offset.animateTo( - targetValue = 0f, - animationSpec = tween( - durationMillis = 300, - easing = LinearEasing - ) - ) - } + if (animate) { + val visibility = remember { Animatable(0f) } + val offset = remember { Animatable(30f) } - Box(modifier = Modifier.graphicsLayer { - this.translationY = offset.value - this.alpha = visibility.value - }) { - content() + LaunchedEffect(recipe) { + delay((intervalStart * 1000).toLong()) + visibility.animateTo( + targetValue = 1f, + animationSpec = tween( + durationMillis = 300, + easing = LinearEasing + ) + ) + } + LaunchedEffect(recipe) { + delay((intervalStart * 1000).toLong()) + delay(intervalStart.toLong()) + offset.animateTo( + targetValue = 0f, + animationSpec = tween( + durationMillis = 300, + easing = LinearEasing + ) + ) + } + + Box(modifier = Modifier.graphicsLayer { + this.translationY = offset.value + this.alpha = visibility.value + }) { + content() + } + } else { + Box { content() } } } diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/IngradientItem.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/IngredientItem.kt similarity index 64% rename from composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/IngradientItem.kt rename to composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/IngredientItem.kt index 135522e..9920f7e 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/IngradientItem.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/IngredientItem.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.selection.SelectionContainer +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -26,11 +27,12 @@ import bakersmenagerie.composeapp.generated.resources.chef import com.menagerie.bakers.DisplayManager import com.menagerie.bakers.Size import com.menagerie.bakers.model.Recipe +import com.menagerie.bakers.util.rememberClipboardController import org.jetbrains.compose.resources.painterResource @Composable -fun IngredientItem(recipe: Recipe, ingredient: String) { +fun IngredientItem(recipe: Recipe, ingredient: String, index: Int) { Box(modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp)) { Box( modifier = Modifier @@ -38,13 +40,24 @@ fun IngredientItem(recipe: Recipe, ingredient: String) { .padding(top = 8.dp) .border( width = 2.dp, - color = if (recipe.bgColor != MaterialTheme.colorScheme.primaryContainer) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.background, + color = if (recipe.bgColor != MaterialTheme.colorScheme.primaryContainer) { + if (index % 2 == 0) { + MaterialTheme.colorScheme.secondaryContainer + } else { + MaterialTheme.colorScheme.onBackground + } + } else + if (index % 2 == 0) { + MaterialTheme.colorScheme.background + } else { + MaterialTheme.colorScheme.onBackground + }, shape = RoundedCornerShape(35.dp) ) ) { SelectionContainer { - val style = when(DisplayManager.size) { + val style = when (DisplayManager.size) { Size.Small -> MaterialTheme.typography.bodySmall Size.Medium -> MaterialTheme.typography.bodyMedium Size.Large -> MaterialTheme.typography.bodyLarge @@ -72,12 +85,22 @@ fun IngredientItem(recipe: Recipe, ingredient: String) { CircleShape ), ) { - Image( - painter = painterResource(Res.drawable.chef), - contentDescription = null, - modifier = Modifier.padding(12.dp).rotate(-30f), - colorFilter = ColorFilter.tint(if (recipe.bgColor.luminance() > 0.3) Color.Companion.Black else Color.White) - ) + + val clipboardController = rememberClipboardController() + + IconButton(onClick = { + val actualIngredient = + ingredient.split(' ', ',', limit = 3).getOrElse(2) { ingredient } + clipboardController.copyToClipboard(actualIngredient) + + }) { + Image( + painter = painterResource(Res.drawable.chef), + contentDescription = null, + modifier = Modifier.padding(12.dp).rotate(-30f), + colorFilter = ColorFilter.tint(if (recipe.bgColor.luminance() > 0.3) Color.Companion.Black else Color.White) + ) + } } } diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/InstructionItem.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/InstructionItem.kt index c5502f1..5a5307b 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/InstructionItem.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/InstructionItem.kt @@ -17,16 +17,22 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.LineHeightStyle import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import com.menagerie.bakers.DisplayManager import com.menagerie.bakers.Size -import com.menagerie.bakers.model.Recipe @Composable fun InstructionItem( - recipe: Recipe, + bgColor: Color, + steps: List, index: Int, slider: Float) { Box(modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp)) { @@ -36,7 +42,18 @@ fun InstructionItem( .padding(top = 8.dp) .border( width = 2.dp, - color = if (recipe.bgColor != MaterialTheme.colorScheme.primaryContainer) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.background, + color = if (bgColor != MaterialTheme.colorScheme.primaryContainer) { + if (index % 2 == 0) { + MaterialTheme.colorScheme.secondaryContainer + } else { + MaterialTheme.colorScheme.onBackground + } + } else + if (index % 2 == 0) { + MaterialTheme.colorScheme.background + } else { + MaterialTheme.colorScheme.onBackground + }, shape = RoundedCornerShape(35.dp) ) ) { @@ -49,7 +66,7 @@ fun InstructionItem( } Text( - text = scaleRecipeServingsInstructions(recipe.instructions[index], slider), + text = boldBracketedText(scaleRecipeServingsInstructions(steps[index], slider), style.fontSize), style = style, modifier = Modifier .fillMaxWidth().fillMaxHeight() @@ -66,7 +83,7 @@ fun InstructionItem( .size(50.dp) .shadow(elevation = 10.dp, shape = CircleShape) .background( - if (recipe.bgColor != MaterialTheme.colorScheme.primaryContainer) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.background, + if (bgColor != MaterialTheme.colorScheme.primaryContainer) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.background, CircleShape ), contentAlignment = Alignment.Center @@ -74,14 +91,14 @@ fun InstructionItem( Text( - text = "${index + 1}", + text = getOffsetIndex(steps, steps[index]), style = MaterialTheme.typography.displayMedium.copy( lineHeightStyle = LineHeightStyle( alignment = LineHeightStyle.Alignment.Center, trim = LineHeightStyle.Trim.None ) ), - color = if (recipe.bgColor != MaterialTheme.colorScheme.primaryContainer) MaterialTheme.colorScheme.onSecondaryContainer else MaterialTheme.colorScheme.onBackground, + color = if (bgColor != MaterialTheme.colorScheme.primaryContainer) MaterialTheme.colorScheme.onSecondaryContainer else MaterialTheme.colorScheme.onBackground, modifier = Modifier.padding(5.dp).rotate(-30f), maxLines = 1, overflow = TextOverflow.Ellipsis @@ -90,3 +107,48 @@ fun InstructionItem( } } } + +fun getOffsetIndex(instructions: List, s: String): String { + + var realIndex = 0 + + for(str in instructions) + { + if(str.startsWith("HEADER-").not()) + realIndex++ + + if(str == s) + break + } + + return realIndex.toString() + +} + +fun boldBracketedText(inputText: String, fontSize: TextUnit): AnnotatedString { + val builder = AnnotatedString.Builder() + var currentIndex = 0 + + while (true) { + val startIndex = inputText.indexOf('[', currentIndex) + if (startIndex == -1) { + builder.append(inputText.substring(currentIndex)) + break + } + + val endIndex = inputText.indexOf(']', startIndex) + if (endIndex == -1) { + builder.append(inputText.substring(currentIndex)) + break + } + + builder.append(inputText.substring(currentIndex, startIndex)) + builder.withStyle(style = SpanStyle(fontWeight = FontWeight.Bold, fontSize = fontSize.times(1.05f) )) { + builder.append(inputText.substring(startIndex, endIndex + 1)) + } + + currentIndex = endIndex + 1 + } + + return builder.toAnnotatedString() +} diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/RecipeDetails.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/RecipeDetails.kt index 42c1b4d..1186d19 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/RecipeDetails.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/RecipeDetails.kt @@ -13,8 +13,11 @@ import com.menagerie.bakers.model.Recipe fun RecipeDetails( recipe: Recipe, multipleRecipes: Boolean, + animate: Boolean, + discreet: Boolean, goForward: () -> Unit, navController: NavHostController, + navTo: String, ) { if ((DisplayManager.size == Size.Large || DisplayManager.size == Size.Medium) && DisplayManager.orientation == Orientation.Landscape) RecipeDetailsLarge( @@ -22,10 +25,16 @@ fun RecipeDetails( multipleRecipes = multipleRecipes, goForward = goForward, navController = navController, + animate = animate, + discreet = discreet, + navTo = navTo ) else RecipeDetailsSmall( recipe = recipe, + animate = animate, + discreet = discreet, navController = navController, + navTo = navTo, ) } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/RecipeDetailsLarge.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/RecipeDetailsLarge.kt index 85db20b..079aaa9 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/RecipeDetailsLarge.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/RecipeDetailsLarge.kt @@ -48,7 +48,10 @@ fun RecipeDetailsLarge( recipe: Recipe, goForward: () -> Unit, multipleRecipes: Boolean, + animate: Boolean, navController: NavHostController, + navTo: String, + discreet: Boolean ) { val nestedScrollConnection = remember { object : NestedScrollConnection { @@ -57,6 +60,7 @@ fun RecipeDetailsLarge( ): Offset { return Offset.Zero } + override suspend fun onPreFling(available: Velocity): Velocity { return super.onPreFling(available) } @@ -67,7 +71,7 @@ fun RecipeDetailsLarge( modifier = Modifier.fillMaxSize() .background(if (recipe.bgColor == MaterialTheme.colorScheme.primaryContainer) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.background) ) { - var reduce by remember { mutableStateOf(false) } + var reduce by remember { mutableStateOf(true) } var slider by remember { mutableFloatStateOf(1f) } Row { @@ -137,7 +141,7 @@ fun RecipeDetailsLarge( } Column(modifier = Modifier.weight(.5f)) { - ingredientsHeader(recipe) + ingredientsHeader(recipe, animate) LazyColumn( contentPadding = PaddingValues(64.dp), userScrollEnabled = true, @@ -145,11 +149,11 @@ fun RecipeDetailsLarge( modifier = Modifier.nestedScroll(nestedScrollConnection), state = ingredientState ) { - ingredients(recipe, slider) + ingredients(recipe, slider, animate) } } Column(modifier = Modifier.weight(1f)) { - stepsHeader(recipe) + stepsHeader(recipe, animate) LazyColumn( contentPadding = PaddingValues(64.dp), userScrollEnabled = true, @@ -157,7 +161,7 @@ fun RecipeDetailsLarge( modifier = Modifier.nestedScroll(nestedScrollConnection), state = stepsState ) { - steps(recipe, slider) + steps(recipe, slider, animate, discreet) } } } @@ -167,15 +171,18 @@ fun RecipeDetailsLarge( } Row { - BackForwardButton({ - navController.navigate(RecipeAppScreen.List.name) { - popUpTo(RecipeAppScreen.List.name){inclusive = true} - } - }) + BackForwardButton( + { + navController.navigate(navTo) { + popUpTo(navTo) { inclusive = true } + } + }, + text = if (navTo == RecipeAppScreen.History.name) "Back to History " else "Back to Recipes " + ) Spacer(modifier = Modifier.weight(1f)) - if(multipleRecipes) - BackForwardButton(goForward, true) + if (multipleRecipes) + BackForwardButton(goForward, true, " Next") } } } diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/RecipeDetailsSmall.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/RecipeDetailsSmall.kt index 330e2b7..40f2916 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/RecipeDetailsSmall.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/RecipeDetailsSmall.kt @@ -49,6 +49,9 @@ import com.menagerie.bakers.view.util.BackForwardButton fun RecipeDetailsSmall( recipe: Recipe, navController: NavHostController, + animate: Boolean, + discreet: Boolean, + navTo: String, ) { val imageRotation = remember { mutableStateOf(0) } @@ -104,7 +107,11 @@ fun RecipeDetailsSmall( ) { Row { if (DisplayManager.device != Device.Android) - BackForwardButton({navController.popBackStack()}) + BackForwardButton({ + navController.navigate(navTo) { + popUpTo(navTo){inclusive = true} + } + }, text = "") Box(modifier = Modifier.weight(1f)) { SelectionContainer { @@ -176,16 +183,16 @@ fun RecipeDetailsSmall( } item { - ingredientsHeader(recipe) + ingredientsHeader(recipe, animate) } - ingredients(recipe, slider) + ingredients(recipe, slider, animate) item { - stepsHeader(recipe) + stepsHeader(recipe, animate) } - steps(recipe, slider) + steps(recipe, slider, animate, discreet) } } } diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/StepsAndDetails.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/StepsAndDetails.kt index 2af3ca3..0a5dc0f 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/StepsAndDetails.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/details/StepsAndDetails.kt @@ -47,7 +47,7 @@ fun recipeHeader(recipe: Recipe, slider: Float) modifier = Modifier.padding(top = 16.dp, start = 16.dp, end = 16.dp) ) - val tags = recipe.tags.keys.toList() + val tags = recipe.tags.keys.toList().sorted() LazyRow (modifier = Modifier.padding(start = 16.dp, top = 16.dp)) { items(tags.size) { item -> @@ -99,10 +99,11 @@ fun DetailsTextStyle() : TextStyle { } @Composable -fun ingredientsHeader(recipe: Recipe) +fun ingredientsHeader(recipe: Recipe, animate: Boolean) { AnimateInEffect( recipe = recipe, + animate = animate, intervalStart = 0 / (recipe.instructions.size + recipe.ingredients.size + 2).toFloat(), content = { Text( @@ -115,10 +116,11 @@ fun ingredientsHeader(recipe: Recipe) } @Composable -fun stepsHeader(recipe: Recipe) +fun stepsHeader(recipe: Recipe, animate: Boolean) { AnimateInEffect( recipe = recipe, + animate = animate, intervalStart = (recipe.ingredients.size + 1) / (recipe.instructions.size + recipe.ingredients.size + 2).toFloat(), content = { Text( @@ -133,14 +135,16 @@ fun stepsHeader(recipe: Recipe) internal fun LazyListScope.ingredients( recipe: Recipe, - slider: Float + slider: Float, + animate: Boolean ){ itemsIndexed(recipe.ingredients) { index, value -> AnimateInEffect( intervalStart = (index + 1) / (recipe.ingredients.size + 1).toFloat(), recipe = recipe, + animate = animate, content = { - if (value.contains("HEADER-")) { + if (value.startsWith("HEADER-")) { Column { HorizontalDivider( thickness = 2.dp, @@ -155,7 +159,7 @@ internal fun LazyListScope.ingredients( } } else { - IngredientItem(recipe, scaleRecipeServings(value, slider)) + IngredientItem(recipe, scaleRecipeServings(value, slider), index) } } ) @@ -164,15 +168,26 @@ internal fun LazyListScope.ingredients( internal fun LazyListScope.steps( recipe: Recipe, - slider: Float + slider: Float, + animate: Boolean, + discreet: Boolean, ) { - itemsIndexed(recipe.instructions) { index, value -> + + val steps = if(discreet) { + splitListByDelimiterIgnoringBrackets(recipe.instructions) + } else { + recipe.instructions + } + + + itemsIndexed(steps) { index, value -> AnimateInEffect( recipe = recipe, - intervalStart = (index + 1) / (recipe.instructions.size + 1).toFloat(), + animate = animate, + intervalStart = (index + 1) / (steps.size + 1).toFloat(), content = { - if (value.contains("HEADER-")) { + if (value.startsWith("HEADER-")) { Column { HorizontalDivider( thickness = 2.dp, @@ -186,7 +201,7 @@ internal fun LazyListScope.steps( ) } }else { - InstructionItem(recipe, index, slider) + InstructionItem(recipe.bgColor, steps, index, slider) } }) } @@ -213,4 +228,37 @@ fun removeTrailingZeros(number: Float): String { number.toInt().toString() else number.toString() +} + +fun splitListByDelimiter(list: List, delimiter: String = "."): List { + return list.flatMap {it.split(delimiter).map { map -> map.trim() }.filter { filter -> filter.isNotEmpty() }.map { map1 -> map1 + delimiter } } +} + +fun splitListByDelimiterIgnoringBrackets( + list: List, + delimiter: String = "." +): List { + return list.flatMap { str -> + val parts = mutableListOf() + var currentPart = StringBuilder() + var bracketLevel = 0 + + for (char in str) { + if (char == '[') { + bracketLevel++ + } else if (char == ']') { + bracketLevel-- + } + + if (char.toString() == delimiter && bracketLevel == 0) { + parts.add(currentPart.toString().trim() + delimiter) + currentPart = StringBuilder() + } else { + currentPart.append(char) + } + } + + parts.add(currentPart.toString().trim()) // Add the last part + parts.filter { it.isNotEmpty() } + } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/ImageWrapper.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/ImageWrapper.kt index 7b0fe0d..1540ce1 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/ImageWrapper.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/ImageWrapper.kt @@ -27,44 +27,61 @@ import androidx.compose.ui.unit.dp fun RecipeListItemImageWrapper( modifier: Modifier, child: @Composable () -> Unit, + animate: Boolean, ) { - val animationDuration = 700 - val scale = remember { Animatable(0.3f) } - val rotation = remember { Animatable(20f) } - val offset = remember { Animatable(0f) } - LaunchedEffect(Unit) { - scale.animateTo( - targetValue = 1f, animationSpec = spring( - dampingRatio = 0.6f, stiffness = 200f + if(animate) { + val animationDuration = 700 + val scale = remember { Animatable(0.3f) } + val rotation = remember { Animatable(20f) } + val offset = remember { Animatable(0f) } + + LaunchedEffect(Unit) { + scale.animateTo( + targetValue = 1f, animationSpec = spring( + dampingRatio = 0.6f, stiffness = 200f + ) ) - ) - } + } - LaunchedEffect(Unit) { - rotation.animateTo(0f, animationSpec = tween(durationMillis = animationDuration)) - } + LaunchedEffect(Unit) { + rotation.animateTo(0f, animationSpec = tween(durationMillis = animationDuration)) + } - LaunchedEffect(Unit) { - offset.animateTo( - 60f, animationSpec = tween( - durationMillis = animationDuration / 2, easing = FastOutSlowInEasing + LaunchedEffect(Unit) { + offset.animateTo( + 60f, animationSpec = tween( + durationMillis = animationDuration / 2, easing = FastOutSlowInEasing + ) ) - ) - offset.animateTo( - targetValue = 0f, animationSpec = spring( - dampingRatio = DampingRatioLowBouncy, stiffness = 200f + offset.animateTo( + targetValue = 0f, animationSpec = spring( + dampingRatio = DampingRatioLowBouncy, stiffness = 200f + ) ) - ) - } + } - Box(modifier = modifier.offset(x = offset.value.dp).graphicsLayer { + Box(modifier = modifier.offset(x = offset.value.dp).graphicsLayer { this.rotationZ = rotation.value }) { - Box( - modifier = Modifier.wrapContentSize().scale(scale.value).rotate(rotation.value).align(Alignment.BottomEnd) - ) { - child() + Box( + modifier = Modifier.wrapContentSize().scale(scale.value).rotate(rotation.value) + .align(Alignment.BottomEnd) + ) { + child() + } + } + } + else { + Box(modifier = modifier.offset(x = 0.dp).graphicsLayer { + this.rotationZ = 0f + }) { + Box( + modifier = Modifier.wrapContentSize().scale(1f).rotate(0f) + .align(Alignment.BottomEnd) + ) { + child() + } } } } diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/RecipeListItem.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/RecipeListItem.kt index 16b1ff3..727bc82 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/RecipeListItem.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/RecipeListItem.kt @@ -34,7 +34,8 @@ import com.menagerie.bakers.model.Recipe fun RecipeListItem( recipe: Recipe, onClick: (recipe: Recipe) -> Unit, - largeList: Boolean + largeList: Boolean, + animate: Boolean, ) { Box(modifier = Modifier) { Box(modifier = Modifier.padding(top = 8.dp, start = 16.dp, end = 16.dp, bottom = 16.dp) @@ -84,7 +85,9 @@ fun RecipeListItem( } } RecipeListItemImageWrapper(modifier = Modifier.align(Alignment.BottomEnd) - .fillMaxWidth(0.45f).aspectRatio(1f), child = { + .fillMaxWidth(0.45f).aspectRatio(1f), + animate = animate, + child = { RecipeImage( imageBitmap = recipe.image, modifier = Modifier.clip( CircleShape diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/RecipeListItemWrapper.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/RecipeListItemWrapper.kt index e06143f..185dc43 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/RecipeListItemWrapper.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/RecipeListItemWrapper.kt @@ -21,51 +21,63 @@ const val rotateX = 9f @Composable fun RecipeListItemWrapper( child: @Composable () -> Unit, - scrollDirection: Boolean + scrollDirection: Boolean, + animate: Boolean ) { - val scaleAnimatable = remember { Animatable(initialValue = 0.75f) } - val rotateXAnimatable = - remember { Animatable(initialValue = if (scrollDirection) rotateX else -rotateX) } + if(animate) { + val scaleAnimatable = remember { Animatable(initialValue = 0.75f) } + val rotateXAnimatable = + remember { Animatable(initialValue = if (scrollDirection) rotateX else -rotateX) } - // Observe changes to scrollDirection and update rotateXAnimatable accordingly - LaunchedEffect(scrollDirection) { - // Animate from 0 to either 60 or -60 - rotateXAnimatable.animateTo( - if (scrollDirection) rotateX else -rotateX, - animationSpec = tween( - durationMillis = 100, - easing = CubicBezierEasing(0f, 0.5f, 0.5f, 1f) + // Observe changes to scrollDirection and update rotateXAnimatable accordingly + LaunchedEffect(scrollDirection) { + // Animate from 0 to either 60 or -60 + rotateXAnimatable.animateTo( + if (scrollDirection) rotateX else -rotateX, + animationSpec = tween( + durationMillis = 100, + easing = CubicBezierEasing(0f, 0.5f, 0.5f, 1f) + ) ) - ) - // Animate from either 60 or -60 to 0 - rotateXAnimatable.animateTo( - targetValue = 0f, - animationSpec = tween( - durationMillis = 500, - easing = CubicBezierEasing(0f, 0.5f, 0.5f, 1f) + // Animate from either 60 or -60 to 0 + rotateXAnimatable.animateTo( + targetValue = 0f, + animationSpec = tween( + durationMillis = 500, + easing = CubicBezierEasing(0f, 0.5f, 0.5f, 1f) + ) ) - ) + } + + LaunchedEffect(Unit) { + scaleAnimatable.animateTo( + 1f, + animationSpec = tween( + durationMillis = 700, + easing = CubicBezierEasing(0f, 0.5f, 0.5f, 1f) + ) + ) + } + + Box( + modifier = Modifier + .fillMaxSize() + .graphicsLayer { + scaleX = scaleAnimatable.value + scaleY = scaleAnimatable.value + rotationX = rotateXAnimatable.value + } + ) { + child() + } + } + else { + Box( + modifier = Modifier + .fillMaxSize() + ) { + child() + } } - LaunchedEffect(Unit) { - scaleAnimatable.animateTo( - 1f, - animationSpec = tween( - durationMillis = 700, - easing = CubicBezierEasing(0f, 0.5f, 0.5f, 1f) - ) - ) - } - - Box( - modifier = Modifier - .fillMaxSize() - .graphicsLayer { - scaleX = scaleAnimatable.value - scaleY = scaleAnimatable.value - rotationX = rotateXAnimatable.value - } - ) { - child() - } } diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/RecipesList.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/RecipesList.kt index e040dd9..c297174 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/RecipesList.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/list/RecipesList.kt @@ -32,6 +32,7 @@ import com.menagerie.bakers.model.Recipe fun RecipesListScreen( items: List, onClick: (recipe: Recipe) -> Unit, + animate: Boolean, ) { Box( modifier = Modifier.fillMaxSize() @@ -54,11 +55,13 @@ fun RecipesListScreen( recipe.bgColor = (if(item % 2 == 0) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.secondaryContainer) RecipeListItemWrapper( scrollDirection = listState.isScrollingUp(), + animate = animate, child = { RecipeListItem( recipe = recipe, + animate = animate, onClick = onClick, - items.size > when(DisplayManager.size) { + largeList = items.size > when(DisplayManager.size) { Size.Small -> 20 diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/util/BackForwardButton.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/util/BackForwardButton.kt index 11a96a7..d332d88 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/util/BackForwardButton.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/util/BackForwardButton.kt @@ -29,6 +29,7 @@ import com.menagerie.bakers.Size fun BackForwardButton( go : () -> Unit, forward : Boolean = false, + text: String, ) { val start = when (DisplayManager.size) { @@ -76,7 +77,7 @@ fun BackForwardButton( if (DisplayManager.orientation == Orientation.Landscape) { Spacer(Modifier.padding(start = 8.dp)) Text( - text = if (forward) " Next " else "Back to Recipes ", + text = text, style = MaterialTheme.typography.headlineSmall, color = Color.White ) @@ -93,4 +94,4 @@ fun BackForwardButton( ) } } -} \ No newline at end of file +} diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/util/GetRecipe.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/util/GetRecipe.kt index 7f09d9d..66f04e7 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/util/GetRecipe.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/util/GetRecipe.kt @@ -6,6 +6,7 @@ import com.menagerie.bakers.model.Recipe import bakersmenagerie.composeapp.generated.resources.Res import bakersmenagerie.composeapp.generated.resources._10_strawberries import com.menagerie.bakers.SortBy +import com.menagerie.bakers.model.TTT import kotlin.time.Duration @@ -14,6 +15,7 @@ fun getFilteredRecipeList( search : String, lockTag : String, sortBy: SortBy, + tttBy: TTT, returnAny: Boolean, reverse: Boolean, showMissing: Boolean = false, @@ -22,6 +24,8 @@ fun getFilteredRecipeList( var recipes: List + + //First filter by tags recipes = if (!returnAny) items.filter { it.tags.keys.containsAll(tags) } else if (tags.isNotEmpty()) @@ -29,6 +33,24 @@ fun getFilteredRecipeList( else items + //trim everything down by the lock tag + if (lockTag != "" && lockTag != "SURPRISE") { + recipes = recipes.filter { it.tags.contains(lockTag) } + } + + //trim out the missing recipes + recipes = + if (showMissing) + recipes.inverseFilter { + isMissing(it) + } + else + recipes.filter { + isMissing(it) + } + + + //then filter by the search bar search recipes = recipes.filter { it.ingredients.any { item -> @@ -50,29 +72,26 @@ fun getFilteredRecipeList( ) } - if (lockTag != "" && lockTag != "SURPRISE") { - recipes = recipes.filter { it.tags.contains(lockTag) } - } + //Organise 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() } } - recipes = - if (showMissing) - recipes.inverseFilter { - isMissing(it) - } - else - recipes.filter { - isMissing(it) - } - if (reverse) recipes = recipes.reversed() + + //Filter by TTT Level + when(tttBy) { + TTT.TRIED -> {} + TTT.TESTED -> {recipes = recipes.filter { it.ttt == TTT.TESTED || it.ttt == TTT.TRUE }} + TTT.TRUE -> {recipes = recipes.filter { it.ttt == TTT.TRUE }} + } + + return recipes } diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/util/MainMenuDropdown.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/util/MainMenuDropdown.kt index edf11ba..e4c4c33 100644 --- a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/util/MainMenuDropdown.kt +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/util/MainMenuDropdown.kt @@ -1,7 +1,10 @@ package com.menagerie.bakers.view.util import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem @@ -19,6 +22,8 @@ import com.menagerie.bakers.Device import com.menagerie.bakers.DisplayManager import com.menagerie.bakers.SortBy import com.menagerie.bakers.Theme +import com.menagerie.bakers.model.TTT +import com.menagerie.bakers.isDebug @Composable fun MainDropDown( @@ -28,11 +33,17 @@ fun MainDropDown( theme: Theme, sortBy: SortBy, helpUs: Boolean, - onHelp: () -> Unit, + animate: Boolean, + discreet: Boolean, + ttt: TTT, + onHelp: (Boolean) -> Unit, + onTTTToggle: () -> Unit, onTag: () -> Unit, onSortBy: () -> Unit, onDesc: () -> Unit, onTheme: () -> Unit, + onAnim: () -> Unit, + onDiscreet: () -> Unit, onRandom: () -> Unit, onBack: () -> Unit, onClose: () -> Unit, @@ -51,32 +62,33 @@ fun MainDropDown( onDismissRequest = { expanded = false } ) { DropdownMenuItem( - text = { Text(theme.name) }, + text = { Text("Current Theme: ".plus(theme.name)) }, onClick = onTheme ) + DropdownMenuItem( + text = { Text("Play Animations? ".plus(animate)) }, + onClick = onAnim + ) + 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 - ) - - DropdownMenuItem( - text = { - Text(text = "Help Us Improve! Show Only Recipes with Missing Info?: ".plus(helpUs.toString())) - }, - onClick = onHelp - ) + if (DisplayManager.device != Device.Web) + nonWebDropdown( + onTag = onTag, + onSortBy = onSortBy, + onDesc = onDesc, + andOr = andOr, + sortBy = sortBy, + descending = descending, + onHelp = onHelp, + helpUs = helpUs, + ttt = ttt, + onTTTToggle = onTTTToggle, + discreet = discreet, + onDiscreet = onDiscreet, + ) HorizontalDivider() @@ -84,11 +96,10 @@ fun MainDropDown( text = { Text("Random Filtered Recipe") }, onClick = onRandom ) - when(DisplayManager.device) { + when (DisplayManager.device) { Device.Android -> {} - Device.Web, Device.Desktop -> - { + Device.Web, Device.Desktop -> { HorizontalDivider() DropdownMenuItem( @@ -105,4 +116,147 @@ fun MainDropDown( } } } +} + +@Composable +fun innerDropDown( + onDismiss: () -> Unit, + onHelp: (Boolean) -> Unit, + helpUs: Boolean, + ttt: TTT, + onTTTToggle: () -> Unit, + expandedDebug: Boolean, + onDiscreet: () -> Unit, + discreet: Boolean, +) { + Column { + DropdownMenu( + expanded = expandedDebug, + onDismissRequest = onDismiss + ) { + + DropdownMenuItem( + text = { + Text( + text = "Show Extra Discreet Recipe Steps?: ".plus(discreet.toString()) + ) + }, + onClick = onDiscreet + ) + + DropdownMenuItem( + text = { + Text( + text = "Help Us Improve! Show Only Recipes with Missing Info?: ".plus( + helpUs.toString() + ) + ) + }, + onClick = {onHelp(helpUs)} + ) + DropdownMenuItem( + text = { + Text(text = "Show ".plus(ttt.name).plus(" recipes or better")) + }, + onClick = onTTTToggle + ) + } + } +} + +@Composable +fun nonWebDropdown( + onTag: () -> Unit, + onSortBy: () -> Unit, + onDesc: () -> Unit, + andOr: Boolean, + sortBy: SortBy, + descending: Boolean, + onHelp: (Boolean) -> Unit, + helpUs: Boolean, + ttt: TTT, + onTTTToggle: () -> Unit, + discreet: Boolean, + onDiscreet: () -> Unit, +) { + + var expandedFilter by remember { mutableStateOf(false) } + + DropdownMenuItem( + text = { + Row { + Text(text = "Filter Options") + Icon(imageVector = Icons.Default.ArrowDropDown, contentDescription = "") + } + }, + onClick = {expandedFilter = true} + ) + + if(expandedFilter) + FilterDropdown( + onTag = onTag, + onSortBy = onSortBy, + onDesc = onDesc, + andOr = andOr, + sortBy = sortBy, + descending = descending, + expanded = expandedFilter, + ) {expandedFilter = false} + + var expandedDebug by remember { mutableStateOf(false) } + + if(isDebug) + DropdownMenuItem( + text = { + Row { + Text(text = "Debug Recipes") + Icon(imageVector = Icons.Default.ArrowDropDown, contentDescription = "") + } + }, + onClick = {expandedDebug = true} + ) + + if(expandedDebug) + innerDropDown( + onDismiss = {expandedDebug = false}, + onHelp = onHelp, + helpUs = helpUs, + ttt = ttt, + onTTTToggle = onTTTToggle, + expandedDebug = expandedDebug, + discreet = discreet, + onDiscreet = onDiscreet, + ) +} + +@Composable +fun FilterDropdown( + onTag: () -> Unit, + onSortBy: () -> Unit, + onDesc: () -> Unit, + andOr: Boolean, + sortBy: SortBy, + descending: Boolean, + expanded: Boolean, + onDismiss: () -> Unit +){ + Column { + DropdownMenu( + onDismissRequest = onDismiss, + expanded = expanded + ) { + 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 + ) + } + } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/util/PartiallyClickableText.kt b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/util/PartiallyClickableText.kt new file mode 100644 index 0000000..5db6b16 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/menagerie/bakers/view/util/PartiallyClickableText.kt @@ -0,0 +1,24 @@ +package com.menagerie.bakers.view.util + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Row +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +fun PartiallyClickableText( + prefix: String? = null, + clickable: String, + onClick: () -> Unit, + suffix: String? = null, +) { + Row { + prefix?.let { Text(text = it.plus(" ")) } + Text( + text = clickable, + modifier = Modifier.clickable(onClick = onClick) + ) + suffix?.let { Text(text = " ".plus(it))} + } +} \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/com/menagerie/bakers/isDebug.desktop.kt b/composeApp/src/desktopMain/kotlin/com/menagerie/bakers/isDebug.desktop.kt new file mode 100644 index 0000000..67e01c7 --- /dev/null +++ b/composeApp/src/desktopMain/kotlin/com/menagerie/bakers/isDebug.desktop.kt @@ -0,0 +1,4 @@ +package com.menagerie.bakers + +actual val isDebug: Boolean + get() = true \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/com/menagerie/bakers/util/rememberClipboardController.desktop.kt b/composeApp/src/desktopMain/kotlin/com/menagerie/bakers/util/rememberClipboardController.desktop.kt new file mode 100644 index 0000000..f6dbf5d --- /dev/null +++ b/composeApp/src/desktopMain/kotlin/com/menagerie/bakers/util/rememberClipboardController.desktop.kt @@ -0,0 +1,19 @@ +package com.menagerie.bakers.util + +import java.awt.Toolkit +import java.awt.datatransfer.StringSelection +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember + +class JvmClipboardController : ClipboardController { + override fun copyToClipboard(text: String) { + val selection = StringSelection(text) + val clipboard = Toolkit.getDefaultToolkit().systemClipboard + clipboard.setContents(selection, selection) + } +} + +@Composable +actual fun rememberClipboardController(): ClipboardController { + return remember { JvmClipboardController() } +} \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/com/menagerie/bakers/view/Settings.desktop.kt b/composeApp/src/desktopMain/kotlin/com/menagerie/bakers/view/Settings.desktop.kt new file mode 100644 index 0000000..995c0bc --- /dev/null +++ b/composeApp/src/desktopMain/kotlin/com/menagerie/bakers/view/Settings.desktop.kt @@ -0,0 +1,153 @@ +package com.menagerie.bakers.view + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.Checkbox +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import com.menagerie.bakers.Theme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.menagerie.bakers.DisplayManager +import com.menagerie.bakers.Orientation +import com.menagerie.bakers.SortBy +import com.menagerie.bakers.model.TTT +import com.menagerie.bakers.view.util.PartiallyClickableText + +@Composable +actual fun SettingsMenu( + theme: Theme, + onTheme: () -> Unit, + animate: Boolean, + onAnim: () -> Unit, + helpUs: Boolean, + onHelpToggle: (Boolean) -> Unit, + ttt: TTT, + onTTTToggle: () -> Unit, + andOr: Boolean, + onAndOr: () -> Unit, + sortBy: SortBy, + onSortToggle: () -> Unit, + descending: Boolean, + onDesc: () -> Unit, + onRandom: () -> Unit, + onBack: () -> Unit, + onClear: () -> Unit, + discreet: Boolean, + onDiscreet: () -> Unit, +) { + Box( + modifier = Modifier.fillMaxSize() + ) { + Row { + Column(modifier = Modifier.weight(1f)) { + Row { + IconButton( + onClick = onBack, + content = { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "Back" + ) + } + ) + } + + Row(modifier = Modifier.padding(16.dp)) { + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { + //Display Settings + Text( + text = "Display Settings", + style = MaterialTheme.typography.headlineSmall + ) + + PartiallyClickableText("Current Theme: ", theme.name, onTheme) + + PartiallyClickableText( + "Play Animations: ", + if (animate) "Yes" else "No", + onAnim + ) + HorizontalDivider() + //END Display + + //Filter Stuff + Text( + text = "Filter Settings", + style = MaterialTheme.typography.headlineSmall + ) + + PartiallyClickableText( + "Filter Style:", + if (andOr) "OR" else "AND", + onAndOr + ) + + PartiallyClickableText( + "Sort By:", + sortBy.name, + onSortToggle, + ) + + PartiallyClickableText( + "Sort Order:", + if (descending) "DESC" else "ASC", + onDesc + ) + //END Filter + HorizontalDivider() + + //Beta Recipes + Text( + text = "Beta Recipe Settings", + style = MaterialTheme.typography.headlineSmall + ) + + PartiallyClickableText("Use extra discreet steps for recipes?", if (discreet) "Yes" else "No", onDiscreet) + + PartiallyClickableText("Show", ttt.name, onTTTToggle, "recipes or better") + + Row { + Text( + text = "Help Us Improve! Show Only Recipes with Missing Info?", + modifier = Modifier.align(Alignment.CenterVertically) + ) + Checkbox( + checked = helpUs, + onCheckedChange = onHelpToggle, + modifier = Modifier.align(Alignment.CenterVertically) + ) + } + //END BETA + + HorizontalDivider() + + //DANGER + Text( + text = "DANGER ZONE", + style = MaterialTheme.typography.headlineSmall + ) + + PartiallyClickableText( + "Clear Settings?", + clickable = "CLEAR ALL SETTINGS", + onClick = onClear + ) + } + } + } + Column(modifier = Modifier.weight(if(DisplayManager.orientation == Orientation.Landscape) 4f else 2f)){ } //empty weight pusher + } + } +} \ No newline at end of file diff --git a/composeApp/src/wasmJsMain/kotlin/com/menagerie/bakers/isDebug.wasmJs.kt b/composeApp/src/wasmJsMain/kotlin/com/menagerie/bakers/isDebug.wasmJs.kt new file mode 100644 index 0000000..3d3cb7e --- /dev/null +++ b/composeApp/src/wasmJsMain/kotlin/com/menagerie/bakers/isDebug.wasmJs.kt @@ -0,0 +1,4 @@ +package com.menagerie.bakers + +actual val isDebug: Boolean + get() = false \ No newline at end of file diff --git a/composeApp/src/wasmJsMain/kotlin/com/menagerie/bakers/util/rememberClipboardController.wasmJs.kt b/composeApp/src/wasmJsMain/kotlin/com/menagerie/bakers/util/rememberClipboardController.wasmJs.kt new file mode 100644 index 0000000..1aa62bb --- /dev/null +++ b/composeApp/src/wasmJsMain/kotlin/com/menagerie/bakers/util/rememberClipboardController.wasmJs.kt @@ -0,0 +1,23 @@ +package com.menagerie.bakers.util + +import androidx.compose.runtime.Composable + +import kotlinx.browser.window +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import androidx.compose.runtime.remember + +class JsClipboardController : ClipboardController { + override fun copyToClipboard(text: String) { + CoroutineScope(Dispatchers.Main).launch { + + window.navigator.clipboard.writeText(text) + } + } +} + +@Composable +actual fun rememberClipboardController(): ClipboardController { + return remember { JsClipboardController() } +} \ No newline at end of file diff --git a/composeApp/src/wasmJsMain/kotlin/com/menagerie/bakers/view/Settings.wasmJs.kt b/composeApp/src/wasmJsMain/kotlin/com/menagerie/bakers/view/Settings.wasmJs.kt new file mode 100644 index 0000000..717c532 --- /dev/null +++ b/composeApp/src/wasmJsMain/kotlin/com/menagerie/bakers/view/Settings.wasmJs.kt @@ -0,0 +1,30 @@ +package com.menagerie.bakers.view + +import androidx.compose.runtime.Composable +import com.menagerie.bakers.SortBy +import com.menagerie.bakers.Theme +import com.menagerie.bakers.model.TTT + +@Composable +actual fun SettingsMenu( + theme: Theme, + onTheme: () -> Unit, + animate: Boolean, + onAnim: () -> Unit, + helpUs: Boolean, + onHelpToggle: (Boolean) -> Unit, + ttt: TTT, + onTTTToggle: () -> Unit, + andOr: Boolean, + onAndOr: () -> Unit, + sortBy: SortBy, + onSortToggle: () -> Unit, + descending: Boolean, + onDesc: () -> Unit, + onRandom: () -> Unit, + onBack: () -> Unit, + onClear: () -> Unit, + discreet: Boolean, + onDiscreet: () -> Unit, +) { +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e2d3c20..00bc1e3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,39 +1,26 @@ [versions] -agp = "8.9.0" -android-compileSdk = "34" +agp = "8.9.1" +android-compileSdk = "35" android-minSdk = "24" android-targetSdk = "34" androidx-activityCompose = "1.10.1" -androidx-appcompat = "1.7.0" -androidx-constraintlayout = "2.2.1" -androidx-core-ktx = "1.15.0" -androidx-espresso-core = "3.6.1" androidx-lifecycle = "2.8.4" -androidx-material = "1.12.0" -androidx-test-junit = "1.2.1" compose-multiplatform = "1.7.0" -junit = "4.13.2" kotlin = "2.1.0" kotlinx-coroutines = "1.10.1" material3 = "1.7.0" +multiplatformSettings = "1.3.0" navigationCompose = "2.7.0-alpha07" [libraries] -kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } -kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } -junit = { group = "junit", name = "junit", version.ref = "junit" } -androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-ktx" } -androidx-test-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-junit" } -androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "androidx-espresso-core" } -androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } -androidx-material = { group = "com.google.android.material", name = "material", version.ref = "androidx-material" } -androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout" } androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" } androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" } androidx-lifecycle-runtime-compose = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidx-lifecycle" } kotlinx-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" } androidx-navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "navigationCompose" } material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "material3" } +multiplatform-settings = { module = "com.russhwolf:multiplatform-settings", version.ref = "multiplatformSettings" } +multiplatform-settings-no-arg = { module = "com.russhwolf:multiplatform-settings-no-arg", version.ref = "multiplatformSettings" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" }