Recent in Technology

Enhancing Your Recipe App: Adding Favorites and SQLite Integration

 Introduction:

A recipe app becomes truly invaluable when it offers users the ability to mark their favorite recipes for easy access. In this article, we'll guide you through the process of adding a "Favorites" button to each recipe item and integrating SQLite to manage and display the details of each favorite recipe.

This enhancement will create a more personalized and user-friendly experience for your app's users.



Adding the Favorites Button:

  1. Layout Modification: First, we'll modify the recipe item layout (recipe_item_layout.xml) to include a heart-shaped icon that serves as the "Favorites" button. We'll use an ImageView and customize it to be clickable.

  2. Setting Click Functionality: In the RecipeAdapter class, we'll set an OnClickListener for the "Favorites" button. When the button is clicked, we'll toggle the favorite status of the recipe item and update the UI accordingly.

SQLite Integration:

  1. SQLite Database Setup: We'll create an SQLite database to store information about favorite recipes. We'll define a contract class to manage the database schema, including table creation and deletion.

  2. Inserting and Deleting Favorites: In the RecipeAdapter, we'll implement methods to insert and delete recipes from the favorites database. When a recipe is marked as a favorite, its details will be added to the database, and when it's unmarked, its details will be removed.

  3. Displaying Favorite Recipes: To show the list of favorite recipes, we'll create a new activity (FavoritesActivity) and a corresponding layout (activity_favorites.xml). We'll use a RecyclerView to display the favorite recipes, and we'll fetch data from the favorites database to populate the list.

  4. Customizing the Favorites List: Similar to the main recipe list, we'll customize the layout of each item in the favorites list using a separate layout (favorite_item_layout.xml). This layout will display the recipe title, image, and other relevant details.

Connecting Favorites to Recipe Details:

  1. Passing Data to RecipeDetailsActivity: When a user clicks on a favorite recipe in the FavoritesActivity, we'll pass the recipe details (such as title, category, instructions, and ingredients) to the RecipeDetailsActivity.

  2. Displaying Recipe Details: In the RecipeDetailsActivity, we'll retrieve the passed recipe data and populate the UI elements (TextViews and ImageView) with the details of the selected recipe.

Conclusion:

By adding a "Favorites" button and integrating SQLite to manage favorite recipes, you've taken your recipe app to the next level. Users can now mark their preferred recipes and easily access them whenever they want. This enhancement not only enhances user engagement but also demonstrates your commitment to creating a feature-rich and user-friendly app. With the guidance provided in this article, you have the tools to implement these features and create a seamless and enjoyable cooking experience for your app's users.


Java code:

package com.peterc.kitchenwhiz;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class RecipeDetailsActivity extends AppCompatActivity {

private boolean isFavorite = false; // Track favorite status
private Recipe recipe; // The current recipe
private SQLiteDatabase favoritesDb;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recipe_details);

// Get the Recipe object from the intent
recipe = getIntent().getParcelableExtra("RECIPE");

// Set up the favorites database
FavoritesDbHelper dbHelper = new FavoritesDbHelper(this);
favoritesDb = dbHelper.getWritableDatabase();

// Set the toolbar as the action bar
androidx.appcompat.widget.Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

// Enable the back button in the action bar
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setTitle(recipe.getTitle());
}

// Display the recipe details
ImageView recipeImageView = findViewById(R.id.recipeImageView);
TextView cookingTimeTextView = findViewById(R.id.cookingTimeTextView);
TextView titleTextView = findViewById(R.id.recipeTitleTextView);
TextView categoryTextView = findViewById(R.id.categoryTextView);
TextView ingredientsTextView = findViewById(R.id.ingredientsTextView);
TextView instructionsTextView = findViewById(R.id.instructionsTextView);

recipeImageView.setImageResource(recipe.getImageResource());
cookingTimeTextView.setText(recipe.getCookingTime());
titleTextView.setText(recipe.getTitle());
categoryTextView.setText(android.text.TextUtils.join(", ", recipe.getCategories()));

String formattedIngredients = recipe.getIngredients().replace("\n", System.getProperty("line.separator"));
ingredientsTextView.setText(formattedIngredients);

instructionsTextView.setText(recipe.getInstructions());

// Add to Favorites Button
Button addToFavoritesButton = findViewById(R.id.addToFavoritesButton);
addToFavoritesButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
toggleFavoriteStatus();
}
});

// Check if the recipe is already in favorites
isFavorite = isRecipeInFavorites(recipe.getTitle());
updateFavoritesButtonText(addToFavoritesButton);
}

private void toggleFavoriteStatus() {
isFavorite = !isFavorite; // Toggle favorite status

// Update button text based on favorite status
updateFavoritesButtonText(findViewById(R.id.addToFavoritesButton));

// Add or remove recipe from favorites in the database
if (isFavorite) {
addToFavorites();
} else {
removeFromFavorites();
}
}

private void updateFavoritesButtonText(Button button) {
if (isFavorite) {
button.setText("Remove from Favorites");
} else {
button.setText("Add to Favorites");
}
}

private boolean isRecipeInFavorites(String recipeTitle) {
Cursor cursor = favoritesDb.rawQuery("SELECT * FROM " + FavoritesContract.FavoritesEntry.TABLE_NAME +
" WHERE " + FavoritesContract.FavoritesEntry.COLUMN_TITLE + " = ?", new String[]{recipeTitle});
boolean exists = cursor.getCount() > 0;
cursor.close();
return exists;
}

private void addToFavorites() {
ContentValues values = new ContentValues();
values.put(FavoritesContract.FavoritesEntry.COLUMN_TITLE, recipe.getTitle());
values.put(FavoritesContract.FavoritesEntry.COLUMN_CATEGORIES, TextUtils.join(",", recipe.getCategories()));
values.put(FavoritesContract.FavoritesEntry.COLUMN_IMAGE_URL, recipe.getImageResource());
values.put(FavoritesContract.FavoritesEntry.COLUMN_COOKING_TIME, recipe.getCookingTime());
values.put(FavoritesContract.FavoritesEntry.COLUMN_INGREDIENTS, recipe.getIngredients());
values.put(FavoritesContract.FavoritesEntry.COLUMN_INSTRUCTIONS, recipe.getInstructions());

long newRowId = favoritesDb.insert(FavoritesContract.FavoritesEntry.TABLE_NAME, null, values);
if (newRowId != -1) {
Toast.makeText(this, "Added to Favorites", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Failed to add to Favorites", Toast.LENGTH_SHORT).show();
}
}

private void removeFromFavorites() {
int deletedRows = favoritesDb.delete(FavoritesContract.FavoritesEntry.TABLE_NAME,
FavoritesContract.FavoritesEntry.COLUMN_TITLE + " = ?", new String[]{recipe.getTitle()});
if (deletedRows > 0) {
Toast.makeText(this, "Removed from Favorites", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Failed to remove from Favorites", Toast.LENGTH_SHORT).show();
}
}


@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
// Handle the back button click
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}

@Override
protected void onDestroy() {
super.onDestroy();
// Close the favorites database when the activity is destroyed
favoritesDb.close();
}
}

Let's break down the code step by step:

  1. RecipeDetailsActivity Class: This class is an AppCompatActivity that displays the details of a selected recipe. It includes features like adding the recipe to favorites, toggling the favorite status, and integrating with an SQLite database to manage favorite recipes.

  2. isFavorite and recipe: These variables are used to track whether the current recipe is a favorite and hold the data of the selected recipe, respectively.

  3. favoritesDb: An instance of the SQLiteDatabase class that will be used to interact with the SQLite database for managing favorite recipes.

  4. onCreate Method: This method is called when the activity is created. It sets up the layout, initializes UI elements, displays recipe details, and sets up the favorites database.

  5. Setting Up the Toolbar: The code initializes and customizes the toolbar at the top of the activity. It enables the back button and sets the title of the toolbar to the recipe's title.

  6. Displaying Recipe Details: The code retrieves the various UI elements (such as ImageView, TextViews) from the layout and populates them with details from the recipe object.

  7. addToFavoritesButton Click Listener: This listener is set on the "Add to Favorites" button. When clicked, it toggles the favorite status and calls the toggleFavoriteStatus method.

  8. toggleFavoriteStatus Method: This method toggles the favorite status, updates the button text, and either adds or removes the recipe from the favorites database based on the status.

  9. Database Operations (isRecipeInFavorites, addToFavorites, removeFromFavorites): These methods interact with the SQLite database. isRecipeInFavorites checks if the recipe is already in favorites, addToFavorites adds the recipe to favorites, and removeFromFavorites removes the recipe from favorites.

  10. onOptionsItemSelected Method: This method handles the action when the back button in the toolbar is clicked. It navigates back to the previous activity.

  11. onDestroy Method: This method is called when the activity is destroyed. It ensures that the favorites database is properly closed to prevent memory leaks.

Conclusion:

The RecipeDetailsActivity class is a critical component of your app, allowing users to view detailed information about a selected recipe and manage its favorite status. By integrating with an SQLite database, users can easily mark recipes as favorites and access them later. This code demonstrates a seamless flow between displaying recipe details, updating favorite status, and database interactions. With this functionality, your recipe app becomes even more engaging and user-friendly.


package com.peterc.kitchenwhiz;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class FavoritesDbHelper extends SQLiteOpenHelper {

private static final String DATABASE_NAME = "favorites.db";
private static final int DATABASE_VERSION = 1;

public FavoritesDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {
// Create the favorites table
db.execSQL(FavoritesContract.FavoritesEntry.SQL_CREATE_TABLE);
}


@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Handle database upgrade if needed
db.execSQL(FavoritesContract.FavoritesEntry.SQL_DELETE_TABLE);
onCreate(db);
}
}


This code defines a class named FavoritesDbHelper which is a subclass of SQLiteOpenHelper. It's used for managing the creation, upgrading, and opening of an SQLite database specifically for managing "favorites" in an Android application.

Let's break down the code step by step:

  1. Import Statements:

    • android.content.Context: This class provides access to the application's global information and resources.
    • android.database.sqlite.SQLiteDatabase: This class represents an SQLite database that can be used for performing database operations.
    • android.database.sqlite.SQLiteOpenHelper: This is the base class for managing database creation and version management.
  2. Class Definition:


    public class FavoritesDbHelper extends SQLiteOpenHelper {

    This class is defined as a subclass of SQLiteOpenHelper.

  3. Constants:


    private static final String DATABASE_NAME = "favorites.db"; private static final int DATABASE_VERSION = 1;

    These constants define the name of the database file (favorites.db) and the initial version number (1) for the database.

  4. Constructor:


    public FavoritesDbHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); }

    The constructor of FavoritesDbHelper takes a Context parameter (typically the application context) and uses it to call the constructor of the parent class (SQLiteOpenHelper) with the database name, null for the CursorFactory, and the specified database version.

  5. onCreate Method:


    @Override public void onCreate(SQLiteDatabase db) { // Create the favorites table db.execSQL(FavoritesContract.FavoritesEntry.SQL_CREATE_TABLE); }

    This method is overridden from SQLiteOpenHelper. It's called when the database needs to be created for the first time. Inside this method, an SQL query is executed (db.execSQL(...)) to create the "favorites" table. The SQL query is obtained from FavoritesContract.FavoritesEntry.SQL_CREATE_TABLE.

  6. onUpgrade Method:


    @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // Handle database upgrade if needed db.execSQL(FavoritesContract.FavoritesEntry.SQL_DELETE_TABLE); onCreate(db); }

    This method is also overridden from SQLiteOpenHelper. It's called when the database needs to be upgraded due to a change in database version. Inside this method:

    • The existing "favorites" table is deleted by executing the SQL query obtained from FavoritesContract.FavoritesEntry.SQL_DELETE_TABLE.
    • Then, the onCreate method is called to recreate the database using the new structure.

In summary, the FavoritesDbHelper class provides a structured way to manage the creation and upgrading of an SQLite database for managing "favorites" in an Android application. It uses an SQL schema defined in another class (FavoritesContract.FavoritesEntry) to create and delete the "favorites" table. This design pattern helps maintain a clean and organized database management process.


package com.peterc.kitchenwhiz;

import android.provider.BaseColumns;

public class FavoritesContract {

private FavoritesContract() {
// Prevent instantiation
}

public static class FavoritesEntry implements BaseColumns {
public static final String TABLE_NAME = "favorites";
public static final String COLUMN_TITLE = "title";
public static final String COLUMN_CATEGORIES = "categories";
public static final String COLUMN_IMAGE_URL = "image_url";
public static final String COLUMN_COOKING_TIME = "cooking_time";
public static final String COLUMN_INGREDIENTS = "ingredients";
public static final String COLUMN_INSTRUCTIONS = "instructions";

public static final String SQL_CREATE_TABLE =
"CREATE TABLE " + FavoritesEntry.TABLE_NAME + " (" +
FavoritesEntry._ID + " INTEGER PRIMARY KEY," +
FavoritesEntry.COLUMN_TITLE + " TEXT," +
FavoritesEntry.COLUMN_CATEGORIES + " TEXT," +
FavoritesEntry.COLUMN_IMAGE_URL + " TEXT," +
FavoritesEntry.COLUMN_COOKING_TIME + " TEXT," +
FavoritesEntry.COLUMN_INGREDIENTS + " TEXT," +
FavoritesEntry.COLUMN_INSTRUCTIONS + " TEXT" +
")";

public static final String SQL_DELETE_TABLE =
"DROP TABLE IF EXISTS " + TABLE_NAME;
}
}



This code defines a contract class named FavoritesContract that holds the contract details for managing a database table called "favorites" in an Android application. A contract class typically defines constants, column names, and SQL statements for database operations, helping to organize and centralize database-related information.

Let's go through the code step by step:

  1. Import Statement:

    • android.provider.BaseColumns: This interface provides constants that are commonly used when working with tables in an SQLite database.
  2. Class Definition:


    public class FavoritesContract {

    This class is defined to encapsulate the contract details for the "favorites" database table.

  3. Private Constructor:


    private FavoritesContract() { // Prevent instantiation }

    The private constructor prevents the instantiation of this contract class. It's a common pattern used for utility classes that should not be instantiated.

  4. Nested Class FavoritesEntry - Column and Table Definitions:


    public static class FavoritesEntry implements BaseColumns { public static final String TABLE_NAME = "favorites"; public static final String COLUMN_TITLE = "title"; public static final String COLUMN_CATEGORIES = "categories"; public static final String COLUMN_IMAGE_URL = "image_url"; public static final String COLUMN_COOKING_TIME = "cooking_time"; public static final String COLUMN_INGREDIENTS = "ingredients"; public static final String COLUMN_INSTRUCTIONS = "instructions";

    This nested class FavoritesEntry defines constants for the table name and column names of the "favorites" table. It also implements the BaseColumns interface, which automatically provides an _ID column required by Android's CursorAdapter classes.

  5. SQL Statements:


    public static final String SQL_CREATE_TABLE = "CREATE TABLE " + FavoritesEntry.TABLE_NAME + " (" + FavoritesEntry._ID + " INTEGER PRIMARY KEY," + FavoritesEntry.COLUMN_TITLE + " TEXT," + FavoritesEntry.COLUMN_CATEGORIES + " TEXT," + FavoritesEntry.COLUMN_IMAGE_URL + " TEXT," + FavoritesEntry.COLUMN_COOKING_TIME + " TEXT," + FavoritesEntry.COLUMN_INGREDIENTS + " TEXT," + FavoritesEntry.COLUMN_INSTRUCTIONS + " TEXT" + ")"; public static final String SQL_DELETE_TABLE = "DROP TABLE IF EXISTS " + TABLE_NAME;

    These constants define the SQL statements for creating and deleting the "favorites" table. The SQL_CREATE_TABLE statement defines the table schema, including column names, types, and constraints. The SQL_DELETE_TABLE statement drops the table if it exists.

In summary, the FavoritesContract class serves as a contract that defines the structure and operations for managing the "favorites" table in an SQLite database. It provides a clean and centralized way to manage constants and SQL statements related to the database, promoting better organization and maintainability of the database-related code.





Post a Comment

0 Comments