Repository: IChaporgin/RA-learning-app
Pull request #9: RA-11-Implement-a-screen-with-a-list-of-recipes
Author: login: IChaporgin
Created: 2025-05-02T07:15:32Z | Merged: 2025-05-06T06:46:23Z



Diff:
diff --git a/app/src/main/java/ru/ichaporgin/ralearningapp/CategoriesListAdapter.kt b/app/src/main/java/ru/ichaporgin/ralearningapp/CategoriesListAdapter.kt
index 9c45c42..57537d8 100644
--- a/app/src/main/java/ru/ichaporgin/ralearningapp/CategoriesListAdapter.kt
+++ b/app/src/main/java/ru/ichaporgin/ralearningapp/CategoriesListAdapter.kt
@@ -38,7 +38,7 @@ class CategoriesListAdapter(private val dataSet: List<Category>) :
                 loadCategoryImage(category.imageUrl, viewHolder)
                 imgItemCategory.contentDescription =
                     viewHolder.itemView.context.getString(
-                        R.string.category_image_description,
+                        R.string.recipe_image_description,
                         category.title
                     )
                 root.setOnClickListener { itemClickListener?.onItemClick(category.id) }
diff --git a/app/src/main/java/ru/ichaporgin/ralearningapp/RecipeFragment.kt b/app/src/main/java/ru/ichaporgin/ralearningapp/RecipeFragment.kt
new file mode 100644
index 0000000..e20ee32
--- /dev/null
+++ b/app/src/main/java/ru/ichaporgin/ralearningapp/RecipeFragment.kt
@@ -0,0 +1,29 @@
+package ru.ichaporgin.ralearningapp
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import ru.ichaporgin.ralearningapp.databinding.FragmentRecipeBinding
+
+class RecipeFragment: Fragment() {
+    private var _binding: FragmentRecipeBinding? = null
+    private val binding
+        get() = _binding
+            ?: throw IllegalStateException("Binding for FragmentRecipeBinding must not to be null")
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        _binding = FragmentRecipeBinding.inflate(inflater, container, false)
+        return binding.root
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        _binding = null
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/ichaporgin/ralearningapp/RecipesListAdapter.kt b/app/src/main/java/ru/ichaporgin/ralearningapp/RecipesListAdapter.kt
new file mode 100644
index 0000000..0856fad
--- /dev/null
+++ b/app/src/main/java/ru/ichaporgin/ralearningapp/RecipesListAdapter.kt
@@ -0,0 +1,57 @@
+package ru.ichaporgin.ralearningapp
+
+import android.graphics.drawable.Drawable
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import ru.ichaporgin.ralearningapp.databinding.ItemRecipesBinding
+import java.io.InputStream
+
+class RecipesListAdapter(private val dataSet: List<Recipe>) :
+    RecyclerView.Adapter<RecipesListAdapter.ViewHolder>() {
+    interface OnItemClickListener {
+        fun onItemClick(categoryId: Int)
+    }
+
+    private var itemClickListener: OnItemClickListener? = null
+    fun setOnItemClickListener(listener: OnItemClickListener) {
+        itemClickListener = listener
+    }
+
+    class ViewHolder(val binding: ItemRecipesBinding) : RecyclerView.ViewHolder(binding.root)
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+        val binding = ItemRecipesBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+        return ViewHolder(binding)
+    }
+
+    override fun getItemCount() = dataSet.size
+
+    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+        val recipe: Recipe = dataSet[position]
+        with(holder.binding) {
+            textItemRecipeName.text = recipe.title
+            loadCategoryImage(recipe.imageUrl, holder)
+            imgItemRecipe.contentDescription =
+                holder.itemView.context.getString(
+                    R.string.recipe_image_description,
+                    recipe.title
+                )
+            root.setOnClickListener { itemClickListener?.onItemClick(recipe.id) }
+        }
+        holder.binding.imgItemRecipe
+    }
+
+    private fun loadCategoryImage(imageUrl: String, viewHolder: ViewHolder) {
+        try {
+            val inputStream: InputStream = viewHolder.itemView.context.assets.open(imageUrl)
+            val drawable = Drawable.createFromStream(inputStream, null)
+            with(viewHolder.binding) {
+                imgItemRecipe.setImageDrawable(drawable)
+            }
+        } catch (e: Exception) {
+            Log.e("!!!", "Load image error: $imageUrl", e)
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/ichaporgin/ralearningapp/RecipesListFragment.kt b/app/src/main/java/ru/ichaporgin/ralearningapp/RecipesListFragment.kt
index 66f5e37..41eb389 100644
--- a/app/src/main/java/ru/ichaporgin/ralearningapp/RecipesListFragment.kt
+++ b/app/src/main/java/ru/ichaporgin/ralearningapp/RecipesListFragment.kt
@@ -7,6 +7,9 @@ import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import androidx.fragment.app.Fragment
+import androidx.fragment.app.commit
+import androidx.fragment.app.replace
+import androidx.recyclerview.widget.LinearLayoutManager
 import ru.ichaporgin.ralearningapp.databinding.FragmentRecipesListBinding
 
 class RecipesListFragment : Fragment() {
@@ -39,13 +42,14 @@ class RecipesListFragment : Fragment() {
             val drawable = Drawable.createFromStream(inputStream, null)
             if (drawable != null) {
                 binding.imgRecipes.setImageDrawable(drawable)
-                Log.d("CategoriesListFragment", "Картинка успешно загружена")
+                Log.d("RecipesListFragment", "Картинка успешно загружена")
             } else {
-                Log.e("CategoriesListFragment", "Drawable == null")
+                Log.e("RecipesiesListFragment", "Drawable == null")
             }
         } catch (e: Exception) {
-            Log.e("CategoriesListFragment", "Ошибка загрузки картинки", e)
+            Log.e("RecipesListFragment", "Ошибка загрузки картинки", e)
         }
+        initRecycler()
     }
 
     override fun onDestroyView() {
@@ -61,4 +65,23 @@ class RecipesListFragment : Fragment() {
         }
     }
 
+    private fun initRecycler() {
+        Log.d("RecipesListFragment", "initRecycler called")
+        binding.rvRecipes.layoutManager = LinearLayoutManager(requireContext())
+        val categoriesAdapter = RecipesListAdapter(STUB.getRecipesByCategoryId(categoryId ?: 0))
+        binding.rvRecipes.adapter = categoriesAdapter
+        categoriesAdapter.setOnItemClickListener(object :
+            RecipesListAdapter.OnItemClickListener {
+            override fun onItemClick(recipeId: Int) {
+                openRecipeByRecipeId(recipeId)
+            }
+        })
+    }
+    private fun openRecipeByRecipeId(recipeId: Int) {
+        parentFragmentManager.commit {
+            setReorderingAllowed(false)
+            replace<RecipesListFragment>(R.id.mainContainer)
+            addToBackStack(null)
+        }
+    }
 }
diff --git a/app/src/main/java/ru/ichaporgin/ralearningapp/recipes.kt b/app/src/main/java/ru/ichaporgin/ralearningapp/recipes.kt
index 6691c26..24772ee 100644
--- a/app/src/main/java/ru/ichaporgin/ralearningapp/recipes.kt
+++ b/app/src/main/java/ru/ichaporgin/ralearningapp/recipes.kt
@@ -39,6 +39,228 @@ object STUB {
             imageUrl = "salad.png"
         )
     )
+    private val burgerRecipes = listOf(
+        Recipe(
+            id = 0,
+            title = "Классический гамбургер",
+            ingredients = listOf(
+                Ingredient("1", "шт.", "Булочка для гамбургера"),
+                Ingredient("150", "г", "Фарш говяжий"),
+                Ingredient("0.5", "шт.", "Лук репчатый"),
+                Ingredient("1", "лист", "Салат айсберг"),
+                Ingredient("1", "ломтик", "Помидор"),
+                Ingredient("1", "ломтик", "Сыр чеддер"),
+                Ingredient("1", "ст. ложка", "Майонез"),
+                Ingredient("1", "ст. ложка", "Кетчуп"),
+                Ingredient("0.5", "ч. ложки", "Горчица"),
+                Ingredient("1", "г", "Соленые огурцы"),
+                Ingredient("1", "г", "Соль"),
+                Ingredient("0.5", "г", "Перец черный молотый")
+            ),
+            method = listOf(
+                "Разогрейте сковороду и обжаривайте фарш до готовности.",
+                "Лук нарежьте кольцами и добавьте к фаршу. Обжаривайте вместе до золотистой корки.",
+                "Разрежьте булочку на две части и поджарьте их до золотистости.",
+                "На нижнюю часть булочки положите лист салата, ломтик помидора и сыр.",
+                "Добавьте фарш с луком и огурцами.",
+                "Смажьте верхнюю часть булочки майонезом, кетчупом и горчицей.",
+                "Положите верхнюю часть булочки на остальные ингредиенты и подавайте."
+            ),
+            imageUrl = "burger-hamburger.png"
+        ),
+        Recipe(
+            id = 1,
+            title = "Чизбургер",
+            ingredients = listOf(
+                Ingredient("1", "шт.", "Булочка для гамбургера"),
+                Ingredient("150", "г", "Фарш говяжий"),
+                Ingredient("0.5", "шт.", "Лук репчатый"),
+                Ingredient("1", "лист", "Салат айсберг"),
+                Ingredient("1", "ломтик", "Помидор"),
+                Ingredient("1", "ломтик", "Сыр чеддер"),
+                Ingredient("1", "ст. ложка", "Майонез"),
+                Ingredient("1", "ст. ложка", "Кетчуп"),
+                Ingredient("0.5", "ч. ложки", "Горчица"),
+                Ingredient("1", "г", "Соленые огурцы"),
+                Ingredient("1", "г", "Соль"),
+                Ingredient("0.5", "г", "Перец черный молотый")
+            ),
+            method = listOf(
+                "Разогрейте сковороду и обжаривайте фарш до готовности.",
+                "Лук нарежьте кольцами и добавьте к фаршу. Обжаривайте вместе до золотистой корки.",
+                "Разрежьте булочку на две части и поджарьте их до золотистости.",
+                "На нижнюю часть булочки положите лист салата, ломтик помидора и сыр.",
+                "Добавьте фарш с луком и огурцами.",
+                "Смажьте верхнюю часть булочки майонезом, кетчупом и горчицей.",
+                "Положите верхнюю часть булочки на остальные ингредиенты и подавайте."
+            ),
+            imageUrl = "burger-cheeseburger.png"
+        ),
+        Recipe(
+            id = 2,
+            title = "Бургер с грибами и сыром",
+            ingredients = listOf(
+                Ingredient("1", "шт.", "Булочка для гамбургера"),
+                Ingredient("150", "г", "Фарш говяжий"),
+                Ingredient("0.5", "шт.", "Лук репчатый"),
+                Ingredient("1", "лист", "Салат айсберг"),
+                Ingredient("1", "ломтик", "Помидор"),
+                Ingredient("2", "шт.", "Грибы шампиньоны"),
+                Ingredient("1", "ст. ложка", "Майонез"),
+                Ingredient("1", "ст. ложка", "Кетчуп"),
+                Ingredient("0.5", "ч. ложки", "Горчица"),
+                Ingredient("1", "г", "Соль"),
+                Ingredient("0.5", "г", "Перец черный молотый")
+            ),
+            method = listOf(
+                "Разогрейте сковороду и обжаривайте фарш до готовности.",
+                "Лук нарежьте кольцами и добавьте к фаршу. Обжаривайте вместе до золотистой корки.",
+                "Грибы порежьте и обжарьте до золотистой корки.",
+                "Разрежьте булочку на две части и поджарьте их до золотистости.",
+                "На нижнюю часть булочки положите лист салата, ломтик помидора и фарш.",
+                "Добавьте обжаренные грибы.",
+                "Смажьте верхнюю часть булочки майонезом, кетчупом и горчицей.",
+                "Положите верхнюю часть булочки на остальные ингредиенты и подавайте."
+            ),
+            imageUrl = "burger-mushrooms.png"
+        ),
+        Recipe(
+            id = 3,
+            title = "Бургер с курицей и авокадо",
+            ingredients = listOf(
+                Ingredient("1", "шт.", "Булочка для гамбургера"),
+                Ingredient("150", "г", "Куринное филе"),
+                Ingredient("0.5", "шт.", "Лук репчатый"),
+                Ingredient("1", "лист", "Салат айсберг"),
+                Ingredient("1", "ломтик", "Помидор"),
+                Ingredient("0.5", "шт.", "Авокадо"),
+                Ingredient("1", "ст. ложка", "Майонез"),
+                Ingredient("1", "ст. ложка", "Кетчуп"),
+                Ingredient("0.5", "ч. ложки", "Горчица"),
+                Ingredient("1", "г", "Соль"),
+                Ingredient("0.5", "г", "Перец черный молотый")
+            ),
+            method = listOf(
+                "Куринное филе нарежьте на порционные куски и обжаривайте до готовности.",
+                "Лук нарежьте кольцами и добавьте к фаршу. Обжаривайте вместе до золотистой корки.",
+                "Авокадо порежьте ломтиками.",
+                "Разрежьте булочку на две части и поджарьте их до золотистости.",
+                "На нижнюю часть булочки положите лист салата, ломтик помидора и курицу.",
+                "Добавьте ломтики авокадо.",
+                "Смажьте верхнюю часть булочки майонезом, кетчупом и горчицей.",
+                "Положите верхнюю часть булочки на остальные ингредиенты и подавайте."
+            ),
+            imageUrl = "burger-avocado.png"
+        ),
+        Recipe(
+            id = 4,
+            title = "Бургер с рыбой",
+            ingredients = listOf(
+                Ingredient("1", "шт.", "Булочка для гамбургера"),
+                Ingredient("150", "г", "Филе рыбы (треска, лосось и т. д.)"),
+                Ingredient("0.5", "шт.", "Лук репчатый"),
+                Ingredient("1", "лист", "Салат айсберг"),
+                Ingredient("1", "ломтик", "Помидор"),
+                Ingredient("1", "ст. ложка", "Майонез"),
+                Ingredient("1", "ст. ложка", "Кетчуп"),
+                Ingredient("0.5", "ч. ложки", "Горчица"),
+                Ingredient("1", "г", "Соль"),
+                Ingredient("0.5", "г", "Перец черный молотый")
+            ),
+            method = listOf(
+                "Рыбное филе приготовьте по вашему рецепту (можно пожарить, запечь или приготовить на пару).",
+                "Лук нарежьте кольцами и добавьте к рыбе. Обжаривайте вместе до золотистой корки.",
+                "Разрежьте булочку на две части и поджарьте их до золотистости.",
+                "На нижнюю часть булочки положите лист салата, ломтик помидора и рыбу с луком.",
+                "Смажьте верхнюю часть булочки майонезом, кетчупом и горчицей.",
+                "Положите верхнюю часть булочки на остальные ингредиенты и подавайте."
+            ),
+            imageUrl = "burger-fish.png"
+        ),
+        Recipe(
+            id = 5,
+            title = "Бургер с беконом",
+            ingredients = listOf(
+                Ingredient("1", "шт.", "Булочка для гамбургера"),
+                Ingredient("150", "г", "Фарш говяжий"),
+                Ingredient("0.5", "шт.", "Лук репчатый"),
+                Ingredient("1", "лист", "Салат айсберг"),
+                Ingredient("1", "ломтик", "Помидор"),
+                Ingredient("2", "ломтика", "Бекон"),
+                Ingredient("1", "ст. ложка", "Майонез"),
+                Ingredient("1", "ст. ложка", "Кетчуп"),
+                Ingredient("0.5", "ч. ложки", "Горчица"),
+                Ingredient("1", "г", "Соль"),
+                Ingredient("0.5", "г", "Перец черный молотый")
+            ),
+            method = listOf(
+                "Разогрейте сковороду и обжаривайте фарш до готовности.",
+                "Лук нарежьте кольцами и добавьте к фаршу. Обжаривайте вместе до золотистой корки.",
+                "Бекон обжарьте до хрустящей корки.",
+                "Разрежьте булочку на две части и поджарьте их до золотистости.",
+                "На нижнюю часть булочки положите лист салата, ломтик помидора и фарш.",
+                "Добавьте ломтики бекона.",
+                "Смажьте верхнюю часть булочки майонезом, кетчупом и горчицей.",
+                "Положите верхнюю часть булочки на остальные ингредиенты и подавайте."
+            ),
+            imageUrl = "burger-bacon.png"
+        ),
+        Recipe(
+            id = 6,
+            title = "Веганский бургер",
+            ingredients = listOf(
+                Ingredient("1", "шт.", "Веганская булочка для гамбургера"),
+                Ingredient("150", "г", "Фарш из нута"),
+                Ingredient("0.25", "шт.", "Красный лук"),
+                Ingredient("1", "ст. ложка", "Томатный соус"),
+                Ingredient("1", "ст. ложка", "Горчица"),
+                Ingredient("0.5", "г", "Капуста краснокочанная"),
+                Ingredient("0.5", "г", "Морковь"),
+                Ingredient("0.5", "г", "Соль"),
+                Ingredient("0.25", "г", "Черный перец"),
+                Ingredient("0.25", "г", "Паприка"),
+                Ingredient("0.25", "г", "Чеснок в порошке")
+            ),
+            method = listOf(
+                "Фарш из нута приготовьте по вашему рецепту (можно использовать консервированный).",
+                "Лук и капусту нарежьте кольцами, морковь на тонкие полоски.",
+                "Веганскую булочку поджарьте.",
+                "На нижнюю часть булочки положите фарш из нута.",
+                "Добавьте лук, капусту и морковь.",
+                "Смажьте верхнюю часть булочки томатным соусом и горчицей.",
+                "Положите верхнюю часть булочки на остальные ингредиенты и подавайте."
+            ),
+            imageUrl = "burger-vegan.png"
+        ),
+        Recipe(
+            id = 7,
+            title = "Острый гамбургер",
+            ingredients = listOf(
+                Ingredient("1", "шт.", "Булочка для гамбургера"),
+                Ingredient("150", "г", "Фарш говяжий"),
+                Ingredient("0.5", "шт.", "Лук репчатый"),
+                Ingredient("1", "лист", "Салат айсберг"),
+                Ingredient("1", "ломтик", "Помидор"),
+                Ingredient("1", "ломтик", "Сыр чеддер"),
+                Ingredient("1", "ст. ложка", "Майонез"),
+                Ingredient("1", "ст. ложка", "Кетчуп"),
+                Ingredient("1", "ч. ложка", "Соус табаско"),
+                Ingredient("1", "г", "Соль"),
+                Ingredient("0.5", "г", "Перец черный молотый")
+            ),
+            method = listOf(
+                "Разогрейте сковороду и обжаривайте фарш до готовности.",
+                "Лук нарежьте кольцами и добавьте к фаршу. Обжаривайте вместе до золотистой корки.",
+                "Разрежьте булочку на две части и поджарьте их до золотистости.",
+                "На нижнюю часть булочки положите лист салата, ломтик помидора и сыр.",
+                "Добавьте фарш с луком.",
+                "Смажьте верхнюю часть булочки майонезом, кетчупом и соусом табаско.",
+                "Положите верхнюю часть булочки на остальные ингредиенты и подавайте."
+            ),
+            imageUrl = "burger-chili.png"
+        )
+    )
 
     fun getCategories(): List<Category> = categories
+    fun getRecipesByCategoryId(categoryId: Int): List<Recipe> = if (categoryId == 0) burgerRecipes else emptyList()
 }
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_recipe.xml b/app/src/main/res/layout/fragment_recipe.xml
new file mode 100644
index 0000000..361fefa
--- /dev/null
+++ b/app/src/main/res/layout/fragment_recipe.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/Recipe"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center">
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:text="Test" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_recipes_list.xml b/app/src/main/res/layout/fragment_recipes_list.xml
index 60bdb1f..2892cdd 100644
--- a/app/src/main/res/layout/fragment_recipes_list.xml
+++ b/app/src/main/res/layout/fragment_recipes_list.xml
@@ -35,6 +35,7 @@
             android:paddingHorizontal="@dimen/main_margin_half"
             android:paddingVertical="@dimen/main_margin_half"
             android:text="@string/recipes_title_text"
+            tools:text="Бургеры"
             app:layout_constraintBottom_toBottomOf="@+id/imgRecipes"
             app:layout_constraintStart_toStartOf="parent" />
     </androidx.constraintlayout.widget.ConstraintLayout>
@@ -46,5 +47,5 @@
         android:layout_marginHorizontal="@dimen/main_margin_half"
         android:layout_weight="1"
         tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
-        tools:listitem="@layout/item_category" />
+        tools:listitem="@layout/item_recipes" />
 </LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_category.xml b/app/src/main/res/layout/item_category.xml
index f94d2c1..7e18bd2 100644
--- a/app/src/main/res/layout/item_category.xml
+++ b/app/src/main/res/layout/item_category.xml
@@ -22,7 +22,7 @@
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:layout_weight="0.6"
-            android:contentDescription="@string/category_image_description"
+            android:contentDescription="@string/recipe_image_description"
             android:scaleType="centerCrop"
             tools:src="@drawable/burger" />
 
diff --git a/app/src/main/res/layout/item_recipes.xml b/app/src/main/res/layout/item_recipes.xml
new file mode 100644
index 0000000..b4ea5de
--- /dev/null
+++ b/app/src/main/res/layout/item_recipes.xml
@@ -0,0 +1,41 @@
+<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/recipesItem"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/item_recipes_height"
+    android:layout_marginHorizontal="@dimen/main_margin_half"
+    android:layout_marginTop="@dimen/main_margin"
+    android:clickable="true"
+    android:focusable="true"
+    android:foreground="?selectableItemBackground"
+    app:cardCornerRadius="@dimen/corner_radius"
+    app:layout_constraintStart_toStartOf="parent"
+    android:contentDescription="">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <ImageView
+            android:id="@+id/imgItemRecipe"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="0.6"
+            android:contentDescription="@string/recipe_image_description"
+            android:scaleType="centerCrop"
+            tools:src="@drawable/burger" />
+
+        <TextView
+            android:id="@+id/textItemRecipeName"
+            style="@style/StyleItemCategoryTitle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingHorizontal="@dimen/main_margin_half"
+            android:paddingVertical="@dimen/main_margin_half"
+            tools:text="Бургеры" />
+
+    </LinearLayout>
+
+</androidx.cardview.widget.CardView>
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 3e3e277..c27799b 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -12,4 +12,5 @@
     <dimen name="header_text_width">149dp</dimen>
     <dimen name="header_text_height">44dp</dimen>
     <dimen name="title_item_text_size">16sp</dimen>
+    <dimen name="item_recipes_height">132dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 9651264..9ba190c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -5,6 +5,6 @@
     <string name="category_list">список категорий</string>
     <string name="burger_recipes_category">Бургеры</string>
     <string name="category_image">изображение списка категорий</string>
-    <string name="category_image_description">Изображение категории %1$s</string>
+    <string name="recipe_image_description">Изображение рецепта %1$s</string>
     <string name="recipes_title_text">%1$s</string>
 </resources>
\ No newline at end of file


Reviews:
user: login: ArseniyAndroidSprint
state: CHANGES_REQUESTED
author_association: NONE
submitted_at: 2025-05-02T21:18:28Z
user: login: IChaporgin
state: COMMENTED
author_association: OWNER
submitted_at: 2025-05-02T21:53:12Z
user: login: IChaporgin
state: COMMENTED
author_association: OWNER
submitted_at: 2025-05-02T21:54:24Z
user: login: ArseniyAndroidSprint
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-05T22:06:36Z
user: login: ArseniyAndroidSprint
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-05T22:08:01Z
user: login: ArseniyAndroidSprint
state: APPROVED
author_association: NONE
submitted_at: 2025-05-05T22:19:21Z

Review comments:
diff_hunk: @@ -35,6 +35,7 @@
             android:paddingHorizontal="@dimen/main_margin_half"
             android:paddingVertical="@dimen/main_margin_half"
             android:text="@string/recipes_title_text"
+            tools:text="Бургеры"
             app:layout_constraintBottom_toBottomOf="@+id/imgRecipes"
             app:layout_constraintStart_toStartOf="parent" />
     </androidx.constraintlayout.widget.ConstraintLayout>
path: app/src/main/res/layout/fragment_recipes_list.xml
user: login: ArseniyAndroidSprint
body: Ты указал tools:listitem="@layout/item_category", но на этом экране должны отображаться рецепты, а не категории
created_at: 2025-05-02T21:05:55Z
author_association: NONE
diff_hunk: @@ -0,0 +1,60 @@
+package ru.ichaporgin.ralearningapp
+
+import android.graphics.drawable.Drawable
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import ru.ichaporgin.ralearningapp.databinding.ItemRecipesBinding
+import java.io.InputStream
+
+class RecipesListAdapter(private val dataSet: List<Recipe>) : RecyclerView.Adapter<RecipesListAdapter.ViewHolder>() {
+    interface OnItemClickListener {
+        fun onItemClick(categoryId: Int)
+    }
+
+    private var itemClickListener: OnItemClickListener? = null
+    fun setOnItemClickListener(listener: OnItemClickListener) {
+        itemClickListener = listener
+    }
+
+    class ViewHolder (val binding: ItemRecipesBinding) : RecyclerView.ViewHolder(binding.root)
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+        val binding = ItemRecipesBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+        return ViewHolder(binding)
+    }
+
+    override fun getItemCount() = dataSet.size
+
+    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+        try {
+            val recipe: Recipe = dataSet[position]
+            with(holder.binding) {
+                textItemRecipeName.text = recipe.title
+                loadCategoryImage(recipe.imageUrl, holder)
+                imgItemRecipe.contentDescription =
+                    holder.itemView.context.getString(
+                        R.string.category_image_description,
+                        recipe.title
+                    )
+                root.setOnClickListener { itemClickListener?.onItemClick(recipe.id) }
+
+            }
+        } catch (e: Exception) {
+            Log.e("!!!", "File error!!!", e)
+        }
+        holder.binding.imgItemRecipe
path: app/src/main/java/ru/ichaporgin/ralearningapp/RecipesListAdapter.kt
user: login: ArseniyAndroidSprint
body: Это нам тут зачем? =)
created_at: 2025-05-02T21:15:17Z
author_association: NONE
diff_hunk: @@ -0,0 +1,60 @@
+package ru.ichaporgin.ralearningapp
+
+import android.graphics.drawable.Drawable
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import ru.ichaporgin.ralearningapp.databinding.ItemRecipesBinding
+import java.io.InputStream
+
+class RecipesListAdapter(private val dataSet: List<Recipe>) : RecyclerView.Adapter<RecipesListAdapter.ViewHolder>() {
+    interface OnItemClickListener {
+        fun onItemClick(categoryId: Int)
+    }
+
+    private var itemClickListener: OnItemClickListener? = null
+    fun setOnItemClickListener(listener: OnItemClickListener) {
+        itemClickListener = listener
+    }
+
+    class ViewHolder (val binding: ItemRecipesBinding) : RecyclerView.ViewHolder(binding.root)
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+        val binding = ItemRecipesBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+        return ViewHolder(binding)
+    }
+
+    override fun getItemCount() = dataSet.size
+
+    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+        try {
+            val recipe: Recipe = dataSet[position]
+            with(holder.binding) {
+                textItemRecipeName.text = recipe.title
+                loadCategoryImage(recipe.imageUrl, holder)
+                imgItemRecipe.contentDescription =
+                    holder.itemView.context.getString(
+                        R.string.category_image_description,
path: app/src/main/java/ru/ichaporgin/ralearningapp/RecipesListAdapter.kt
user: login: ArseniyAndroidSprint
body: Наверно хотелрецепт называть)  <string name="recipe_image_description">Изображение рецепта %1$s</string>
created_at: 2025-05-02T21:16:30Z
author_association: NONE
diff_hunk: @@ -61,4 +63,23 @@ class RecipesListFragment : Fragment() {
         }
     }
 
+    private fun initRecycler() {
+        Log.d("RecipesListFragment", "initRecycler called")
+        binding.rvRecipes.layoutManager = LinearLayoutManager(requireContext())
+        val categoriesAdapter = RecipesListAdapter(STUB.getRecipesByCategoryId(categoryId ?: 0))
+        binding.rvRecipes.adapter = categoriesAdapter
+        categoriesAdapter.setOnItemClickListener(object :
+            RecipesListAdapter.OnItemClickListener {
+            override fun onItemClick(recipeId: Int) {
+                openRecipeByRecipeId(recipeId)
+            }
+        })
+    }
+    private fun openRecipeByRecipeId(recipeId: Int) {
+        val fragment = RecipeFragment()
+        parentFragmentManager.beginTransaction()
+            .replace(R.id.mainContainer, fragment)
path: app/src/main/java/ru/ichaporgin/ralearningapp/RecipesListFragment.kt
user: login: ArseniyAndroidSprint
body:  replace<RecipeFragment>(R.id.mainContainer)
created_at: 2025-05-02T21:18:00Z
author_association: NONE
diff_hunk: @@ -61,4 +63,23 @@ class RecipesListFragment : Fragment() {
         }
     }
 
+    private fun initRecycler() {
+        Log.d("RecipesListFragment", "initRecycler called")
+        binding.rvRecipes.layoutManager = LinearLayoutManager(requireContext())
+        val categoriesAdapter = RecipesListAdapter(STUB.getRecipesByCategoryId(categoryId ?: 0))
+        binding.rvRecipes.adapter = categoriesAdapter
+        categoriesAdapter.setOnItemClickListener(object :
+            RecipesListAdapter.OnItemClickListener {
+            override fun onItemClick(recipeId: Int) {
+                openRecipeByRecipeId(recipeId)
+            }
+        })
+    }
+    private fun openRecipeByRecipeId(recipeId: Int) {
+        val fragment = RecipeFragment()
+        parentFragmentManager.beginTransaction()
path: app/src/main/java/ru/ichaporgin/ralearningapp/RecipesListFragment.kt
user: login: ArseniyAndroidSprint
body: Ты используешь устаревший способ с beginTransaction(). Подход с KTX делает код короче и безопаснее. Используй метод commit {} с функцией replace<RecipeFragment>(), который предоставляют KTX-расширения. 
created_at: 2025-05-02T21:18:18Z
author_association: NONE
diff_hunk: @@ -35,6 +35,7 @@
             android:paddingHorizontal="@dimen/main_margin_half"
             android:paddingVertical="@dimen/main_margin_half"
             android:text="@string/recipes_title_text"
+            tools:text="Бургеры"
             app:layout_constraintBottom_toBottomOf="@+id/imgRecipes"
             app:layout_constraintStart_toStartOf="parent" />
     </androidx.constraintlayout.widget.ConstraintLayout>
path: app/src/main/res/layout/fragment_recipes_list.xml
user: login: IChaporgin
body: Хотел проверить, будут ли отображаться карточки в превью, но у меня по прежнему не видно сетки
created_at: 2025-05-02T21:53:12Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,60 @@
+package ru.ichaporgin.ralearningapp
+
+import android.graphics.drawable.Drawable
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import ru.ichaporgin.ralearningapp.databinding.ItemRecipesBinding
+import java.io.InputStream
+
+class RecipesListAdapter(private val dataSet: List<Recipe>) : RecyclerView.Adapter<RecipesListAdapter.ViewHolder>() {
+    interface OnItemClickListener {
+        fun onItemClick(categoryId: Int)
+    }
+
+    private var itemClickListener: OnItemClickListener? = null
+    fun setOnItemClickListener(listener: OnItemClickListener) {
+        itemClickListener = listener
+    }
+
+    class ViewHolder (val binding: ItemRecipesBinding) : RecyclerView.ViewHolder(binding.root)
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+        val binding = ItemRecipesBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+        return ViewHolder(binding)
+    }
+
+    override fun getItemCount() = dataSet.size
+
+    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+        try {
+            val recipe: Recipe = dataSet[position]
+            with(holder.binding) {
+                textItemRecipeName.text = recipe.title
+                loadCategoryImage(recipe.imageUrl, holder)
+                imgItemRecipe.contentDescription =
+                    holder.itemView.context.getString(
+                        R.string.category_image_description,
path: app/src/main/java/ru/ichaporgin/ralearningapp/RecipesListAdapter.kt
user: login: IChaporgin
body: Вроде работает)) При необходимости могу убрать
created_at: 2025-05-02T21:54:23Z
author_association: OWNER
diff_hunk: @@ -35,6 +35,7 @@
             android:paddingHorizontal="@dimen/main_margin_half"
             android:paddingVertical="@dimen/main_margin_half"
             android:text="@string/recipes_title_text"
+            tools:text="Бургеры"
             app:layout_constraintBottom_toBottomOf="@+id/imgRecipes"
             app:layout_constraintStart_toStartOf="parent" />
     </androidx.constraintlayout.widget.ConstraintLayout>
path: app/src/main/res/layout/fragment_recipes_list.xml
user: login: ArseniyAndroidSprint
body: Что карточки не отображаются в превью RecyclerView это известная проблема некоторых версий Android Studio после обновления. Атрибуты tools могут не отображаться корректно. Попробуй перезапустить студию или очистить кеш (File > Invalidate Caches / Restart). Не переживай, это проблема с IDE, а не с твоим кодом)
У меня на meerkat тоже отвалилось, пока откатил обратно до ladybug
created_at: 2025-05-05T22:06:35Z
author_association: NONE
diff_hunk: @@ -0,0 +1,60 @@
+package ru.ichaporgin.ralearningapp
+
+import android.graphics.drawable.Drawable
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import ru.ichaporgin.ralearningapp.databinding.ItemRecipesBinding
+import java.io.InputStream
+
+class RecipesListAdapter(private val dataSet: List<Recipe>) : RecyclerView.Adapter<RecipesListAdapter.ViewHolder>() {
+    interface OnItemClickListener {
+        fun onItemClick(categoryId: Int)
+    }
+
+    private var itemClickListener: OnItemClickListener? = null
+    fun setOnItemClickListener(listener: OnItemClickListener) {
+        itemClickListener = listener
+    }
+
+    class ViewHolder (val binding: ItemRecipesBinding) : RecyclerView.ViewHolder(binding.root)
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+        val binding = ItemRecipesBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+        return ViewHolder(binding)
+    }
+
+    override fun getItemCount() = dataSet.size
+
+    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+        try {
+            val recipe: Recipe = dataSet[position]
+            with(holder.binding) {
+                textItemRecipeName.text = recipe.title
+                loadCategoryImage(recipe.imageUrl, holder)
+                imgItemRecipe.contentDescription =
+                    holder.itemView.context.getString(
+                        R.string.category_image_description,
path: app/src/main/java/ru/ichaporgin/ralearningapp/RecipesListAdapter.kt
user: login: ArseniyAndroidSprint
body: Работает, ты прав! но ресурс с текстом для категорий, а фрагмент у нас с рецептами)
created_at: 2025-05-05T22:08:01Z
author_association: NONE

PR comments:
user: login: IChaporgin
created_at: 2025-05-02T21:58:23Z
body: Исправляю ошибки, но я давно столкнулся с проблемой, что я не понимаю сути как все работает. Условно пишу код, но нет понимания, исправление каких-то косяков идет в гуглении и проверке сработает како-то метод или нет((((
author_association: OWNER
user: login: ArseniyAndroidSprint
created_at: 2025-05-05T22:21:16Z
body: > Исправляю ошибки, но я давно столкнулся с проблемой, что я не понимаю сути как все работает. Условно пишу код, но нет понимания, исправление каких-то косяков идет в гуглении и проверке сработает како-то метод или нет((((

Привет! То, что ты описываешь это абсолютно нормальная часть пути каждого разработчика, и я тоже через это проходил..
Давай попробуем сделать иначе. Не просто исправлять код, а разбираться с каждой сложность. Я постараюсь подробнее описывать нюансы, но попрошу тебя оставлять комменты прям по коду, если понимаешь, что тяжело пошла конструкция

Я буду отвечать на каждый такой вопрос и подкидывать дополнительные материалы. Это гораздо эффективнее, чем гуглить наугад.
author_association: NONE