Code

Recipe Book - पाककृती पुस्तक is a native Android application

Recipe Book - पाककृती पुस्तक is a native Android application

Recipebook Documentation

This is a documentation for recipebook app created by WebsiteMan. Recipebook is a native Android application. You can find here useful info about configuring, customizing, building and publishing the app.

Features

  • Support for Ice Cream Sandwich (Android 4.0.3) and newer
  • Developed with Android Studio & Gradle
  • Material design following Android Design Guidelines
  • Eight color themes (blue, brown, carrot, gray, green, indigo, red, yellow)
  • Animations and effects
  • Animated action bar
  • Animated floating action button
  • Parallax scrolling effect
  • Quick return effect
  • Ripple effect
  • Navigation drawer menu with categories
  • List of recipes
  • Search for recipe with suggestion
  • Favorite recipes
  • Recipe detail screen (intro, ingredients, instruction)
  • Ingredients check list
  • Share recipe or shopping list
  • Open web link of the recipe
  • Kitchen timer
  • Recalculate quantity of ingredients by servings
  • Convert calories to joules
  • About dialog
  • Rate app on Google Play
  • Data (categories, recipes, ingredients) is stored in local SQLite database
  • Images can be loaded from the Internet or locally
  • Caching images
  • App works in offline mode
  • Google Analytics
  • AdMob
  • Responsive design and tablet support (portrait, landscape, handling orientation change)
  • Support for high-resolution displays (xxhdpi)
  • Multi-language support
  • Possibility to build the project without Android Studio / Eclipse (using Gradle & Android SDK)
  • Easy configuration
  • Well documented
  • Top quality clean code created by experienced senior Android developer
  • Free support

Android SDK & Android Studio

This chapter describes how to install Android SDK and Android Studio. You don’t have to install Android Studio, but it’s better. The project can be built without Android Studio, using Gradle and Android SDK. Gradle is a build system used for building final APK file.

  1. Install Java JDK
  2. Install Android SDK
  3. Run Android SDK Manager and download necessary SDK packages, make sure that you have installed Android SDK Tools, Android SDK Platform-tools, Android SDK Build-tools, Android Support Repository, Android Support Library and Google Play services
  4. Install Android Studio
  5. Now you should be able to open/edit the Android project and build APK
  6. You can also install Genymotion – fast Android emulator

Project structure

Project has the following structure (directories are marked by square braces):

  • [doc] – documentation
  • [extras] – contains extras
  • [extras]/[keystore]
  • [extras]/[keystore]/recipebook.keystore – keystore certificate for signing APK
  • [extras]/[keystore]/recipebook.properties – alias and password for keystore
  • [gradle]
  • [gradle]/[wrapper] – Gradle Wrapper
  • [mobile] – main module
  • [mobile]/[libs] – contains 3rd party libraries (not used)
  • [mobile]/[src] – contains source code
  • [mobile]/[src]/[main]
  • [mobile]/[src]/[main]/[assets] – asset files (prepopulated database, images)
  • [mobile]/[src]/[main]/[java] – java sources
  • [mobile]/[src]/[main]/[res] – xml resources, drawables
  • [mobile]/[src]/[main]/AndroidManifest.xml – manifest file
  • [mobile]/build.gradle – main build script
  • [mobile]/proguard-rules.pro – Proguard config (not used)
  • .gitignore – Gitignore file
  • build.gradle – parent build script
  • gradle.properties – build script properties containing path to keystore
  • gradlew – Gradle Wrapper (Unix)
  • gradlew.bat – Gradle Wrapper (Windows)
  • README.md – readme file
  • settings.gradle – build settings containing list of modules

Java packages:

  • com.websiteman.recipebook – contains application class and main config class
  • com.websiteman.recipebook.activity – contains activities representing screens
  • com.websiteman.recipebook.adapter – contains all adapters
  • com.websiteman.recipebook.content – contains content provider for search suggestions
  • com.websiteman.recipebook.database – contains database helper and tools for managing asynchronous database calls
  • com.websiteman.recipebook.database.dao – database access objects
  • com.websiteman.recipebook.database.data – data model wrapper
  • com.websiteman.recipebook.database.model – database models representing SQL tables
  • com.websiteman.recipebook.database.query – database queries
  • com.websiteman.recipebook.dialog – contains dialogs
  • com.websiteman.recipebook.fragment – contains fragments with main application logic
  • com.websiteman.recipebook.listener – contains listeners
  • com.websiteman.recipebook.utility – contains utilities
  • com.websiteman.recipebook.view – contains custom views, layouts, decorations and other tools for working with views

Configuration

This chapter describes how to configure the project to be ready for publishing. All these steps are very important!

1. Import

Unzip the package and import/open the project in Android Studio. Choose “Import project” on Quick Start screen and select “recipebook-x.y.z” directory.

2. Rename package name

  1. Create new package in java directory, e.g. “com.mycompany.myapp”. Right click on mobile/src/main/java directory -> New -> Package.
  2. Select all packages and classes in “com.websiteman.recipebook” and move (drag) them to the new package. Confirm by click on “Do Refactor”.
  3. Delete the old package “com.websiteman.recipebook”.
  4. Open mobile/src/main/AndroidManifest.xml and rename the package name. Select package name “com.websiteman.recipebook” -> Right click on selected text -> Refactor -> Rename -> enter the new package name, select “Search in comments and strings” option -> Refactor -> Do Refactor.
  5. Clean the project. Main menu -> Build -> Clean Project.
  6. Replace all occurrences of “com.websiteman.recipebook” for a new package name, e.g. “com.mycompany.myapp”. Right click on mobile directory -> Replace in Path -> set old and new package names, Case sensitive to true -> Find -> Replace.
  7. Clean the project again. Main menu -> Build -> Clean Project.
  8. Synchronize the project. Main menu -> Tools -> Android -> Sync Project with Gradle Files.
  9. If you see “Activity class does not exist” error, restart Android Studio.

3. Rename application name

Open mobile/src/main/res/values/strings.xml and change “recipebook” to your own name. Change app_name and drawer_title strings.

4. Create launcher icon

Right click on mobile/src/main/res directory -> New -> Image Asset -> Asset type Launcher Icons, Resource name “ic_launcher”, create the icon -> Next -> Finish.

You can also change the icon replacing ic_launcher.png file in mipmap-mdpi, mipmap-hdpi, mipmap-xhdpi, mipmap-xxhdpi, mipmap-xxxhdpi directories. See Android Cheatsheet for Graphic Designers for correct launcher icon dimensions.

Another possibility is to create launcher icons using Android Asset Studio.

5. Choose color theme

Open mobile/src/main/AndroidManifest.xml and change value of application.android:theme attribute. There are 8 themes you can use:

  • Theme.recipebook.Blue
  • Theme.recipebook.Brown
  • Theme.recipebook.Carrot
  • Theme.recipebook.Gray
  • Theme.recipebook.Green
  • Theme.recipebook.Indigo
  • Theme.recipebook.Red
  • Theme.recipebook.Yellow

You also have to modify MainActivity’s theme. Main Activity uses a special theme with transparent status bar because of navigation drawer status overlay effect. It is an activity.android:theme attribute. Choose one of these themes:

  • Theme.recipebook.TransparentStatusBar.Blue
  • Theme.recipebook.TransparentStatusBar.Brown
  • Theme.recipebook.TransparentStatusBar.Carrot
  • Theme.recipebook.TransparentStatusBar.Gray
  • Theme.recipebook.TransparentStatusBar.Green
  • Theme.recipebook.TransparentStatusBar.Indigo
  • Theme.recipebook.TransparentStatusBar.Red
  • Theme.recipebook.TransparentStatusBar.Yellow

6. Prepare database and images

Data (categories, recipes, ingredients) is stored in local SQLite database. Prepopulated database with recipes is stored in mobile/src/main/assets/recipebook.db. This prepopulated database is automatically copied on device storage on first run of the application and also if the database is updated (see below for more info about database update). Database is in SQLite 3.0 format and has the following structure (SQL script):

<span class="hljs-operator"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`categories`</span> (<span class="hljs-string">`id`</span> <span class="hljs-built_in">INTEGER</span> <span class="hljs-keyword">PRIMARY</span> <span class="hljs-keyword">KEY</span> AUTOINCREMENT , <span class="hljs-string">`name`</span> <span class="hljs-built_in">VARCHAR</span> , <span class="hljs-string">`image`</span> <span class="hljs-built_in">VARCHAR</span> );</span>
<span class="hljs-operator"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`recipes`</span> (<span class="hljs-string">`id`</span> <span class="hljs-built_in">INTEGER</span> <span class="hljs-keyword">PRIMARY</span> <span class="hljs-keyword">KEY</span> AUTOINCREMENT , <span class="hljs-string">`category_id`</span> <span class="hljs-built_in">BIGINT</span> , <span class="hljs-string">`name`</span> <span class="hljs-built_in">VARCHAR</span> , <span class="hljs-string">`intro`</span> <span class="hljs-built_in">VARCHAR</span> , <span class="hljs-string">`instruction`</span> <span class="hljs-built_in">VARCHAR</span> , <span class="hljs-string">`image`</span> <span class="hljs-built_in">VARCHAR</span> , <span class="hljs-string">`link`</span> <span class="hljs-built_in">VARCHAR</span> , <span class="hljs-string">`time`</span> <span class="hljs-built_in">INTEGER</span> , <span class="hljs-string">`servings`</span> <span class="hljs-built_in">INTEGER</span> , <span class="hljs-string">`calories`</span> <span class="hljs-built_in">INTEGER</span> , <span class="hljs-string">`favorite`</span> <span class="hljs-built_in">SMALLINT</span> );</span>
<span class="hljs-operator"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">INDEX</span> <span class="hljs-string">`recipes_category_idx`</span> <span class="hljs-keyword">ON</span> <span class="hljs-string">`recipes`</span> ( <span class="hljs-string">`category_id`</span> );</span>
<span class="hljs-operator"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`ingredients`</span> (<span class="hljs-string">`id`</span> <span class="hljs-built_in">INTEGER</span> <span class="hljs-keyword">PRIMARY</span> <span class="hljs-keyword">KEY</span> AUTOINCREMENT , <span class="hljs-string">`recipe_id`</span> <span class="hljs-built_in">BIGINT</span> , <span class="hljs-string">`name`</span> <span class="hljs-built_in">VARCHAR</span> , <span class="hljs-string">`quantity`</span> <span class="hljs-built_in">FLOAT</span> , <span class="hljs-string">`unit`</span> <span class="hljs-built_in">VARCHAR</span> );</span>
<span class="hljs-operator"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">INDEX</span> <span class="hljs-string">`ingredients_recipe_idx`</span> <span class="hljs-keyword">ON</span> <span class="hljs-string">`ingredients`</span> ( <span class="hljs-string">`recipe_id`</span> );</span>

As you can see, there are 3 SQL tables (categories, recipes, ingredients) and 2 indexes (category_id, recipe_id) which are also foreign keys. This database schema corresponds to database models in the code. You can find models in com.websiteman.recipebook.database.model package.

This app contains a prepopulated database with demo data. Open database file mobile/src/main/assets/recipebook.db in any SQLite editor and modify data in the database as you need. You can add/remove/edit recipes, categories and ingredients. There are many SQLite editors. We recommend SQLite Studio because it is free, open source, cross-platform, portable and intuitive. If you are working with SQLite Studio, don’t forget to commit changes. Don’t modify structure of the database, modify only data! Database tables have following columns:

categories:

  • id (integer) – Unique primary key
  • name (string) – Category name
  • image (string) – URL of the category image. This field is optional and if it is empty or null, no category image is shown. URL should be in this format: assets://categories/mycategory.png. It points to mobile/src/main/assets/categories folder where all category images should be stored.

recipes:

  • id (integer) – Unique primary key
  • category_id (integer) – Foreign key pointing to category id
  • name (string) – Recipe name
  • intro (string) – Introduction text on recipe detail screen. This field is optional and if it is empty or null, no text is shown.
  • instruction (string) – Main instruction text for the recipe
  • image (string) – URL of the recipe image. Image can be loaded from the Internet (URL with standard HTTP protocol) or locally from assets. Local URL should be in this format: assets://recipes/myrecipe.jpg. It points to mobile/src/main/assets/recipes folder where all local recipe images should be stored.
  • link (string) – URL of the web page. This field is optional and if it is empty or null, no web link is shown in the menu.
  • time (integer) – Cooking time in minutes. This field is optional and if it is empty or null, no time is shown.
  • servings (integer) – Number of servings. This field is optional and if it is empty or null, no servings info is shown.
  • calories (integer) – Number of calories in kcal for 100 g of serving. This field is optional and if it is empty or null, no calories info is shown.
  • favorite (boolean) – True/false value if the recipe is favorite. This field should stay 0 by default. This is the only column modified by the app. All other columns are read only.

ingredients:

  • id (integer) – Unique primary key
  • recipe_id (integer) – Foreign key pointing to recipe id
  • name (string) – Ingredient name
  • quantity (float) – Quantity of the ingredient. This field is optional and if it is empty or null, no quantity is shown.
  • unit (string) – Physical unit of the quantity. This field is optional and if it is empty or null, no unit is shown.

There are two special categories: “All recipes” and “Favorites”. Keep in mind that these categories are automatically added to the menu and does not have to be in the database. Categories are ordered by id, recipes are ordered alphabetically by name and ingredients are ordered by id. Search query is looking for a match in name, intro and instruction fields. Searching is case insensitive.

If you modify prepopulated database in assets folder, internal database on device storage will not be updated automatically. If you make any change in the prepopulated database, you have to increment database version. Open configuration file /mobile/src/main/java/com/robotemplates/recipebook/recipebookConfig.java and increment number in DATABASE_VERSION constant. Database helper detects that database data has been changed and copy the prepopulated database on device storage so data in the app will be updated. You have to increment database version every time when you want to publish a new build on Google Play and you have changed the data in prepopulated database.

Name of the prepopulated database is defined in configuration file /mobile/src/main/java/com/robotemplates/recipebook/recipebookConfig.java in DATABASE_NAME constant. Database file name should correspond to the file in mobile/src/main/assets directory. The database file should be stored in this directory and not in any sub-directory.

7. Setup Google Analytics

Open mobile/src/main/res/xml/analytics_app_tracker.xml and change UA code (ga_trackingId parameter) to your own UA code. You can enable/disable Google Analytics in configuration file /mobile/src/main/java/com/robotemplates/recipebook/recipebookConfig.java.

8. Setup AdMob

Open mobile/src/main/res/values/admob.xml and change unit ids (admob_unit_id_recipe_list and admob_unit_id_recipe_detail parameters) to your own unit ids (banner ids). You should also specify your test device id (admob_test_device_id parameter) and use test mode when debugging the app. Requesting test ads is recommended when testing your application so you do not request invalid impressions. You can find your hashed device id in the logcat output by requesting an ad when debugging on your device. You can enable/disable AdMob banners in configuration file /mobile/src/main/java/com/robotemplates/recipebook/recipebookConfig.java.

9. Create signing keystore

You need to create your own keystore to sign an APK file before publishing on Google Play. You can create the keystore via keytool utility which is part of Java JDK.

  1. Run following command: keytool -genkey -v -keystore recipebook.keystore -alias <your_alias> -keyalg RSA -keysize 2048 -validity 36500 where <your_alias> is your alias name. For example your company name or app name. If you are going to publish the app on Google Play, you have to set the validity attribute.
  2. Copy new recipebook.keystore file into extras/keystore directory.
  3. Open extras/keystore/recipebook.properties and set keystore alias and passwords.
  4. Done. Remember that recipebook.keystore and recipebook.properties are automatically read by Gradle script when creating a release APK via assembleRelease command. Paths to these files are defined in gradle.properties.

Customization

This chapter describes some optional customizations of the app.

Custom colors and icons

You can customize colors in mobile/src/main/res/values/colors.xml.

There are 11 category icons. If you need to create the icon for the category, it is recommended to use Android Asset Studio. See Android Cheatsheet for Graphic Designers for correct icon dimensions. Use the icons with highest DPI.

Custom banner logo in drawer menu

There is a green table cloth texture shown in the drawer menu. You can easily change this texture replacing banner.png file in drawable-xxhdpi directory.

About dialog

If you want to change the text in About dialog, just open mobile/src/main/res/values/strings.xml and edit dialog_about_message string. Note that this text is in HTML format and can also contains links.

Multi-language support

Create a new directory mobile/src/main/res/values-xx where xx is an ISO 639-1 code of the language you want to translate. For example “values-es” for Spanish, “values-fr” for French, “values-de” for German etc. Copy strings.xml from mobile/src/main/res/values into the new directory. Now you can translate texts for specific languages. The language is automatically determined by system device settings. If there is no match with values-xx language, default language in mobile/src/main/res/values is selected. See Localizing with Resources for more info.

Building & publishing

This chapter describes how to build APK with Gradle and prepare app for publishing. Android Studio uses Gradle for building Android applications.

You don’t need to install Gradle on your system, because there is a Gradle Wrapper. The wrapper is a batch script on Windows, and a shell script for other operating systems. When you start a Gradle build via the wrapper, Gradle will be automatically downloaded and used to run the build.

  1. Open the project in Android Studio
  2. Open configuration file /mobile/src/main/java/com/robotemplates/recipebook/recipebookConfig.java and set constants as required (see below for more info)
  3. Open main build script /mobile/build.gradle and set constants as required (see below for more info)
  4. Run gradlew assemble in console
  5. APK should be available in /mobile/build/outputs/apk directory

Note: You will also need a “local.properties” file to set the location of the SDK in the same way that the existing SDK requires, using the “sdk.dir” property. Example of “local.properties” on Windows: sdk.dir=C:\\adt-bundle-windows\\sdk. Alternatively, you can set an environment variable called “ANDROID_HOME”.

Tip: Command gradlew assemble builds both – debug and release APK. You can use gradlew assembleDebug to build debug APK. You can use gradlew assembleRelease to build release APK. Debug APK is signed by debug keystore. Release APK is signed by own keystore, stored in /extras/keystore directory.

Signing process: Keystore passwords are automatically loaded from property file during building the release APK. Path to this file is defined in “keystore.properties” property in “gradle.properties” file. If this property or the file does not exist, user is asked for passwords explicitly.

recipebookConfig.java

This is the main configuration file. There are some true/false switches. It is very important to correctly set these switches before building the APK.

  • LOGS – true for enabling debug logs
  • ANALYTICS – true for enabling Google Analytics
  • ADMOB_RECIPE_LIST_BANNER – true for enabling Google AdMob banner on recipe list screen
  • ADMOB_RECIPE_DETAIL_BANNER – true for enabling Google AdMob on recipe detail screen

Important: Following configuration should be used for release APK, intended for publishing on Google Play:

<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">boolean</span> LOGS = <span class="hljs-keyword">false</span>;
<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">boolean</span> ANALYTICS = <span class="hljs-keyword">true</span>;
<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">boolean</span> ADMOB_RECIPE_LIST_BANNER = <span class="hljs-keyword">true</span>;
<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">boolean</span> ADMOB_RECIPE_DETAIL_BANNER = <span class="hljs-keyword">true</span>;

build.gradle

This is the main build script and there are 4 important constants for defining version code and version name.

  • VERSION_MAJOR
  • VERSION_MINOR
  • VERSION_PATCH
  • VERSION_BUILD
by
by
by
by
by
by