Added a toggle to keep the screen active and a recipe deletion button

master
Wynd 2025-08-31 01:11:04 +03:00
parent a33e3be0cc
commit e996254451
8 changed files with 168 additions and 6 deletions

View File

@ -1,6 +1,7 @@
package xyz.pixelatedw.recipe package xyz.pixelatedw.recipe
import android.os.Bundle import android.os.Bundle
import android.view.WindowManager
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
@ -19,7 +20,7 @@ import xyz.pixelatedw.recipe.utils.getRecipes
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
private val recipeView: RecipesView by viewModels() private val recipeView: RecipesView by viewModels()
private lateinit var db: AppDatabase lateinit var db: AppDatabase
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)

View File

@ -5,6 +5,7 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Entity import androidx.room.Entity
import androidx.room.Insert import androidx.room.Insert
import androidx.room.OnConflictStrategy import androidx.room.OnConflictStrategy
@ -37,4 +38,7 @@ data class Recipe(
interface RecipeDao { interface RecipeDao {
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(recipe: Recipe) fun insert(recipe: Recipe)
@Delete
fun delete(recipe: Recipe)
} }

View File

@ -2,6 +2,7 @@ package xyz.pixelatedw.recipe.data
import android.os.Parcelable import android.os.Parcelable
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Embedded import androidx.room.Embedded
import androidx.room.Entity import androidx.room.Entity
import androidx.room.Insert import androidx.room.Insert
@ -42,4 +43,7 @@ interface RecipeWithTagsDao {
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(recipe: RecipeTag) fun insert(recipe: RecipeTag)
@Query("DELETE FROM recipe WHERE recipe.title = :recipe")
fun delete(recipe: String)
} }

View File

@ -15,10 +15,21 @@ class RecipesView : ViewModel() {
private val _search = MutableStateFlow<String?>(null) private val _search = MutableStateFlow<String?>(null)
val search = _search.asStateFlow() val search = _search.asStateFlow()
private val _keepScreenOn = MutableStateFlow<Boolean>(false)
val keepScreenOn = _keepScreenOn.asStateFlow()
fun setKeepScreenOn(flag: Boolean) {
_keepScreenOn.update { flag }
}
fun setRecipes(recipes: List<RecipeWithTags>) { fun setRecipes(recipes: List<RecipeWithTags>) {
_recipes.update { recipes } _recipes.update { recipes }
} }
fun removeRecipe(recipe: RecipeWithTags) {
_recipes.value = _recipes.value.toMutableList().apply { remove(recipe) }.toList()
}
fun setSearch(search: String) { fun setSearch(search: String) {
_search.update { search } _search.update { search }
} }

View File

@ -8,7 +8,8 @@ import androidx.room.PrimaryKey
@Entity @Entity
data class Tag( data class Tag(
@PrimaryKey val name: String @PrimaryKey
val name: String
) )
@Dao @Dao

View File

@ -84,7 +84,7 @@ fun MainScreen(ctx: MainActivity, padding: PaddingValues, view: RecipesView) {
} }
} }
composable("info") { composable("info") {
RecipeInfo(padding, active.value!!) RecipeInfo(ctx, view, navController, padding, active.value!!)
} }
} }
} }

View File

@ -0,0 +1,53 @@
package xyz.pixelatedw.recipe.ui.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
@Composable
fun RecipeDeletionDialog(onAccept: ( ) -> Unit, onDismiss: () -> Unit) {
Dialog(onDismissRequest = { onDismiss() }) {
Card(
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
.padding(16.dp),
shape = RoundedCornerShape(16.dp),
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.height(100.dp).wrapContentSize(Alignment.Center)
) {
Text(
text = "Do you really wish to permanently delete this recipe ?",
textAlign = TextAlign.Center,
)
}
Row(modifier = Modifier.fillMaxWidth().padding(end = 16.dp), horizontalArrangement = Arrangement.End) {
TextButton(onClick = onDismiss) {
Text("Dismiss")
}
TextButton(onClick = onAccept) {
Text("Confirm")
}
}
}
}
}

View File

@ -1,26 +1,48 @@
package xyz.pixelatedw.recipe.ui.components package xyz.pixelatedw.recipe.ui.components
import android.view.WindowManager
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Switch
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import xyz.pixelatedw.recipe.data.Recipe import androidx.navigation.NavHostController
import xyz.pixelatedw.recipe.MainActivity
import xyz.pixelatedw.recipe.data.RecipeWithTags import xyz.pixelatedw.recipe.data.RecipeWithTags
import xyz.pixelatedw.recipe.data.RecipesView
import xyz.pixelatedw.recipe.utils.parseMarkdown import xyz.pixelatedw.recipe.utils.parseMarkdown
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun RecipeInfo(padding: PaddingValues, active: RecipeWithTags) { fun RecipeInfo(
ctx: MainActivity,
view: RecipesView,
nav: NavHostController,
padding: PaddingValues,
active: RecipeWithTags
) {
val keepScreen = view.keepScreenOn.collectAsState()
val openDeletionDialog = remember { mutableStateOf(false) }
Column( Column(
modifier = Modifier modifier = Modifier
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
@ -28,7 +50,9 @@ fun RecipeInfo(padding: PaddingValues, active: RecipeWithTags) {
) { ) {
Row( Row(
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth() modifier = Modifier
.fillMaxWidth()
.padding(top = 24.dp, bottom = 24.dp)
) { ) {
Text( Text(
text = active.recipe.title, text = active.recipe.title,
@ -37,6 +61,55 @@ fun RecipeInfo(padding: PaddingValues, active: RecipeWithTags) {
) )
} }
Row(modifier = Modifier.fillMaxWidth()) {
Box(
modifier = Modifier
.fillMaxHeight()
.padding(start = 16.dp)
) {
Text(
text = "Keep Screen On",
style = MaterialTheme.typography.bodySmall,
)
Switch(
modifier = Modifier.padding(start = 16.dp, top = 16.dp),
checked = keepScreen.value,
onCheckedChange = {
view.setKeepScreenOn(it)
if (it) {
ctx.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else {
ctx.window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
)
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(end = 16.dp),
horizontalArrangement = Arrangement.End
) {
Box(
modifier = Modifier
.fillMaxHeight()
.padding(start = 16.dp)
) {
Button(
onClick = {
openDeletionDialog.value = true
},
colors = ButtonDefaults.buttonColors(containerColor = Color.Red)
) {
Text(
text = "Delete",
style = MaterialTheme.typography.bodyMedium
)
}
}
}
}
Box( Box(
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
@ -48,4 +121,19 @@ fun RecipeInfo(padding: PaddingValues, active: RecipeWithTags) {
) )
} }
} }
when {
openDeletionDialog.value -> {
RecipeDeletionDialog(
onAccept = {
view.removeRecipe(active)
ctx.db.recipeDao().delete(active.recipe)
ctx.db.recipeWithTagsDao().delete(active.recipe.title)
openDeletionDialog.value = false
nav.popBackStack()
},
onDismiss = { openDeletionDialog.value = false }
)
}
}
} }