From 0b9caef00c001a8b27d497fb4dd4407ff7dabd19 Mon Sep 17 00:00:00 2001 From: Anv0l Date: Tue, 29 Apr 2025 16:18:09 +0300 Subject: [PATCH 1/5] Attempt was made but it wasn't enough --- .../ru/otus/cookbook/ui/CookbookAdapter.kt | 14 ++++ .../ru/otus/cookbook/ui/CookbookFragment.kt | 7 ++ app/src/main/res/layout/activity_main.xml | 13 ++-- app/src/main/res/layout/fragment_cookbook.xml | 11 +++ .../main/res/layout/vh_recipe_category.xml | 21 ++++- app/src/main/res/layout/vh_recipe_item.xml | 78 ++++++++++++++++++- 6 files changed, 133 insertions(+), 11 deletions(-) create mode 100644 app/src/main/kotlin/ru/otus/cookbook/ui/CookbookAdapter.kt diff --git a/app/src/main/kotlin/ru/otus/cookbook/ui/CookbookAdapter.kt b/app/src/main/kotlin/ru/otus/cookbook/ui/CookbookAdapter.kt new file mode 100644 index 0000000..74c93e4 --- /dev/null +++ b/app/src/main/kotlin/ru/otus/cookbook/ui/CookbookAdapter.kt @@ -0,0 +1,14 @@ +package ru.otus.cookbook.ui + +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import ru.otus.cookbook.data.Recipe + +class CookbookAdapter(private val categories: List) : + RecyclerView.Adapter() { + inner class CategoryViewHolder(itemView: View) : ViewHolder(itemView) {} + + inner class RecipeViewHolder(itemView: View) : ViewHolder(itemView) {} + +} \ No newline at end of file diff --git a/app/src/main/kotlin/ru/otus/cookbook/ui/CookbookFragment.kt b/app/src/main/kotlin/ru/otus/cookbook/ui/CookbookFragment.kt index efe6939..a88f591 100644 --- a/app/src/main/kotlin/ru/otus/cookbook/ui/CookbookFragment.kt +++ b/app/src/main/kotlin/ru/otus/cookbook/ui/CookbookFragment.kt @@ -8,7 +8,9 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.RecyclerView import kotlinx.coroutines.launch +import ru.otus.cookbook.R import ru.otus.cookbook.data.RecipeListItem import ru.otus.cookbook.databinding.FragmentCookbookBinding @@ -37,6 +39,11 @@ class CookbookFragment : Fragment() { } private fun setupRecyclerView() = binding.withBinding { + view.findViewById(R.id.rec_view_category).apply { + adapter = CookbookAdapter(model.recipeList.value.get(0), object: CookbookAdapter.onItemClick { + + } ) + } // Setup RecyclerView } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 86a5d97..b1dc094 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -7,13 +7,10 @@ android:layout_height="match_parent" tools:context=".MainActivity"> - + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_cookbook.xml b/app/src/main/res/layout/fragment_cookbook.xml index 77d9ef6..d907a7c 100644 --- a/app/src/main/res/layout/fragment_cookbook.xml +++ b/app/src/main/res/layout/fragment_cookbook.xml @@ -1,6 +1,17 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/vh_recipe_category.xml b/app/src/main/res/layout/vh_recipe_category.xml index 006fd49..82ed2b3 100644 --- a/app/src/main/res/layout/vh_recipe_category.xml +++ b/app/src/main/res/layout/vh_recipe_category.xml @@ -1,6 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/vh_recipe_item.xml b/app/src/main/res/layout/vh_recipe_item.xml index 006fd49..53c4b71 100644 --- a/app/src/main/res/layout/vh_recipe_item.xml +++ b/app/src/main/res/layout/vh_recipe_item.xml @@ -1,6 +1,80 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="5dp"> + + + + + + + + + + + + + + + + + + \ No newline at end of file From 28f4e115ff1127bec9902a33bf7801aaca41463b Mon Sep 17 00:00:00 2001 From: Anv0l Date: Tue, 29 Apr 2025 16:18:25 +0300 Subject: [PATCH 2/5] Attempt was made but it wasn't enough --- .../main/res/layout-v28/vh_recipe_item.xml | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 app/src/main/res/layout-v28/vh_recipe_item.xml diff --git a/app/src/main/res/layout-v28/vh_recipe_item.xml b/app/src/main/res/layout-v28/vh_recipe_item.xml new file mode 100644 index 0000000..36f593c --- /dev/null +++ b/app/src/main/res/layout-v28/vh_recipe_item.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 2e321ade792fad0372fa6261ada05684879beadd Mon Sep 17 00:00:00 2001 From: Anv0l Date: Sat, 3 May 2025 14:31:30 +0300 Subject: [PATCH 3/5] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD=D0=B8=D1=8F=201-3.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 1 + app/src/main/AndroidManifest.xml | 5 +- .../kotlin/ru/otus/cookbook/MainActivity.kt | 7 ++ .../ru/otus/cookbook/ui/CookbookAdapter.kt | 103 ++++++++++++++++-- .../ru/otus/cookbook/ui/CookbookFragment.kt | 31 ++++-- .../otus/cookbook/ui/DialogFragmentDelete.kt | 40 +++++++ .../ru/otus/cookbook/ui/RecipeFragment.kt | 51 ++++++++- app/src/main/res/anim/slide_in_left.xml | 7 ++ app/src/main/res/anim/slide_in_right.xml | 7 ++ app/src/main/res/anim/slide_out_left.xml | 7 ++ app/src/main/res/anim/slide_out_right.xml | 7 ++ app/src/main/res/drawable/arrow_back_24dp.xml | 9 ++ app/src/main/res/drawable/category_80dp.xml | 9 ++ .../main/res/drawable/category_xxx_width.xml | 9 ++ .../main/res/drawable/circle_background.xml | 9 ++ app/src/main/res/drawable/close_24dp.xml | 9 ++ app/src/main/res/drawable/delete_24dp.xml | 9 ++ .../main/res/layout-v28/vh_recipe_item.xml | 87 --------------- app/src/main/res/layout/activity_main.xml | 15 +-- app/src/main/res/layout/fragment_cookbook.xml | 48 +++++++- app/src/main/res/layout/fragment_recipe.xml | 95 +++++++++++++++- .../main/res/layout/vh_recipe_category.xml | 17 +-- app/src/main/res/layout/vh_recipe_item.xml | 64 ++++++----- app/src/main/res/menu/recipe_menu.xml | 9 ++ app/src/main/res/navigation/nav_graph.xml | 50 +++++++++ app/src/main/res/values/colors.xml | 5 + app/src/main/res/values/dimens.xml | 11 ++ app/src/main/res/values/strings.xml | 14 +++ gradle/libs.versions.toml | 14 ++- 29 files changed, 587 insertions(+), 162 deletions(-) create mode 100644 app/src/main/kotlin/ru/otus/cookbook/ui/DialogFragmentDelete.kt create mode 100644 app/src/main/res/anim/slide_in_left.xml create mode 100644 app/src/main/res/anim/slide_in_right.xml create mode 100644 app/src/main/res/anim/slide_out_left.xml create mode 100644 app/src/main/res/anim/slide_out_right.xml create mode 100644 app/src/main/res/drawable/arrow_back_24dp.xml create mode 100644 app/src/main/res/drawable/category_80dp.xml create mode 100644 app/src/main/res/drawable/category_xxx_width.xml create mode 100644 app/src/main/res/drawable/circle_background.xml create mode 100644 app/src/main/res/drawable/close_24dp.xml create mode 100644 app/src/main/res/drawable/delete_24dp.xml delete mode 100644 app/src/main/res/layout-v28/vh_recipe_item.xml create mode 100644 app/src/main/res/menu/recipe_menu.xml create mode 100644 app/src/main/res/navigation/nav_graph.xml create mode 100644 app/src/main/res/values/dimens.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f3207a6..1b3b0dc 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -48,6 +48,7 @@ dependencies { implementation(libs.material) implementation(libs.androidx.activity) implementation(libs.androidx.constraintlayout) + implementation(libs.github.glide) testImplementation(libs.junit) testImplementation(libs.kotlin.coroutines.test) } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 063f4d1..f90e760 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,10 +2,13 @@ + + ) : - RecyclerView.Adapter() { - inner class CategoryViewHolder(itemView: View) : ViewHolder(itemView) {} - inner class RecipeViewHolder(itemView: View) : ViewHolder(itemView) {} +class CookbookAdapter( + private val onRecipeClick: (Int) -> Unit +) : + ListAdapter(RecipeDiff) { + + override fun getItemViewType(position: Int): Int { + return getItem(position).layoutId + } + + + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ) = when (viewType) { + RecipeListItem.CategoryItem.layoutId -> CookbookViewHolder.CategoryHolder( + VhRecipeCategoryBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + + RecipeListItem.RecipeItem.layoutId -> CookbookViewHolder.RecipeHolder( + VhRecipeItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ), onRecipeClick + ) + + else -> throw IllegalArgumentException("View is not supported") + } + + override fun onBindViewHolder(holder: CookbookAdapter.CookbookViewHolder, position: Int) { + when (holder) { + is CookbookViewHolder.CategoryHolder -> holder.bind(getItem(position) as RecipeListItem.CategoryItem) + is CookbookViewHolder.RecipeHolder -> holder.bind(getItem(position) as RecipeListItem.RecipeItem) + } + } + + sealed class CookbookViewHolder(view: View) : ViewHolder(view) { + class RecipeHolder( + private val binding: VhRecipeItemBinding, + private val onClick: (Int) -> Unit + ) : CookbookViewHolder(binding.root) { + private var id: Int = -1 + + init { + binding.root.setOnClickListener { onClick(id) } + } + + fun bind(recipe: RecipeListItem.RecipeItem) = with(binding) { + this@RecipeHolder.id = recipe.id + txtRecipeAvatar.text = recipe.title[0].uppercase() + txtRecipeName.text = recipe.title + txtRecipeDescription.text = recipe.description + Glide.with(root.context).load(recipe.imageUrl).centerCrop().into(imgRecipeImage) + } + + } + + class CategoryHolder( + private val binding: VhRecipeCategoryBinding + ) : + CookbookViewHolder(binding.root) { + + fun bind(category: RecipeListItem.CategoryItem) = with(binding) { + txtCategoryName.text = category.name + } + } + } + +} + +private object RecipeDiff : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: RecipeListItem, newItem: RecipeListItem): Boolean { + return when { + oldItem is RecipeListItem.RecipeItem && newItem is RecipeListItem.RecipeItem -> oldItem.id == newItem.id + oldItem is RecipeListItem.CategoryItem && newItem is RecipeListItem.CategoryItem -> oldItem.category == newItem.category + else -> false + } + } + + override fun areContentsTheSame(oldItem: RecipeListItem, newItem: RecipeListItem): Boolean { + return oldItem == newItem + } +} + -} \ No newline at end of file diff --git a/app/src/main/kotlin/ru/otus/cookbook/ui/CookbookFragment.kt b/app/src/main/kotlin/ru/otus/cookbook/ui/CookbookFragment.kt index a88f591..bdd8d78 100644 --- a/app/src/main/kotlin/ru/otus/cookbook/ui/CookbookFragment.kt +++ b/app/src/main/kotlin/ru/otus/cookbook/ui/CookbookFragment.kt @@ -4,13 +4,13 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope -import androidx.recyclerview.widget.RecyclerView +import androidx.navigation.fragment.findNavController import kotlinx.coroutines.launch -import ru.otus.cookbook.R import ru.otus.cookbook.data.RecipeListItem import ru.otus.cookbook.databinding.FragmentCookbookBinding @@ -19,6 +19,14 @@ class CookbookFragment : Fragment() { private val binding = FragmentBindingDelegate(this) private val model: CookbookFragmentViewModel by viewModels { CookbookFragmentViewModel.Factory } + private val adapter = CookbookAdapter( + { id -> + val navController = findNavController() + val action = CookbookFragmentDirections.actionCookbookToRecipe(id) + navController.navigate(action) + } + ) + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -31,6 +39,7 @@ class CookbookFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setupRecyclerView() + setupAppBar() viewLifecycleOwner.lifecycleScope.launch { model.recipeList .flowWithLifecycle(viewLifecycleOwner.lifecycle) @@ -38,16 +47,20 @@ class CookbookFragment : Fragment() { } } - private fun setupRecyclerView() = binding.withBinding { - view.findViewById(R.id.rec_view_category).apply { - adapter = CookbookAdapter(model.recipeList.value.get(0), object: CookbookAdapter.onItemClick { - - } ) + private fun setupAppBar() { + binding.withBinding { + cookbookToolbar.setNavigationOnClickListener { + Toast.makeText(requireContext(), "Close application?", Toast.LENGTH_LONG).show() + } } - // Setup RecyclerView + } + + + private fun setupRecyclerView() = binding.withBinding { + recViewCategory.adapter = adapter } private fun onRecipeListUpdated(recipeList: List) { - // Handle recipe list + adapter.submitList(recipeList) } } \ No newline at end of file diff --git a/app/src/main/kotlin/ru/otus/cookbook/ui/DialogFragmentDelete.kt b/app/src/main/kotlin/ru/otus/cookbook/ui/DialogFragmentDelete.kt new file mode 100644 index 0000000..cf2c766 --- /dev/null +++ b/app/src/main/kotlin/ru/otus/cookbook/ui/DialogFragmentDelete.kt @@ -0,0 +1,40 @@ +package ru.otus.cookbook.ui + +import android.app.AlertDialog +import android.app.Dialog +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import androidx.navigation.fragment.findNavController +import ru.otus.cookbook.R + +class DialogFragmentDelete : DialogFragment() { + private val title: String get() = DialogFragmentDeleteArgs.fromBundle(requireArguments()).title + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = + requireContext().let { + val navController = findNavController() + AlertDialog.Builder(it) + + .setTitle(getString(R.string.delete_dialog_title, title)) + .setMessage(getString(R.string.delete_dialog_message, title)) + .setPositiveButton(getString(R.string.delete_dialog_positive_button)) { _, _ -> + navController.previousBackStackEntry?.savedStateHandle?.set( + DIALOG_RESULT_KEY, + true + ) + } + .setNegativeButton(getString(R.string.delete_dialog_negative_button)) { _, _ -> + navController.previousBackStackEntry?.savedStateHandle?.set( + DIALOG_RESULT_KEY, + false + ) + } + .create() + } + + companion object { + const val DIALOG_RESULT_KEY = "deleteResult" + } + +} + diff --git a/app/src/main/kotlin/ru/otus/cookbook/ui/RecipeFragment.kt b/app/src/main/kotlin/ru/otus/cookbook/ui/RecipeFragment.kt index e4460c1..d882f5b 100644 --- a/app/src/main/kotlin/ru/otus/cookbook/ui/RecipeFragment.kt +++ b/app/src/main/kotlin/ru/otus/cookbook/ui/RecipeFragment.kt @@ -1,6 +1,7 @@ package ru.otus.cookbook.ui import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -9,15 +10,18 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.viewmodel.MutableCreationExtras +import androidx.navigation.fragment.findNavController +import com.bumptech.glide.Glide import kotlinx.coroutines.launch +import ru.otus.cookbook.R import ru.otus.cookbook.data.Recipe import ru.otus.cookbook.databinding.FragmentRecipeBinding class RecipeFragment : Fragment() { - private val recipeId: Int get() = TODO("Use Safe Args to get the recipe ID: https://developer.android.com/guide/navigation/use-graph/pass-data#Safe-args") - + private val recipeId: Int get() = RecipeFragmentArgs.fromBundle(requireArguments()).recipeId private val binding = FragmentBindingDelegate(this) + private val model: RecipeFragmentViewModel by viewModels( extrasProducer = { MutableCreationExtras(defaultViewModelCreationExtras).apply { @@ -27,6 +31,7 @@ class RecipeFragment : Fragment() { factoryProducer = { RecipeFragmentViewModel.Factory } ) + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -38,6 +43,8 @@ class RecipeFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + setupAppBar() + setupDialogObserver() viewLifecycleOwner.lifecycleScope.launch { model.recipe .flowWithLifecycle(viewLifecycleOwner.lifecycle) @@ -45,6 +52,16 @@ class RecipeFragment : Fragment() { } } + private fun setupDialogObserver() { + findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData( + DialogFragmentDelete.DIALOG_RESULT_KEY + )?.observe(viewLifecycleOwner) { result -> + if (result) { + deleteRecipe() + } + } + } + /** * Use to get recipe title and pass to confirmation dialog */ @@ -52,11 +69,39 @@ class RecipeFragment : Fragment() { return model.recipe.value.title } + private fun setupAppBar() { + binding.withBinding { + recipeToolbar.setNavigationOnClickListener { + findNavController().navigate(R.id.action_recipe_to_cookbook) + } + recipeToolbar.setOnMenuItemClickListener { menuItem -> + when (menuItem.itemId) { + R.id.delete_recipe -> { + val navController = findNavController() + val action = RecipeFragmentDirections.actionRecipeToDialogDelete(getTitle()) + findNavController().navigate(action) + true + } + + else -> false + } + } + } + } + private fun displayRecipe(recipe: Recipe) { - // Display the recipe + binding.withBinding { + txtRecipeName.text = recipe.title + txtRecipeDescription.text = recipe.description + txtRecipeSteps.text = + recipe.steps.mapIndexed { index, step -> "${index + 1}. $step" }.joinToString("\n") + Glide.with(root.context).load(recipe.imageUrl).into(imgRecipeImageBig) + recipeToolbar.title = recipe.title + } } private fun deleteRecipe() { model.delete() + findNavController().navigate(R.id.action_dialog_delete_to_cookbook) } } \ No newline at end of file diff --git a/app/src/main/res/anim/slide_in_left.xml b/app/src/main/res/anim/slide_in_left.xml new file mode 100644 index 0000000..2e2ffcd --- /dev/null +++ b/app/src/main/res/anim/slide_in_left.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/slide_in_right.xml b/app/src/main/res/anim/slide_in_right.xml new file mode 100644 index 0000000..8669814 --- /dev/null +++ b/app/src/main/res/anim/slide_in_right.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/slide_out_left.xml b/app/src/main/res/anim/slide_out_left.xml new file mode 100644 index 0000000..59195b4 --- /dev/null +++ b/app/src/main/res/anim/slide_out_left.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/slide_out_right.xml b/app/src/main/res/anim/slide_out_right.xml new file mode 100644 index 0000000..8669814 --- /dev/null +++ b/app/src/main/res/anim/slide_out_right.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/arrow_back_24dp.xml b/app/src/main/res/drawable/arrow_back_24dp.xml new file mode 100644 index 0000000..1c25a9a --- /dev/null +++ b/app/src/main/res/drawable/arrow_back_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/category_80dp.xml b/app/src/main/res/drawable/category_80dp.xml new file mode 100644 index 0000000..8642d79 --- /dev/null +++ b/app/src/main/res/drawable/category_80dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/category_xxx_width.xml b/app/src/main/res/drawable/category_xxx_width.xml new file mode 100644 index 0000000..ab6455e --- /dev/null +++ b/app/src/main/res/drawable/category_xxx_width.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/circle_background.xml b/app/src/main/res/drawable/circle_background.xml new file mode 100644 index 0000000..d7c8e96 --- /dev/null +++ b/app/src/main/res/drawable/circle_background.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/close_24dp.xml b/app/src/main/res/drawable/close_24dp.xml new file mode 100644 index 0000000..7393823 --- /dev/null +++ b/app/src/main/res/drawable/close_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/delete_24dp.xml b/app/src/main/res/drawable/delete_24dp.xml new file mode 100644 index 0000000..7c0eee8 --- /dev/null +++ b/app/src/main/res/drawable/delete_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout-v28/vh_recipe_item.xml b/app/src/main/res/layout-v28/vh_recipe_item.xml deleted file mode 100644 index 36f593c..0000000 --- a/app/src/main/res/layout-v28/vh_recipe_item.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index b1dc094..68a355d 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,16 +1,13 @@ - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_cookbook.xml b/app/src/main/res/layout/fragment_cookbook.xml index d907a7c..0657f10 100644 --- a/app/src/main/res/layout/fragment_cookbook.xml +++ b/app/src/main/res/layout/fragment_cookbook.xml @@ -1,17 +1,55 @@ + android:layout_height="match_parent" + android:fitsSystemWindows="true"> - + + + + + + + + + + + + + + + + \ 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 index 77d9ef6..e7aebb2 100644 --- a/app/src/main/res/layout/fragment_recipe.xml +++ b/app/src/main/res/layout/fragment_recipe.xml @@ -1,6 +1,99 @@ + android:layout_height="match_parent" + android:fitsSystemWindows="true"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/vh_recipe_category.xml b/app/src/main/res/layout/vh_recipe_category.xml index 82ed2b3..e1d6830 100644 --- a/app/src/main/res/layout/vh_recipe_category.xml +++ b/app/src/main/res/layout/vh_recipe_category.xml @@ -1,6 +1,7 @@ @@ -8,18 +9,20 @@ android:id="@+id/txt_category_name" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="Category placeholder" - android:textSize="36sp" + android:text="@string/category_placeholder" + android:textSize="@dimen/category_name" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> - - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/vh_recipe_item.xml b/app/src/main/res/layout/vh_recipe_item.xml index 53c4b71..8f02621 100644 --- a/app/src/main/res/layout/vh_recipe_item.xml +++ b/app/src/main/res/layout/vh_recipe_item.xml @@ -7,47 +7,51 @@ - @@ -56,23 +60,29 @@ android:id="@+id/txt_recipe_name" android:layout_width="0dp" android:layout_height="wrap_content" - android:text="Placeholder recipe name" - android:textSize="16dp" - android:textStyle="bold" + android:layout_marginLeft="10dp" + android:layout_marginRight="10dp" android:layout_marginBottom="5dp" + android:ellipsize="end" + android:lines="1" + android:text="@string/recipe_name_placeholder" + android:textSize="16sp" + android:textStyle="bold" app:layout_constraintBottom_toTopOf="@id/guideline_recipe" - app:layout_constraintLeft_toRightOf="@id/txt_recipe_shortcut" - app:layout_constraintRight_toRightOf="@id/img_recipe_image" /> + app:layout_constraintLeft_toRightOf="@id/txt_recipe_avatar" + app:layout_constraintRight_toLeftOf="@id/img_recipe_image" /> + android:ellipsize="end" + android:lines="1" + android:text="@string/recipe_description_placeholder" + app:layout_constraintLeft_toLeftOf="@id/txt_recipe_name" + app:layout_constraintRight_toRightOf="@id/txt_recipe_name" + app:layout_constraintTop_toTopOf="@id/guideline_recipe" /> diff --git a/app/src/main/res/menu/recipe_menu.xml b/app/src/main/res/menu/recipe_menu.xml new file mode 100644 index 0000000..7a48c56 --- /dev/null +++ b/app/src/main/res/menu/recipe_menu.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml new file mode 100644 index 0000000..8d73d35 --- /dev/null +++ b/app/src/main/res/navigation/nav_graph.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index c8524cd..45697af 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -2,4 +2,9 @@ #FF000000 #FFFFFFFF + + #F3EDF7 + #DADCE0 + + #F3EDF7 \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..f189e6f --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,11 @@ + + + 32sp + 10dp + 24sp + 24sp + 36sp + 80dp + 40dp + 16sp + \ 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 8fce1d1..b4327a3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,17 @@ Cookbook + Cookbook + Recipe name placeholder + A recipe image + Recipe Description placeholder + Recipe steps Lorem ipsum Quisque blandit dolor vel ullamcorper fringilla. Etiam ut ultricies nibh. Maecenas sit amet ipsum at felis convallis luctus. Praesent at urna ac massa eleifend iaculis. Donec at venenatis metus. Donec malesuada sapien eget neque finibus, vel aliquam mi lacinia. Mauris a sem elementum, pretium diam nec, luctus neque. Praesent lacinia imperdiet erat, eget feugiat mi feugiat ut. Proin iaculis, massa eu lacinia tempor, dui lacus pellentesque dui, ut dapibus tellus purus at augue. Nam sagittis lobortis justo vel porta. Proin vel vulputate quam. Vivamus at vestibulum est. Phasellus a arcu lacus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nullam elit mauris, pharetra vitae libero sit amet, efficitur rhoncus mauris. + Category placeholder + + + Delete %s recipe + Are you sure you want to delete the "%s" recipe? + Yes + No + C + \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 515d8d1..594d23c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,23 +1,25 @@ [versions] agp = "8.7.3" +glideVersion = "4.16.0" kotlin = "2.1.0" -coreKtx = "1.15.0" -fragmentKtx = "1.8.5" +coreKtx = "1.16.0" +fragmentKtx = "1.8.6" lifecycleKtx = "2.8.7" -navigation = "2.8.5" +navigation = "2.8.9" junit = "4.13.2" appcompat = "1.7.0" material = "1.12.0" -activity = "1.9.3" -constraintlayout = "2.2.0" +activity = "1.10.1" +constraintlayout = "2.2.1" coroutines = "1.9.0" junitVersion = "1.2.1" espressoCore = "3.6.1" serialization = "1.7.3" -datastore = "1.1.1" +datastore = "1.1.5" [libraries] +github-glide = { module = "com.github.bumptech.glide:glide", version.ref = "glideVersion" } kotlin-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" } kotlin-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" } kotlin-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" } From babf9bdc83e941868e132b00cb6fdb3f0e6e2fbc Mon Sep 17 00:00:00 2001 From: Anv0l Date: Sat, 3 May 2025 14:34:12 +0300 Subject: [PATCH 4/5] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 1 - app/src/main/kotlin/ru/otus/cookbook/ui/CookbookAdapter.kt | 2 +- app/src/main/kotlin/ru/otus/cookbook/ui/RecipeFragment.kt | 3 +-- app/src/main/res/drawable/category_xxx_width.xml | 4 ++-- app/src/main/res/layout/fragment_recipe.xml | 2 +- app/src/main/res/layout/vh_recipe_item.xml | 1 + app/src/main/res/menu/recipe_menu.xml | 2 +- app/src/main/res/values/strings.xml | 3 ++- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f90e760..0f330b5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -8,7 +8,6 @@ android:name=".App" android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" - android:enableOnBackInvokedCallback="true" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" diff --git a/app/src/main/kotlin/ru/otus/cookbook/ui/CookbookAdapter.kt b/app/src/main/kotlin/ru/otus/cookbook/ui/CookbookAdapter.kt index ec7f6c4..b4d65fd 100644 --- a/app/src/main/kotlin/ru/otus/cookbook/ui/CookbookAdapter.kt +++ b/app/src/main/kotlin/ru/otus/cookbook/ui/CookbookAdapter.kt @@ -45,7 +45,7 @@ class CookbookAdapter( else -> throw IllegalArgumentException("View is not supported") } - override fun onBindViewHolder(holder: CookbookAdapter.CookbookViewHolder, position: Int) { + override fun onBindViewHolder(holder: CookbookViewHolder, position: Int) { when (holder) { is CookbookViewHolder.CategoryHolder -> holder.bind(getItem(position) as RecipeListItem.CategoryItem) is CookbookViewHolder.RecipeHolder -> holder.bind(getItem(position) as RecipeListItem.RecipeItem) diff --git a/app/src/main/kotlin/ru/otus/cookbook/ui/RecipeFragment.kt b/app/src/main/kotlin/ru/otus/cookbook/ui/RecipeFragment.kt index d882f5b..969cf74 100644 --- a/app/src/main/kotlin/ru/otus/cookbook/ui/RecipeFragment.kt +++ b/app/src/main/kotlin/ru/otus/cookbook/ui/RecipeFragment.kt @@ -1,7 +1,6 @@ package ru.otus.cookbook.ui import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -79,7 +78,7 @@ class RecipeFragment : Fragment() { R.id.delete_recipe -> { val navController = findNavController() val action = RecipeFragmentDirections.actionRecipeToDialogDelete(getTitle()) - findNavController().navigate(action) + navController.navigate(action) true } diff --git a/app/src/main/res/drawable/category_xxx_width.xml b/app/src/main/res/drawable/category_xxx_width.xml index ab6455e..0aa162e 100644 --- a/app/src/main/res/drawable/category_xxx_width.xml +++ b/app/src/main/res/drawable/category_xxx_width.xml @@ -1,6 +1,6 @@ \ 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 b4327a3..5dd3a94 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,7 +2,7 @@ Cookbook Cookbook Recipe name placeholder - A recipe image + A recipe image Recipe Description placeholder Recipe steps Lorem ipsum Quisque blandit dolor vel ullamcorper fringilla. Etiam ut ultricies nibh. Maecenas sit amet ipsum at felis convallis luctus. Praesent at urna ac massa eleifend iaculis. Donec at venenatis metus. Donec malesuada sapien eget neque finibus, vel aliquam mi lacinia. Mauris a sem elementum, pretium diam nec, luctus neque. Praesent lacinia imperdiet erat, eget feugiat mi feugiat ut. Proin iaculis, massa eu lacinia tempor, dui lacus pellentesque dui, ut dapibus tellus purus at augue. Nam sagittis lobortis justo vel porta. Proin vel vulputate quam. Vivamus at vestibulum est. Phasellus a arcu lacus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nullam elit mauris, pharetra vitae libero sit amet, efficitur rhoncus mauris. Category placeholder @@ -13,5 +13,6 @@ Yes No C + delete \ No newline at end of file From 5060b62cf4dd45eb467b01ce86b6de9e28c26a5f Mon Sep 17 00:00:00 2001 From: Anv0l Date: Sat, 3 May 2025 16:07:01 +0300 Subject: [PATCH 5/5] =?UTF-8?q?=D0=92=D1=8B=D0=BD=D0=B5=D1=81=20=D1=87?= =?UTF-8?q?=D0=B0=D1=81=D1=82=D1=8C=20=D0=BE=D1=84=D0=BE=D1=80=D0=BC=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B2=20=D1=81=D1=82=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/res/layout/vh_recipe_category.xml | 1 + app/src/main/res/layout/vh_recipe_item.xml | 28 +++++---------- app/src/main/res/navigation/nav_graph.xml | 6 ++-- app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/dimens.xml | 5 +++ app/src/main/res/values/strings.xml | 1 + app/src/main/res/values/styles.xml | 36 +++++++++++++++++++ 7 files changed, 56 insertions(+), 22 deletions(-) create mode 100644 app/src/main/res/values/styles.xml diff --git a/app/src/main/res/layout/vh_recipe_category.xml b/app/src/main/res/layout/vh_recipe_category.xml index e1d6830..becf3f4 100644 --- a/app/src/main/res/layout/vh_recipe_category.xml +++ b/app/src/main/res/layout/vh_recipe_category.xml @@ -9,6 +9,7 @@ android:id="@+id/txt_category_name" android:layout_width="match_parent" android:layout_height="wrap_content" + android:textColor="@color/color_on_primary_container" android:text="@string/category_placeholder" android:textSize="@dimen/category_name" app:layout_constraintLeft_toLeftOf="parent" diff --git a/app/src/main/res/layout/vh_recipe_item.xml b/app/src/main/res/layout/vh_recipe_item.xml index 6dcb2bb..53ad9a1 100644 --- a/app/src/main/res/layout/vh_recipe_item.xml +++ b/app/src/main/res/layout/vh_recipe_item.xml @@ -18,8 +18,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintRight_toRightOf="parent" - - app:layout_constraintTop_toTopOf="parent"> diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 8d73d35..0905028 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -6,7 +6,6 @@ app:startDestination="@id/fragment_cookbook"> + app:exitAnim="@anim/slide_out_left" + app:popEnterAnim="@anim/slide_in_left" + + /> #DADCE0 #F3EDF7 + #4F378A \ 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 f189e6f..9bb1026 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -8,4 +8,9 @@ 80dp 40dp 16sp + 10dp + 16sp + 10dp + 5dp + 5dp \ 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 5dd3a94..3f93997 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -14,5 +14,6 @@ No C delete + monospace \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..3110cc2 --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + \ No newline at end of file