Код: Выделить всё
package com.example.littlelemonandroid
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTapGestures
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.absoluteOffset
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.scale
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import androidx.room.Room
import com.example.littlelemonandroid.ui.theme.Black
import com.example.littlelemonandroid.ui.theme.DarkGray
import com.example.littlelemonandroid.ui.theme.Green
import com.example.littlelemonandroid.ui.theme.LittleLemonAndroidTheme
import com.example.littlelemonandroid.ui.theme.White
import com.example.littlelemonandroid.ui.theme.Yellow
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.engine.android.Android
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.get
import io.ktor.serialization.kotlinx.json.json
//@Preview(showBackground = true)
@Composable
fun Home(navController: NavHostController) {
val searchPhrase = remember {
mutableStateOf("")
}
val focusManager: FocusManager = LocalFocusManager.current
var isAnyTextFieldFocused by remember { mutableStateOf(false) }
var isFocused by remember { mutableStateOf(false) }
val focusRequester = remember { FocusRequester() }
val context = LocalContext.current
val database by lazy {
Room.databaseBuilder(context, AppDatabase::class.java, "database").build()
}
LittleLemonAndroidTheme {
Column(
modifier = Modifier
.fillMaxSize()
.background(White)
.pointerInput(Unit) {
detectTapGestures {
if (isAnyTextFieldFocused) {
focusManager.clearFocus()
}
}
}
) {
Row(
horizontalArrangement = Arrangement.SpaceAround,
modifier = Modifier
.fillMaxWidth()
.padding(start = 110.dp)
) {
Box(
modifier = Modifier
.size(100.dp)
.wrapContentSize(unbounded = true)
) {
Image(
painter = painterResource(id = R.drawable.logo),
contentDescription = "Little Lemon Logo",
modifier = Modifier
.size(150.dp)
)
}
Box(
modifier = Modifier
.size(100.dp)
.wrapContentSize(unbounded = true)
.clip(CircleShape)
.padding(start = 30.dp)
.clickable {
navController.navigate(Profile.route)
}
) {
Image(
painter = painterResource(id = R.drawable.profile),
contentDescription = "Little Lemon Logo",
modifier = Modifier
.size(60.dp)
.clip(CircleShape)
.scale(2.0f)
.absoluteOffset(y = 7.dp)
)
}
}
Column(
modifier = Modifier
.background(Green)
.fillMaxWidth()
.padding(start = 15.dp, end = 15.dp, bottom = 20.dp)
) {
Text(
text = stringResource(id = R.string.app_title),
style = MaterialTheme.typography.titleMedium,
color = Yellow,
modifier = Modifier
.fillMaxWidth()
.size(50.dp)
)
Text(
text = stringResource(id = R.string.app_city),
style = MaterialTheme.typography.titleSmall,
color = White,
)
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.app_description),
color = White,
style = MaterialTheme.typography.bodyMedium,
fontSize = 15.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Left,
modifier = Modifier
.weight(0.7f)
.padding(top = 20.dp)
)
Image(
painter = painterResource(id = R.drawable.hero_image),
contentDescription = "Hero Image",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(height = 130.dp, width = 150.dp)
.weight(0.5f)
.clip(RoundedCornerShape(10.dp))
)
}
TextField(
value = searchPhrase.value,
onValueChange = {searchPhrase.value = it},
placeholder = {
Text(
text = "Enter search phrase",
style = MaterialTheme.typography.labelMedium,
color = DarkGray,
fontSize = 18.sp,
)
},
leadingIcon = {
Icon(
imageVector = Icons.Outlined.Search,
contentDescription = "Search Icon",
tint = Black
)
},
colors = TextFieldDefaults.colors(
unfocusedContainerColor = White,
focusedContainerColor = White
),
textStyle = MaterialTheme.typography.labelMedium,
singleLine = true,
modifier = Modifier
.fillMaxWidth()
.padding(
top = 15.dp,
)
.size(50.dp)
.clip(RoundedCornerShape(6.dp))
.focusRequester(focusRequester)
.onFocusChanged { focusState ->
isFocused = focusState.isFocused
isAnyTextFieldFocused = isFocused
}
)
}
}
}
}
suspend fun fetchMenu() : List {
val httpClient = HttpClient(Android) {
install(ContentNegotiation) {
json()
}
}
val dataURL = "https://raw.githubusercontent.com/Meta-Mobile-Developer-PC/Working-With-Data-API/main/menu.json"
val menuNetwork : MenuNetwork = httpClient.get(dataURL).body()
return menuNetwork.menu
}
Код: Выделить всё
package com.example.littlelemonandroid
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.Scaffold
import androidx.compose.ui.Modifier
import androidx.core.view.WindowCompat
import androidx.navigation.compose.rememberNavController
import com.example.littlelemonandroid.ui.theme.LittleLemonAndroidTheme
import com.example.littlelemonandroid.ui.theme.White
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
enableEdgeToEdge()
setContent {
LittleLemonAndroidTheme {
Scaffold(
modifier = Modifier
.fillMaxSize()
.windowInsetsPadding(WindowInsets.statusBars)
.background(White)
) { innerPadding ->
Box() {
val navController = rememberNavController()
Navigation(navController = navController)
}
}
}
}
}
}
Код: Выделить всё
package com.example.littlelemonandroid
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class MenuNetwork(
@SerialName("menu")
val menu: List
)
@Serializable
data class MenuItemNetwork(
@SerialName("id")
val id: Int,
@SerialName("title")
val title: String,
@SerialName("description")
val description: String,
@SerialName("price")
val price: Double,
@SerialName("image")
val image: String,
@SerialName("category")
val category: String,
) {
fun toMenuItemRoom() = MenuItemRoom(id, title, description, price, image, category)
}
Код: Выделить всё
package com.example.littlelemonandroid
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Database
import androidx.room.Entity
import androidx.room.Insert
import androidx.room.PrimaryKey
import androidx.room.Query
import androidx.room.RoomDatabase
@Entity
data class MenuItemRoom (
@PrimaryKey val id: Int,
val title: String,
val description: String,
val price: Double,
val image: String,
val category: String,
)
@Dao
interface MenuItemDao {
@Query("SELECT * FROM MenuItemRoom")
fun getAll(): LiveData
@Insert
fun insertAll(vararg menuItems: MenuItemRoom)
@Query("SELECT (SELECT COUNT(*) FROM MenuItemRoom) == 0")
fun isEmpty(): Boolean
}
@Database(entities = [MenuItemRoom::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun menuItemDao(): MenuItemDao
}
Изображение приложения
Это то, что дает вызов API, выполненный в функции fetchMenu :
Код: Выделить всё
{
"menu": [
{
"id": 1,
"title": "Greek Salad",
"description": "The famous greek salad of crispy lettuce, peppers, olives, our Chicago.",
"price": "10",
"image": "https://github.com/Meta-Mobile-Developer-PC/Working-With-Data-API/blob/main/images/greekSalad.jpg?raw=true",
"category": "starters"
},
{
"id": 2,
"title": "Lemon Desert",
"description": "Traditional homemade Italian Lemon Ricotta Cake.",
"price": "10",
"image": "https://github.com/Meta-Mobile-Developer-PC/Working-With-Data-API/blob/main/images/lemonDessert%202.jpg?raw=true",
"category": "desserts"
},
{
"id": 3,
"title": "Grilled Fish",
"description": "Our Bruschetta is made from grilled bread that has been smeared with garlic and seasoned with salt and olive oil.",
"price": "10",
"image": "https://github.com/Meta-Mobile-Developer-PC/Working-With-Data-API/blob/main/images/grilledFish.jpg?raw=true",
"category": "mains"
},
{
"id": 4,
"title": "Pasta",
"description": "Penne with fried aubergines, cherry tomatoes, tomato sauce, fresh chili, garlic, basil & salted ricotta cheese.",
"price": "10",
"image": "https://github.com/Meta-Mobile-Developer-PC/Working-With-Data-API/blob/main/images/pasta.jpg?raw=true",
"category": "mains"
},
{
"id": 5,
"title": "Bruschetta",
"description": "Oven-baked bruschetta stuffed with tomatoes and herbs.",
"price": "10",
"image": "https://github.com/Meta-Mobile-Developer-PC/Working-With-Data-API/blob/main/images/bruschetta.jpg?raw=true",
"category": "starters"
}
]
}
Подробнее здесь: https://stackoverflow.com/questions/788 ... ck-compose