kotlin Jetpack编写第一次尝试-正确的用法,我能做得更好吗?

siv3szwd  于 2023-03-30  发布在  Kotlin
关注(0)|答案(1)|浏览(174)

我构建了一个非常小的实践应用程序,但我发现了一些问题。

package com.example.jetrecept

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.sharp.Add
import androidx.compose.material.icons.sharp.Delete
import androidx.compose.material.icons.sharp.Edit
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import com.example.jetrecept.ui.theme.JetReceptTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            JetReceptTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    MainContent()
                }
            }
        }
    }
}

@Preview(showBackground = true)
@Composable
fun MainContent() {
    var recipeTitle by remember { mutableStateOf("") }
    val ingredientList = remember { mutableStateListOf<Ingredient>() }

    var amount by remember { mutableStateOf("") } // Change to Double
    var unit by remember { mutableStateOf("") }
    var notation by remember { mutableStateOf("") }

    RecipeContent(
        recipeTitle = recipeTitle,
        onRecipeTitleChange = { recipeTitle = it },
        ingredientList = ingredientList,
        onIngredientListUpdate = { ingredient: Ingredient, i: Int -> ingredientList[i] = ingredient},
        onIngredientListAdd = { ingredientList.add(it) },
        onIngredientListRemoveItem = { ingredientList.removeAt(it)},

        amount = amount,
        onAmountChange = { amount = it},
        unit = unit,
        onUnitChange = { unit = it},
        notation = notation,
        onNotationChange = { notation = it}
        )
    RecipeHeader(
        recipeTitle = recipeTitle
    )
}

@Composable
fun RecipeHeader(
    recipeTitle: String
) {
    //JetReciptTheme {
    Column {
        //Text(text="recipetitle: $recipeTitle") // Just for testing, if hoisting works
    }
    //}
}

@Composable
fun RecipeContent(
    recipeTitle: String,
    onRecipeTitleChange: (String) -> Unit,
    ingredientList: MutableList<Ingredient>,
    onIngredientListAdd: (Ingredient) -> Unit,
    onIngredientListUpdate: (Ingredient, Int) -> Unit,
    onIngredientListRemoveItem: (Int) -> Unit,

    amount: String, // change to Double,
    onAmountChange: (String) -> Unit, //change to (Double) -> Unit,
    unit: String,
    onUnitChange: (String) -> Unit,
    notation: String,
    onNotationChange: (String) -> Unit
) {
    Column(modifier = Modifier
        .fillMaxSize()
        .padding(21.dp)) {
        // Headline
        Text(text="Add new recipe",
            modifier = Modifier
                .fillMaxWidth()
                .padding(34.dp),
            textAlign = TextAlign.Center)

        // Title of recipe - input
        SectionHeadline(title = "Recipename")
        TextField(
            value = recipeTitle,
            onValueChange = { onRecipeTitleChange(it) },
            modifier = Modifier
                .fillMaxWidth()
                .padding(bottom = 34.dp),
            // Keyboard Action fehlt noch 
            )

        // Ingredient - section
        SectionHeadline(title = "Ingredients")

        // Writing headline over the Ingredient table
        if (ingredientList.isNotEmpty()) {
            IngredientDescription(
                modifier = Modifier.padding(bottom=4.dp),
                firstColumn = "Nr.",
                secondColumn = "Amount",
                thirdColumn = "Unit",
                fourthColumn = "Notation"
                )
            Divider(modifier = Modifier
                .height(10.dp)
                .padding(bottom = 4.dp, top = 4.dp))
        }

        // Print all Ingredients to an Row
        ingredientList.mapIndexed { index, ingredient -> IngredientRow(
            id = index,
            ingredient = ingredient,
            onIngredientListUpdate = onIngredientListUpdate,
            onIngredientListRemoveItem = onIngredientListRemoveItem,

            amount = amount,
            onAmountChange = onAmountChange,
            unit = unit,
            onUnitChange = onUnitChange,
            notation = notation,
            onNotationChange = onNotationChange
        )
        }

        // Ingredient input row
        Row {
            TextField(
                value = amount,
                onValueChange = { onAmountChange(it)},
                modifier = Modifier
                    .width(100.dp)
                    .padding(end = 8.dp),
                label = { Text(text="amount") },
                singleLine = true
                )
            TextField(
                value = unit,
                onValueChange = { onUnitChange(it)},
                modifier = Modifier
                    .width(80.dp)
                    .padding(end = 8.dp),
                label = { Text(text = "unit") },
                singleLine = true
                )
            TextField(
                value = notation,
                onValueChange = { onNotationChange(it)},
                modifier = Modifier.weight(1F),
                label = { Text(text = "notation")},
                singleLine = true
                )
        }

        Spacer(modifier= Modifier.height(8.dp))

        // Add - Button, adding Ingredients
        IconButton(
            buttonText = "add",
            icon = Icons.Sharp.Add,
            iconDescription = "add icon",
            enabled = amount.isNotBlank() && unit.isNotBlank() && notation.isNotBlank(),
            onClick = {
                onIngredientListAdd(Ingredient(amount=amount, unit=unit, notation=notation))
                onAmountChange(""); onUnitChange(""); onNotationChange("")
            })
    }
}

@Composable
fun IngredientRow(
    id: Int = 1,
    ingredient: Ingredient,
    onIngredientListUpdate: (Ingredient, Int) -> Unit,
    onIngredientListRemoveItem: (Int) -> Unit,

    amount: String,
    onAmountChange: (String) -> Unit,
    unit: String,
    onUnitChange: (String) -> Unit,
    notation: String,
    onNotationChange: (String) -> Unit
    ) {
    var buttonVisibility by remember { mutableStateOf(false)}
    var showEditDialog by remember { mutableStateOf(false)}

    Column( modifier = Modifier.fillMaxWidth()) {
        IngredientDescription(
            modifier = Modifier.clickable { buttonVisibility = !buttonVisibility },
            firstColumn = "$id",
            secondColumn = ingredient.amount,
            thirdColumn = ingredient.unit,
            fourthColumn = ingredient.notation
        )

        if (buttonVisibility) {
            Row(modifier = Modifier
                .padding(bottom = 8.dp, top = 8.dp)
                .fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceEvenly
                ) {
                IconButton(
                    buttonText = "edit",
                    icon = Icons.Sharp.Edit,
                    iconDescription = "edit icon",
                    onClick = {
                        onAmountChange( ingredient.amount)
                        onUnitChange( ingredient.unit)
                        onNotationChange( ingredient.notation)
                        showEditDialog = true}
                )
                IconButton(
                    buttonText = "delete",
                    icon = Icons.Sharp.Delete,
                    iconDescription = "delete icon",
                    onClick = { onIngredientListRemoveItem(id) }
                )
            }
        }
        Divider(modifier = Modifier
            .height(10.dp)
            .padding(bottom = 4.dp, top = 4.dp))

        if (showEditDialog) {
            AlertDialog(
                onDismissRequest = {
                    onAmountChange(""); onUnitChange(""); onNotationChange("")
                    showEditDialog = false},
                title = {Text(text="Edit ingredient")},
                text = {
                    Column {
                        Text(text="Amount:")
                        TextField(value = amount, onValueChange = { onAmountChange(it) })
                        Text(text="Unit:")
                        TextField(value = unit, onValueChange = { onUnitChange(it) })
                        Text(text="Notation:")
                        TextField(value = notation, onValueChange = { onNotationChange(it) })
                    }
                },
                confirmButton = { onIngredientListUpdate(
                Ingredient(amount= amount, unit= unit, notation= notation), id)
                    Button(onClick = {
                        showEditDialog = false
                        buttonVisibility = false
                        onAmountChange(""); onUnitChange(""); onNotationChange("")}) {
                        Text(text = "apply")
                    }
                                },
                dismissButton = {
                    Button(onClick = {
                        showEditDialog = false
                        buttonVisibility = false
                        onAmountChange(""); onUnitChange(""); onNotationChange("")}) {
                        Text(text = "discard")
                    }
                }
            )
        }
    }
}

@Composable
fun SectionHeadline(title: String) {
    Text(text = title)
    Divider(modifier = Modifier.height(2.dp))
    Spacer(modifier = Modifier.height(8.dp))
}

@Composable
fun IngredientDescription(
    modifier: Modifier = Modifier,
    firstColumn: String, secondColumn: String, thirdColumn: String, fourthColumn:String) {
    Row( modifier = modifier
        .fillMaxWidth()
        .padding(bottom = 4.dp, top = 4.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        Text(text = firstColumn, modifier = Modifier.width(30.dp), textAlign = TextAlign.Center)
        Text(text = secondColumn, modifier = Modifier.width(60.dp), textAlign = TextAlign.Center)
        Text(text = thirdColumn, modifier = Modifier.width(50.dp), textAlign = TextAlign.Center)
        Text(text = fourthColumn, modifier = Modifier.weight(1F))
    }
}

@Composable
fun IconButton(
    buttonText: String,
    icon: ImageVector,
    enabled: Boolean = true,
    iconDescription: String,
    onClick: () -> Unit
) {
    Button(onClick = onClick, enabled = enabled) {
        Text(text=buttonText, modifier = Modifier.padding(end=5.dp))
        Icon(imageVector = icon, contentDescription = iconDescription)
    }
}

// data class Ingredient (var amount: Double, var unit: String, var notation: String)
data class Ingredient (var amount: String, var unit: String, var notation: String)

提升的方式是否正确?我的意思是,我将大部分状态从Composable中取出,但其中的一些状态只是用于内部工作。我是否也应该将其从Composable中取出,使其完全无状态(buttonVisibilityshowEditDialog)?
有什么我可以做得更好的吗?

9ceoxa92

9ceoxa921#

第一件事首先是需要关注点分离到您的代码。因此,在未来,如果需要修改,您可以轻松地修改它,而无需弄清楚每个组合函数是如何设计的,如何管理状态以及在哪里。为此,您可以遵循任何设计架构(优选的是经由模型-数据存储、视图-UI元素、视图模型-状态管理和逻辑工作-MVVM体系结构的单向数据流)
我知道你的应用程序是如此之小,但干净的设计在未来的帮助。

相关问题