Add linked ingredients to recipe step (#177)

* Add Compose to app module

* Move Theme to ui module

* Add Coil image loader

* Use Compose for recipe screen

* Save instruction to ingredient relation to DB

* Display ingredients as server formats them

* Display linked ingredients under each step

* Fix ingredients padding

* Show recipe full screen

* Fix recipe screen UI issues

* Hide keyboard on recipe navigation

* Fix loading recipes from DB with no instructions or ingredients

* Add instructions section title

* Add ingredients section title

* Remove unused view holders
This commit is contained in:
Kirill Kamakin
2023-11-07 20:47:01 +01:00
committed by GitHub
parent 5ed1acb678
commit 941d45328e
46 changed files with 797 additions and 730 deletions

View File

@@ -1,144 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView 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:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true"
tools:context=".ui.recipes.info.RecipeInfoFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/end_guide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintGuide_end="4dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/start_guide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintGuide_begin="4dp"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/image"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="@string/content_description_fragment_recipe_info_image"
android:scaleType="centerCrop"
app:layout_constraintBottom_toTopOf="@id/title"
app:layout_constraintDimensionRatio="2:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearance="?shapeAppearanceCornerMedium"
tools:srcCompat="@drawable/placeholder_recipe" />
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/margin_small"
android:layout_marginTop="7dp"
android:textAppearance="?textAppearanceHeadline6"
app:layout_constraintBottom_toTopOf="@id/description"
app:layout_constraintEnd_toStartOf="@id/end_guide"
app:layout_constraintStart_toEndOf="@id/start_guide"
app:layout_constraintTop_toBottomOf="@id/image"
tools:text="Best-Ever Beef Stew" />
<TextView
android:id="@+id/description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/margin_small"
android:layout_marginTop="6dp"
android:textAppearance="?textAppearanceBody2"
app:layout_constraintBottom_toTopOf="@id/ingredients_header"
app:layout_constraintEnd_toStartOf="@id/end_guide"
app:layout_constraintStart_toEndOf="@id/start_guide"
app:layout_constraintTop_toBottomOf="@id/title"
tools:text="Stay warm all winter with this classic Beef Stew made with red wine and beef stock from Delish.com." />
<TextView
android:id="@+id/ingredients_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="35dp"
android:layout_marginTop="@dimen/margin_medium"
android:layout_marginEnd="@dimen/margin_small"
android:text="@string/fragment_recipe_info_ingredients_header"
android:textAppearance="?textAppearanceHeadline6"
app:layout_constraintBottom_toTopOf="@id/ingredients_holder"
app:layout_constraintEnd_toStartOf="@id/end_guide"
app:layout_constraintStart_toEndOf="@id/start_guide"
app:layout_constraintTop_toBottomOf="@id/description" />
<com.google.android.material.card.MaterialCardView
android:id="@+id/ingredients_holder"
style="?materialCardViewFilledStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/margin_small"
android:layout_marginTop="11dp"
android:layout_marginBottom="20dp"
app:layout_constraintBottom_toTopOf="@id/instructions_header"
app:layout_constraintEnd_toStartOf="@id/end_guide"
app:layout_constraintStart_toEndOf="@id/start_guide"
app:layout_constraintTop_toBottomOf="@id/ingredients_header">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/ingredients_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/margin_small"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="3"
tools:listitem="@layout/view_holder_ingredient" />
</com.google.android.material.card.MaterialCardView>
<androidx.constraintlayout.widget.Group
android:id="@+id/instructions_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="instructions_header,instructions_list" />
<TextView
android:id="@+id/instructions_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="35dp"
android:layout_marginEnd="@dimen/margin_small"
android:text="@string/fragment_recipe_info_instructions_header"
android:textAppearance="?textAppearanceHeadline6"
app:layout_constraintBottom_toTopOf="@id/instructions_list"
app:layout_constraintEnd_toStartOf="@id/end_guide"
app:layout_constraintStart_toEndOf="@id/start_guide"
app:layout_constraintTop_toBottomOf="@id/ingredients_holder" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/instructions_list"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/end_guide"
app:layout_constraintStart_toEndOf="@id/start_guide"
app:layout_constraintTop_toBottomOf="@id/instructions_header"
tools:itemCount="2"
tools:listitem="@layout/view_holder_instruction" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

View File

@@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.Group
android:id="@+id/section_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="title, title_divider"
tools:visibility="visible" />
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/margin_small"
android:textAppearance="?textAppearanceHeadline6"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Meat a very long and weird title that someone might have for some reason" />
<View
android:id="@+id/title_divider"
android:layout_width="0dp"
android:layout_height="1dp"
android:alpha="0.3"
android:background="?colorOnSurface"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/title" />
<CheckBox
android:id="@+id/checkBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/title_divider"
tools:text="900 g braising steak/stew meat, cubed into 2.5cm pieces" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView 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"
style="?materialCardViewFilledStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_small">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="18dp"
android:paddingVertical="12dp">
<TextView
android:id="@+id/step"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textAppearance="?textAppearanceHeadline6"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Step: 1" />
<TextView
android:id="@+id/instruction"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:textAppearance="?textAppearanceBody2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/step"
tools:text="In a large dutch oven or heavy-bottomed pot over medium heat, heat oil. Add beef and cook until seared on all sides, 10 minutes, working in batches if necessary. Transfer beef to a plate." />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>

View File

@@ -1,94 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation 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/nav_graph"
tools:ignore="InvalidNavigation">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nav_graph"
tools:ignore="InvalidNavigation">
<fragment
android:id="@+id/authenticationFragment"
android:name="gq.kirmanak.mealient.ui.auth.AuthenticationFragment"
android:label="AuthenticationFragment"
tools:layout="@layout/fragment_authentication" />
<fragment
android:id="@+id/authenticationFragment"
android:name="gq.kirmanak.mealient.ui.auth.AuthenticationFragment"
android:label="AuthenticationFragment"
tools:layout="@layout/fragment_authentication" />
<fragment
android:id="@+id/recipesListFragment"
android:name="gq.kirmanak.mealient.ui.recipes.RecipesListFragment"
android:label="fragment_recipes"
tools:layout="@layout/fragment_recipes_list">
<action
android:id="@+id/action_recipesFragment_to_recipeInfoFragment"
app:destination="@id/recipeInfoFragment" />
</fragment>
<fragment
android:id="@+id/recipesListFragment"
android:name="gq.kirmanak.mealient.ui.recipes.RecipesListFragment"
android:label="fragment_recipes"
tools:layout="@layout/fragment_recipes_list">
<action
android:id="@+id/action_recipesFragment_to_recipeInfoFragment"
app:destination="@id/recipeInfoFragment"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
</fragment>
<dialog
android:id="@+id/recipeInfoFragment"
android:name="gq.kirmanak.mealient.ui.recipes.info.RecipeInfoFragment"
android:label="RecipeInfoFragment"
tools:layout="@layout/fragment_recipe_info">
<argument
android:name="recipe_id"
app:argType="string" />
</dialog>
<fragment
android:id="@+id/recipeInfoFragment"
android:name="gq.kirmanak.mealient.ui.recipes.info.RecipeInfoFragment"
android:label="RecipeInfoFragment">
<argument
android:name="recipe_id"
app:argType="string" />
</fragment>
<fragment
android:id="@+id/disclaimerFragment"
android:name="gq.kirmanak.mealient.ui.disclaimer.DisclaimerFragment"
android:label="DisclaimerFragment"
tools:layout="@layout/fragment_disclaimer">
<action
android:id="@+id/action_disclaimerFragment_to_baseURLFragment"
app:destination="@id/baseURLFragment"
app:popUpTo="@id/nav_graph"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/disclaimerFragment"
android:name="gq.kirmanak.mealient.ui.disclaimer.DisclaimerFragment"
android:label="DisclaimerFragment"
tools:layout="@layout/fragment_disclaimer">
<action
android:id="@+id/action_disclaimerFragment_to_baseURLFragment"
app:destination="@id/baseURLFragment"
app:popUpTo="@id/nav_graph"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/baseURLFragment"
android:name="gq.kirmanak.mealient.ui.baseurl.BaseURLFragment"
android:label="fragment_base_url"
tools:layout="@layout/fragment_base_url">
<action
android:id="@+id/action_baseURLFragment_to_recipesListFragment"
app:destination="@id/recipesListFragment"
app:popUpTo="@id/nav_graph" />
<argument
android:name="isOnboarding"
app:argType="boolean" />
</fragment>
<fragment
android:id="@+id/baseURLFragment"
android:name="gq.kirmanak.mealient.ui.baseurl.BaseURLFragment"
android:label="fragment_base_url"
tools:layout="@layout/fragment_base_url">
<action
android:id="@+id/action_baseURLFragment_to_recipesListFragment"
app:destination="@id/recipesListFragment"
app:popUpTo="@id/nav_graph" />
<argument
android:name="isOnboarding"
app:argType="boolean" />
</fragment>
<fragment
android:id="@+id/addRecipeFragment"
android:name="gq.kirmanak.mealient.ui.add.AddRecipeFragment"
android:label="fragment_add_recipe"
tools:layout="@layout/fragment_add_recipe" />
<fragment
android:id="@+id/addRecipeFragment"
android:name="gq.kirmanak.mealient.ui.add.AddRecipeFragment"
android:label="fragment_add_recipe"
tools:layout="@layout/fragment_add_recipe" />
<fragment
android:id="@+id/shoppingListsFragment"
android:name="gq.kirmanak.mealient.shopping_lists.ui.ShoppingListsFragment" />
<fragment
android:id="@+id/shoppingListsFragment"
android:name="gq.kirmanak.mealient.shopping_lists.ui.ShoppingListsFragment" />
<action
android:id="@+id/action_global_authenticationFragment"
app:destination="@id/authenticationFragment" />
<action
android:id="@+id/action_global_authenticationFragment"
app:destination="@id/authenticationFragment" />
<action
android:id="@+id/action_global_recipesListFragment"
app:destination="@id/recipesListFragment"
app:popUpTo="@id/nav_graph" />
<action
android:id="@+id/action_global_recipesListFragment"
app:destination="@id/recipesListFragment"
app:popUpTo="@id/nav_graph" />
<action
android:id="@+id/action_global_addRecipeFragment"
app:destination="@id/addRecipeFragment"
app:popUpTo="@id/recipesListFragment" />
<action
android:id="@+id/action_global_addRecipeFragment"
app:destination="@id/addRecipeFragment"
app:popUpTo="@id/recipesListFragment" />
<action
android:id="@+id/action_global_baseURLFragment"
app:destination="@id/baseURLFragment"
app:popUpTo="@id/recipesListFragment" />
<action
android:id="@+id/action_global_baseURLFragment"
app:destination="@id/baseURLFragment"
app:popUpTo="@id/recipesListFragment" />
<action
android:id="@+id/action_global_shoppingListsFragment"
app:destination="@id/shoppingListsFragment"
app:popUpTo="@id/recipesListFragment" />
<action
android:id="@+id/action_global_shoppingListsFragment"
app:destination="@id/shoppingListsFragment"
app:popUpTo="@id/recipesListFragment" />
</navigation>