Compare commits
2 Commits
821c81cac2
...
7e04c31ae3
| Author | SHA1 | Date |
|---|---|---|
|
|
7e04c31ae3 | |
|
|
b3e8958c5f |
|
|
@ -10,6 +10,7 @@ import androidx.room.Entity
|
||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
import androidx.room.OnConflictStrategy
|
import androidx.room.OnConflictStrategy
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
|
import androidx.room.Query
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
|
|
@ -18,7 +19,8 @@ data class Recipe(
|
||||||
val title: String,
|
val title: String,
|
||||||
val preview: String?,
|
val preview: String?,
|
||||||
val lastModified: Long,
|
val lastModified: Long,
|
||||||
val content: String
|
val content: String,
|
||||||
|
val hash: Int
|
||||||
) {
|
) {
|
||||||
fun previewImage(ctx: Context): Bitmap? {
|
fun previewImage(ctx: Context): Bitmap? {
|
||||||
if (this.preview != null) {
|
if (this.preview != null) {
|
||||||
|
|
@ -41,4 +43,7 @@ interface RecipeDao {
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
fun delete(recipe: Recipe)
|
fun delete(recipe: Recipe)
|
||||||
|
|
||||||
|
@Query("SELECT EXISTS(SELECT hash FROM recipe WHERE recipe.hash = :hash LIMIT 1)")
|
||||||
|
fun hasHash(hash: Int): Boolean
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,13 +36,18 @@ class RecipesView : ViewModel() {
|
||||||
fun setRecipes(recipes: List<RecipeWithTags>) {
|
fun setRecipes(recipes: List<RecipeWithTags>) {
|
||||||
_recipes.update { recipes.sortedBy { it.recipe.title } }
|
_recipes.update { recipes.sortedBy { it.recipe.title } }
|
||||||
|
|
||||||
val filters = arrayListOf<TagFilter>()
|
val filtersMap = mutableMapOf<String, Int>()
|
||||||
|
|
||||||
_recipes.value.stream()
|
_recipes.value.stream()
|
||||||
.filter { it.tags.isNotEmpty() }
|
.filter { it.tags.isNotEmpty() }
|
||||||
.forEach {
|
.forEach {
|
||||||
it.tags.forEach {tag -> filters.add(TagFilter(tag.name))}
|
it.tags.forEach { tag ->
|
||||||
|
val count = filtersMap[tag.name] ?: 0
|
||||||
|
filtersMap[tag.name] = count + 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val filters = filtersMap.map { it -> TagFilter(it.key, count = it.value) }.toList()
|
||||||
|
|
||||||
_tagFilters.update { filters.distinct() }
|
_tagFilters.update { filters.distinct() }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package xyz.pixelatedw.recipe.data
|
package xyz.pixelatedw.recipe.data
|
||||||
|
|
||||||
data class TagFilter(val tag: String, var checked: Boolean = false) {
|
data class TagFilter(val tag: String, var checked: Boolean = false, var count: Int = 0) {
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,11 @@ fun RecipePreview(entry: RecipeWithTags, previewUri: Bitmap?, onClick: () -> Uni
|
||||||
bitmap = previewUri.asImageBitmap(),
|
bitmap = previewUri.asImageBitmap(),
|
||||||
contentDescription = "Recipe image",
|
contentDescription = "Recipe image",
|
||||||
contentScale = ContentScale.Crop,
|
contentScale = ContentScale.Crop,
|
||||||
modifier = Modifier.size(256.dp).padding(top = 16.dp, bottom = 16.dp),
|
modifier = Modifier.size(256.dp).padding(top = 16.dp, bottom = 8.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) {
|
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp)) {
|
||||||
Text(
|
Text(
|
||||||
text = entry.recipe.title,
|
text = entry.recipe.title,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,15 @@
|
||||||
package xyz.pixelatedw.recipe.ui.components
|
package xyz.pixelatedw.recipe.ui.components
|
||||||
|
|
||||||
import androidx.collection.arraySetOf
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.wrapContentSize
|
import androidx.compose.foundation.layout.wrapContentSize
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.grid.GridCells
|
|
||||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
|
||||||
import androidx.compose.foundation.lazy.grid.items
|
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.Checkbox
|
import androidx.compose.material3.Checkbox
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
|
@ -25,20 +18,17 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
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.TextUnit
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.em
|
import androidx.compose.ui.unit.em
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
import xyz.pixelatedw.recipe.data.RecipesView
|
import xyz.pixelatedw.recipe.data.RecipesView
|
||||||
import xyz.pixelatedw.recipe.data.TagFilter
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TagFilterDialog(onAccept: ( ) -> Unit, view: RecipesView) {
|
fun TagFilterDialog(onAccept: () -> Unit, view: RecipesView) {
|
||||||
val filters = view.tagFilters.collectAsState()
|
val filters = view.tagFilters.collectAsState()
|
||||||
|
|
||||||
Dialog(onDismissRequest = { }) {
|
Dialog(onDismissRequest = { }) {
|
||||||
|
|
@ -54,24 +44,45 @@ fun TagFilterDialog(onAccept: ( ) -> Unit, view: RecipesView) {
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxHeight(0.9f)
|
.fillMaxHeight(0.9f)
|
||||||
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
|
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
|
||||||
.wrapContentSize(Alignment.TopStart)) {
|
.wrapContentSize(Alignment.TopStart)
|
||||||
|
) {
|
||||||
items(filters.value) { tag ->
|
items(filters.value) { tag ->
|
||||||
// TODO This doesn't really feel right lmao, but for now it works
|
// TODO This doesn't really feel right lmao, but for now it works
|
||||||
val filterChecked = remember { mutableStateOf(tag.checked) }
|
val filterChecked = remember { mutableStateOf(tag.checked) }
|
||||||
|
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
Checkbox(checked = filterChecked.value, onCheckedChange = {
|
Checkbox(checked = filterChecked.value, onCheckedChange = {
|
||||||
filterChecked.value = !tag.checked
|
filterChecked.value = !tag.checked
|
||||||
view.setTagFilterState(tag.tag, !tag.checked)
|
view.setTagFilterState(tag.tag, !tag.checked)
|
||||||
})
|
})
|
||||||
Text(tag.tag)
|
TextButton(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
contentColor = Color.White,
|
||||||
|
containerColor = Color.Transparent
|
||||||
|
),
|
||||||
|
onClick = {
|
||||||
|
filterChecked.value = !tag.checked
|
||||||
|
view.setTagFilterState(tag.tag, !tag.checked)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
text = tag.tag + " (" + tag.count + ")",
|
||||||
|
textAlign = TextAlign.Left
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row(modifier = Modifier
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(end = 16.dp), horizontalArrangement = Arrangement.End) {
|
.padding(end = 16.dp), horizontalArrangement = Arrangement.End
|
||||||
|
) {
|
||||||
TextButton(onClick = onAccept) {
|
TextButton(onClick = onAccept) {
|
||||||
Text("Done")
|
Text("Done")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,12 @@ private fun parseRecipe(ctx: Context, db: AppDatabase, file: DocumentFile) {
|
||||||
val inputStream = ctx.contentResolver.openInputStream(file.uri)
|
val inputStream = ctx.contentResolver.openInputStream(file.uri)
|
||||||
val reader = BufferedReader(InputStreamReader(inputStream))
|
val reader = BufferedReader(InputStreamReader(inputStream))
|
||||||
val text = reader.readText()
|
val text = reader.readText()
|
||||||
|
|
||||||
|
val hash = text.hashCode() // Probably not the best way but its stable and works
|
||||||
|
if (db.recipeDao().hasHash(hash)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val lines = text.lines()
|
val lines = text.lines()
|
||||||
|
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
|
|
@ -133,12 +139,11 @@ private fun parseRecipe(ctx: Context, db: AppDatabase, file: DocumentFile) {
|
||||||
title = recipeTitle,
|
title = recipeTitle,
|
||||||
preview = recipePreview,
|
preview = recipePreview,
|
||||||
lastModified = lastModified,
|
lastModified = lastModified,
|
||||||
content = content
|
content = content,
|
||||||
|
hash = hash
|
||||||
)
|
)
|
||||||
|
|
||||||
db.recipeDao().insert(recipe)
|
db.recipeDao().insert(recipe)
|
||||||
|
|
||||||
println(recipe)
|
|
||||||
|
|
||||||
reader.close()
|
reader.close()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue