├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── bapspatil
│ │ └── captainchef
│ │ ├── adapters
│ │ ├── FoodItemsRecyclerViewAdapter.kt
│ │ ├── IngredientsRecyclerViewAdapter.kt
│ │ ├── MyRecyclerView.kt
│ │ └── StepsListRecyclerViewAdapter.kt
│ │ ├── model
│ │ ├── FoodItem.kt
│ │ ├── Ingredient.kt
│ │ └── RecipeStep.kt
│ │ ├── network
│ │ └── BakingAPI.kt
│ │ ├── sync
│ │ ├── RecipeWidgetProvider.kt
│ │ ├── RecipeWidgetRemoteViewsService.kt
│ │ └── UpdateRecipeService.kt
│ │ ├── ui
│ │ ├── FoodItemsActivity.kt
│ │ ├── RecipeActivity.kt
│ │ ├── RecipeDetailsActivity.kt
│ │ ├── SplashScreenActivity.kt
│ │ ├── StepsDetailsFragment.kt
│ │ └── StepsListFragment.kt
│ │ └── utils
│ │ ├── CaptainChefGlideModule.kt
│ │ └── EndlessScrollListener.kt
│ └── res
│ ├── drawable-nodpi
│ ├── fallback_recipe_thumbnail.png
│ ├── recipe_widget_preview.png
│ └── splash_screen_logo.png
│ ├── font
│ └── autour_one.ttf
│ ├── layout-land
│ └── fragment_steps_details.xml
│ ├── layout-sw600dp
│ ├── activity_food_items.xml
│ ├── activity_recipe.xml
│ ├── fragment_steps_details.xml
│ └── rv_food_item.xml
│ ├── layout
│ ├── activity_food_items.xml
│ ├── activity_recipe.xml
│ ├── activity_recipe_details.xml
│ ├── activity_splash_screen.xml
│ ├── fragment_steps_details.xml
│ ├── fragment_steps_list.xml
│ ├── recipe_widget_before_selection.xml
│ ├── recipe_widget_list_item_view.xml
│ ├── recipe_widget_provider.xml
│ ├── rv_food_item.xml
│ ├── rv_ingredients.xml
│ └── rv_steps_list.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── values-sw600dp
│ └── strings.xml
│ ├── values-v14
│ └── dimens.xml
│ ├── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
│ └── xml
│ └── recipe_widget_provider_info.xml
├── build.gradle
├── design
├── screen0.png
├── screen1.png
├── screen2.png
├── screen3.png
└── screen4.png
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── resources
├── baking.json
├── brownie.jpg
├── cheesecake.jpg
├── fallback_recipe_thumbnail.png
├── nutella_pie.jpg
└── yellow_cake.jpg
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | .DS_Store
5 | /build
6 | /captures
7 | .externalNativeBuild
8 | .idea
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # CaptainChef
3 |
4 | A Material design baking/cooking recipes app.
5 |
6 |
7 |
8 | ## Screenshots
9 |
10 |
11 |
12 |
13 |
14 | ## Libraries Used
15 |
16 | * [Android Support Library](https://developer.android.com/topic/libraries/support-library/)
17 | * [Anko](https://github.com/Kotlin/anko/)
18 | * [Retrofit](https://github.com/square/retrofit/)
19 | * [Glide](https://github.com/bumptech/glide/)
20 | * [Gson](https://github.com/google/gson/)
21 | * [Toasty](https://github.com/GrenderG/Toasty/)
22 | * [ExoPlayer](https://github.com/google/ExoPlayer/)
23 |
24 | ## Developed By
25 |
26 | Bapusaheb Patil
27 |
28 |
29 |
30 | https://bapspatil.com
31 |
32 | ## License
33 |
34 | Copyright 2018 Bapusaheb Patil
35 |
36 | Licensed under the Apache License, Version 2.0 (the "License");
37 | you may not use this file except in compliance with the License.
38 | You may obtain a copy of the License at
39 |
40 | http://www.apache.org/licenses/LICENSE-2.0
41 |
42 | Unless required by applicable law or agreed to in writing, software
43 | distributed under the License is distributed on an "AS IS" BASIS,
44 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
45 | See the License for the specific language governing permissions and
46 | limitations under the License.
47 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 | apply plugin: 'kotlin-kapt'
5 |
6 | android {
7 | compileSdkVersion 27
8 | buildToolsVersion "28.0.1"
9 | defaultConfig {
10 | applicationId "bapspatil.captainchef"
11 | minSdkVersion 21
12 | targetSdkVersion 27
13 | versionCode 3
14 | versionName "1.2"
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | compileOptions {
23 | sourceCompatibility JavaVersion.VERSION_1_8
24 | targetCompatibility JavaVersion.VERSION_1_8
25 | }
26 | }
27 |
28 | kotlin {
29 | experimental {
30 | coroutines "enable"
31 | }
32 | }
33 |
34 | androidExtensions {
35 | experimental = true
36 | }
37 |
38 | ext {
39 | ankoVersion = '0.10.5'
40 | support = '27.1.1'
41 | glideVersion = '4.7.1'
42 | exoplayerVersion = '2.8.2'
43 | toastyVersion = '1.3.0'
44 | retrofitVer = '2.4.0'
45 | gsonVer = '2.8.5'
46 | }
47 |
48 | dependencies {
49 | // Kotlin
50 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlinVer"
51 | implementation "org.jetbrains.anko:anko:$ankoVersion"
52 | implementation "org.jetbrains.anko:anko-design:$ankoVersion"
53 |
54 | // Android Support Library
55 | implementation "com.android.support:appcompat-v7:$support"
56 | implementation "com.android.support:support-v4:$support"
57 | implementation "com.android.support:support-v13:$support"
58 | implementation "com.android.support:support-annotations:$support"
59 | implementation "com.android.support:cardview-v7:$support"
60 | implementation "com.android.support:design:$support"
61 | implementation "com.android.support:recyclerview-v7:$support"
62 | implementation 'com.android.support.constraint:constraint-layout:1.0.2'
63 |
64 | // App dependencies
65 | implementation "com.github.bumptech.glide:glide:$glideVersion"
66 | kapt "com.github.bumptech.glide:compiler:$glideVersion"
67 | implementation "com.google.android.exoplayer:exoplayer:$exoplayerVersion"
68 | implementation "com.github.GrenderG:Toasty:$toastyVersion"
69 | implementation "com.squareup.retrofit2:retrofit:$retrofitVer"
70 | implementation "com.squareup.retrofit2:converter-gson:$retrofitVer"
71 | implementation "com.google.code.gson:gson:$gsonVer"
72 | }
73 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Users\bapoo\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 | -keep public class * implements com.bumptech.glide.module.GlideModule
27 | -keep public class * extends com.bumptech.glide.AppGlideModule
28 | -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
29 | **[] $VALUES;
30 | public *;
31 | }
32 |
33 | # For GSON and Retrofit
34 | -dontwarn okio.**
35 | -dontwarn javax.annotation.**
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
17 |
18 |
21 |
22 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
40 |
41 |
42 |
45 |
46 |
47 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/adapters/FoodItemsRecyclerViewAdapter.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.adapters
2 |
3 | import android.content.Context
4 | import android.support.v4.content.res.ResourcesCompat
5 | import android.support.v7.widget.RecyclerView
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import android.widget.ImageView
10 | import android.widget.TextView
11 | import bapspatil.captainchef.R
12 | import bapspatil.captainchef.model.FoodItem
13 | import bapspatil.captainchef.utils.GlideApp
14 | import butterknife.BindView
15 | import butterknife.ButterKnife
16 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
17 | import java.util.*
18 |
19 | /**
20 | * Created by bapspatil
21 | */
22 |
23 | class FoodItemsRecyclerViewAdapter(private val mContext: Context, private val mFoodItemsList: ArrayList, private val mClickListener: OnFoodItemClickListener?) : RecyclerView.Adapter() {
24 |
25 | override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): FoodItemsViewHolder {
26 | val view = LayoutInflater.from(mContext).inflate(R.layout.rv_food_item, viewGroup, false)
27 | return FoodItemsViewHolder(view)
28 | }
29 |
30 | override fun onBindViewHolder(holder: FoodItemsViewHolder, position: Int) {
31 | val typeface = ResourcesCompat.getFont(mContext, R.font.autour_one)
32 | holder.mFoodItemTextView!!.typeface = typeface
33 | holder.mFoodItemTextView!!.text = mFoodItemsList[position].foodName
34 | GlideApp.with(mContext)
35 | .load(mFoodItemsList[position].imageUrl)
36 | .centerCrop()
37 | .error(R.drawable.fallback_recipe_thumbnail)
38 | .fallback(R.drawable.fallback_recipe_thumbnail)
39 | .transition(DrawableTransitionOptions().crossFade())
40 | .into(holder.mFoodItemImageView!!)
41 | }
42 |
43 | override fun getItemCount(): Int {
44 | return mFoodItemsList.size
45 | }
46 |
47 | inner class FoodItemsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
48 | @BindView(R.id.food_item_tv)
49 | var mFoodItemTextView: TextView? = null
50 | @BindView(R.id.food_item_iv)
51 | var mFoodItemImageView: ImageView? = null
52 |
53 | init {
54 | ButterKnife.bind(this, itemView)
55 | itemView.setOnClickListener(this)
56 | }
57 |
58 | override fun onClick(v: View) {
59 | mClickListener?.onFoodItemClicked(adapterPosition, mFoodItemTextView)
60 | }
61 | }
62 |
63 | interface OnFoodItemClickListener {
64 | fun onFoodItemClicked(position: Int, textView: TextView?)
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/adapters/IngredientsRecyclerViewAdapter.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.adapters
2 |
3 | import android.content.Context
4 | import android.support.v4.content.res.ResourcesCompat
5 | import android.support.v7.widget.RecyclerView
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import android.widget.TextView
10 | import bapspatil.captainchef.R
11 | import bapspatil.captainchef.model.Ingredient
12 | import butterknife.BindView
13 | import butterknife.ButterKnife
14 | import java.util.*
15 |
16 | /**
17 | * Created by bapspatil
18 | */
19 |
20 | class IngredientsRecyclerViewAdapter(private val mContext: Context, private val mIngredientsList: ArrayList) : RecyclerView.Adapter() {
21 |
22 | override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): IngredientsViewHolder {
23 | val view = LayoutInflater.from(mContext).inflate(R.layout.rv_ingredients, viewGroup, false)
24 | return IngredientsViewHolder(view)
25 | }
26 |
27 | override fun onBindViewHolder(ingredientsViewHolder: IngredientsViewHolder, i: Int) {
28 | val (quant, measuredWith, ingredientName) = mIngredientsList[i]
29 | val typeface = ResourcesCompat.getFont(mContext, R.font.autour_one)
30 | ingredientsViewHolder.mIngredientTextView!!.typeface = typeface
31 | ingredientsViewHolder.mMeasureTextView!!.typeface = typeface
32 | ingredientsViewHolder.mQuantityTextView!!.typeface = typeface
33 | ingredientsViewHolder.mIngredientTextView!!.text = ingredientName
34 | ingredientsViewHolder.mQuantityTextView!!.text = quant.toString()
35 | ingredientsViewHolder.mMeasureTextView!!.text = measuredWith
36 | }
37 |
38 | override fun getItemCount(): Int {
39 | return mIngredientsList.size
40 | }
41 |
42 | inner class IngredientsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
43 | @BindView(R.id.ingredient_tv)
44 | var mIngredientTextView: TextView? = null
45 | @BindView(R.id.quantity_tv)
46 | var mQuantityTextView: TextView? = null
47 | @BindView(R.id.measure_tv)
48 | var mMeasureTextView: TextView? = null
49 |
50 | init {
51 | ButterKnife.bind(this, itemView)
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/adapters/MyRecyclerView.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.adapters
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.os.Parcelable
6 | import android.support.v7.widget.RecyclerView
7 | import android.util.AttributeSet
8 |
9 | /**
10 | * Created by bapspatil
11 | */
12 |
13 | class MyRecyclerView : RecyclerView {
14 | private var mLayoutManagerSavedState: Parcelable? = null
15 |
16 | constructor(context: Context) : super(context)
17 |
18 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
19 |
20 | constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle)
21 |
22 | override fun onSaveInstanceState(): Parcelable? {
23 | val bundle = Bundle()
24 | bundle.putParcelable(SAVED_SUPER_STATE, super.onSaveInstanceState())
25 | bundle.putParcelable(SAVED_LAYOUT_MANAGER, this.layoutManager.onSaveInstanceState())
26 | return bundle
27 | }
28 |
29 | override fun onRestoreInstanceState(state: Parcelable?) {
30 | var mState = state
31 | if (mState is Bundle) {
32 | val bundle = mState as Bundle?
33 | mLayoutManagerSavedState = bundle!!.getParcelable(SAVED_LAYOUT_MANAGER)
34 | mState = bundle.getParcelable(SAVED_SUPER_STATE)
35 | }
36 | super.onRestoreInstanceState(state)
37 | }
38 |
39 | override fun setAdapter(adapter: RecyclerView.Adapter<*>) {
40 | super.setAdapter(adapter)
41 | restorePosition()
42 | }
43 |
44 | /**
45 | * Restores scroll position after configuration change.
46 | * NOTE: Must be called after adapter has been set.
47 | */
48 | fun restorePosition() {
49 | if (mLayoutManagerSavedState != null) {
50 | this.layoutManager.onRestoreInstanceState(mLayoutManagerSavedState)
51 | mLayoutManagerSavedState = null
52 | }
53 | }
54 |
55 | companion object {
56 | private const val SAVED_SUPER_STATE = "super-state"
57 | private const val SAVED_LAYOUT_MANAGER = "layout-manager-state"
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/adapters/StepsListRecyclerViewAdapter.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.adapters
2 |
3 | import android.content.Context
4 | import android.support.v4.content.res.ResourcesCompat
5 | import android.support.v7.widget.RecyclerView
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import android.widget.ImageView
10 | import android.widget.TextView
11 | import bapspatil.captainchef.R
12 | import bapspatil.captainchef.model.RecipeStep
13 | import bapspatil.captainchef.utils.GlideApp
14 | import butterknife.BindView
15 | import butterknife.ButterKnife
16 | import java.util.*
17 |
18 | /**
19 | * Created by bapspatil
20 | */
21 |
22 | class StepsListRecyclerViewAdapter(private val mContext: Context, private val mRecipeStepsList: ArrayList, private val mClickListener: OnRecipeStepClickedListener?) : RecyclerView.Adapter() {
23 |
24 | override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): StepsListViewHolder {
25 | val view = LayoutInflater.from(mContext).inflate(R.layout.rv_steps_list, viewGroup, false)
26 | return StepsListViewHolder(view)
27 | }
28 |
29 | override fun onBindViewHolder(stepsListViewHolder: StepsListViewHolder, i: Int) {
30 | val (stepId, shortInfo, _, _, thumbnailUrl) = mRecipeStepsList[i]
31 | val recipeStepString = stepId.toString() + ". " + shortInfo
32 | val typeface = ResourcesCompat.getFont(mContext, R.font.autour_one)
33 | stepsListViewHolder.mStepTextView!!.typeface = typeface
34 | stepsListViewHolder.mStepTextView!!.text = recipeStepString
35 | GlideApp.with(mContext)
36 | .load(thumbnailUrl)
37 | .centerCrop()
38 | .fallback(R.drawable.fallback_recipe_thumbnail)
39 | .error(R.drawable.fallback_recipe_thumbnail)
40 | .placeholder(R.drawable.fallback_recipe_thumbnail)
41 | .into(stepsListViewHolder.mStepImageView!!)
42 | }
43 |
44 | override fun getItemCount(): Int {
45 | return mRecipeStepsList.size
46 | }
47 |
48 | inner class StepsListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
49 | @BindView(R.id.step_item_tv)
50 | var mStepTextView: TextView? = null
51 | @BindView(R.id.step_item_iv)
52 | var mStepImageView: ImageView? = null
53 |
54 | init {
55 | ButterKnife.bind(this, itemView)
56 | itemView.setOnClickListener(this)
57 | }
58 |
59 | override fun onClick(v: View) {
60 | if (mClickListener != null) {
61 | val recipeStep = mRecipeStepsList[adapterPosition]
62 | mClickListener.onRecipeStepClicked(recipeStep)
63 | }
64 | }
65 | }
66 |
67 | interface OnRecipeStepClickedListener {
68 | fun onRecipeStepClicked(recipeStep: RecipeStep)
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/model/FoodItem.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.model
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.android.parcel.Parcelize
6 | import java.util.*
7 |
8 | @Parcelize
9 | data class FoodItem(
10 | @SerializedName("id") var foodId: Int,
11 | @SerializedName("name") var foodName: String?,
12 | @SerializedName("image") var imageUrl: String?,
13 | @SerializedName("ingredients") var ingredients: ArrayList?,
14 | @SerializedName("steps") var steps: ArrayList?
15 | ) : Parcelable
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/model/Ingredient.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.model
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.android.parcel.Parcelize
6 |
7 | @Parcelize
8 | data class Ingredient(
9 | @SerializedName("quantity") var quant: Float,
10 | @SerializedName("measure") var measuredWith: String?,
11 | @SerializedName("ingredient") var ingredientName: String?
12 | ) : Parcelable
13 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/model/RecipeStep.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.model
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.android.parcel.Parcelize
6 |
7 | @Parcelize
8 | data class RecipeStep(
9 | @SerializedName("id") var stepId: Int,
10 | @SerializedName("shortDescription") var shortInfo: String?,
11 | @SerializedName("description") var info: String?,
12 | @SerializedName("videoURL") var videoUrl: String?,
13 | @SerializedName("thumbnailURL") var thumbnailUrl: String?
14 | ) : Parcelable
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/network/BakingAPI.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.network
2 |
3 | import bapspatil.captainchef.model.FoodItem
4 | import retrofit2.Call
5 | import retrofit2.Retrofit
6 | import retrofit2.converter.gson.GsonConverterFactory
7 | import retrofit2.http.GET
8 | import java.util.*
9 |
10 | /**
11 | * Created by bapspatil
12 | */
13 |
14 | interface BakingAPI {
15 |
16 | @get:GET("resources/baking.json")
17 | val foodItems: Call>
18 |
19 | companion object {
20 |
21 | const val BASE_URL = "https://raw.githubusercontent.com/bapspatil/CaptainChef/master/"
22 |
23 | val retrofit = Retrofit.Builder()
24 | .baseUrl(BASE_URL)
25 | .addConverterFactory(GsonConverterFactory.create())
26 | .build()
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/sync/RecipeWidgetProvider.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.sync
2 |
3 | import android.appwidget.AppWidgetManager
4 | import android.appwidget.AppWidgetProvider
5 | import android.content.ComponentName
6 | import android.content.Context
7 | import android.content.Intent
8 | import android.widget.RemoteViews
9 | import bapspatil.captainchef.R
10 | import bapspatil.captainchef.model.Ingredient
11 | import java.util.*
12 |
13 | /**
14 | * Created by bapspatil
15 | */
16 | class RecipeWidgetProvider : AppWidgetProvider() {
17 |
18 | override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
19 | /*for (int appWidgetId : appWidgetIds) {
20 | updateAppWidget(context, appWidgetManager, appWidgetId);
21 | }*/
22 | }
23 |
24 | override fun onEnabled(context: Context) {
25 | // Enter relevant functionality for when the first widget is created
26 | }
27 |
28 | override fun onDisabled(context: Context) {
29 | // Enter relevant functionality for when the last widget is disabled
30 | }
31 |
32 | override fun onReceive(context: Context, intent: Intent) {
33 | // Get the AppWidgetManager & appWidgetIds from the context
34 | val appWidgetManager = AppWidgetManager.getInstance(context)
35 | val appWidgetIds = appWidgetManager.getAppWidgetIds(ComponentName(context, RecipeWidgetProvider::class.java))
36 |
37 | // Get the action present in the Intent passed by the UpdateRecipeService
38 | val action = intent.action
39 | if (action == "android.appwidget.action.RECIPE_UPDATE") {
40 |
41 | // Get the extras from the Intent obtained from the UpdateRecipeService
42 | ingredientArrayList = intent.getParcelableArrayListExtra("ingredientsList")
43 | foodItemName = intent.getStringExtra("foodItemName")
44 |
45 | // Notify the AppWidgetManager that the data in the widget has changed
46 | appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_ingredients_list_view)
47 |
48 | // Update the data displayed in the widget
49 | updateRecipeWidgets(context, appWidgetManager, appWidgetIds)
50 | super.onReceive(context, intent)
51 | }
52 | }
53 |
54 | companion object {
55 |
56 | var ingredientArrayList = ArrayList()
57 | lateinit var foodItemName: String
58 |
59 | fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
60 |
61 | // Construct the RemoteViews object
62 | val views = RemoteViews(context.packageName, R.layout.recipe_widget_provider)
63 |
64 | // Setting the Food Item name
65 | views.setTextViewText(R.id.appwidget_food_item_title, foodItemName)
66 |
67 | // Setting the RemoteAdapter for the list view of Ingredients
68 | val intentForListView = Intent(context, RecipeWidgetRemoteViewsService::class.java)
69 | views.setRemoteAdapter(R.id.widget_ingredients_list_view, intentForListView)
70 |
71 | // Instruct the widget manager to update the widget
72 | appWidgetManager.updateAppWidget(appWidgetId, views)
73 | }
74 |
75 | fun updateRecipeWidgets(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
76 | for (appWidgetId in appWidgetIds) {
77 | updateAppWidget(context, appWidgetManager, appWidgetId)
78 | }
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/sync/RecipeWidgetRemoteViewsService.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.sync
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.widget.RemoteViews
6 | import android.widget.RemoteViewsService
7 | import bapspatil.captainchef.R
8 | import bapspatil.captainchef.model.Ingredient
9 | import java.util.*
10 |
11 | /**
12 | * Created by bapspatil
13 | */
14 |
15 | class RecipeWidgetRemoteViewsService : RemoteViewsService() {
16 |
17 | internal var remoteIngredientsList: ArrayList? = null
18 |
19 | override fun onGetViewFactory(intent: Intent): RemoteViewsService.RemoteViewsFactory {
20 | return RecipeWidgetRemoteViewsFactory(this.applicationContext, intent)
21 | }
22 |
23 | inner class RecipeWidgetRemoteViewsFactory(internal var mContext: Context, intent: Intent) : RemoteViewsService.RemoteViewsFactory {
24 |
25 | override fun onCreate() {
26 | }
27 |
28 | override fun onDataSetChanged() {
29 | remoteIngredientsList = RecipeWidgetProvider.Companion.ingredientArrayList
30 | }
31 |
32 | override fun onDestroy() {
33 | }
34 |
35 | override fun getCount(): Int {
36 | return if (remoteIngredientsList == null)
37 | 0
38 | else
39 | remoteIngredientsList!!.size
40 | }
41 |
42 | override fun getViewAt(i: Int): RemoteViews {
43 | // Construct the RemoteViews for the individual ingredient list item
44 | val views = RemoteViews(mContext.packageName, R.layout.recipe_widget_list_item_view)
45 |
46 | // Set the TextView in the layout of those individual ingredient list items
47 | views.setTextViewText(R.id.widget_ingredients_text_view, remoteIngredientsList!![i].ingredientName + "\n\t\t\tQuantity: " + remoteIngredientsList!![i].quant + " " + remoteIngredientsList!![i].measuredWith)
48 |
49 | // Return the RemoteViews
50 | return views
51 | }
52 |
53 | override fun getLoadingView(): RemoteViews? {
54 | return null
55 | }
56 |
57 | override fun getViewTypeCount(): Int {
58 | return 1
59 | }
60 |
61 | override fun getItemId(position: Int): Long {
62 | return position.toLong()
63 | }
64 |
65 | override fun hasStableIds(): Boolean {
66 | return true
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/sync/UpdateRecipeService.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.sync
2 |
3 | import android.app.IntentService
4 | import android.content.Context
5 | import android.content.Intent
6 | import bapspatil.captainchef.model.Ingredient
7 | import java.util.*
8 |
9 | /**
10 | * Created by bapspatil
11 | */
12 |
13 | class UpdateRecipeService : IntentService("UpdateRecipeService") {
14 |
15 | override fun onHandleIntent(intent: Intent?) {
16 | if (intent != null) {
17 | val foodItemName = intent.getStringExtra("foodItemName")
18 | val ingredientArrayList = intent.getParcelableArrayListExtra("ingredientsList")
19 | handleRecipeWidgetUpdate(foodItemName, ingredientArrayList)
20 | }
21 | }
22 |
23 | // Handle the recipe update action and send the broadcast to the WidgetProvider which updates the widget
24 | fun handleRecipeWidgetUpdate(foodItemName: String, ingredientArrayList: ArrayList) {
25 | val intentToWidget = Intent("android.appwidget.action.RECIPE_UPDATE")
26 | intentToWidget.action = "android.appwidget.action.RECIPE_UPDATE"
27 | intentToWidget.putExtra("foodItemName", foodItemName)
28 | intentToWidget.putParcelableArrayListExtra("ingredientsList", ingredientArrayList)
29 | sendBroadcast(intentToWidget)
30 | }
31 |
32 | companion object {
33 |
34 | // Helper method to explicitly start the UpdateRecipeService
35 | fun startRecipeWidgetService(context: Context, ingredientArrayList: ArrayList, foodItemName: String) {
36 | val intent = Intent(context, UpdateRecipeService::class.java)
37 | intent.putParcelableArrayListExtra("ingredientsList", ingredientArrayList)
38 | intent.putExtra("foodItemName", foodItemName)
39 | context.startService(intent)
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/ui/FoodItemsActivity.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.ui
2 |
3 | import android.app.ActivityOptions
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import android.support.v7.app.AppCompatActivity
7 | import android.support.v7.widget.GridLayoutManager
8 | import android.support.v7.widget.LinearLayoutManager
9 | import android.support.v7.widget.RecyclerView
10 | import android.support.v7.widget.Toolbar
11 | import android.widget.TextView
12 | import bapspatil.captainchef.R
13 | import bapspatil.captainchef.adapters.FoodItemsRecyclerViewAdapter
14 | import bapspatil.captainchef.model.FoodItem
15 | import bapspatil.captainchef.network.BakingAPI
16 | import butterknife.BindView
17 | import butterknife.ButterKnife
18 | import es.dmoral.toasty.Toasty
19 | import retrofit2.Call
20 | import retrofit2.Callback
21 | import retrofit2.Response
22 | import java.util.*
23 |
24 | class FoodItemsActivity : AppCompatActivity(), FoodItemsRecyclerViewAdapter.OnFoodItemClickListener {
25 | private val foodItemsList = ArrayList()
26 | private var mAdapter: FoodItemsRecyclerViewAdapter? = null
27 |
28 | @BindView(R.id.food_items_rv)
29 | var mFoodItemsRecyclerView: RecyclerView? = null
30 | @BindView(R.id.toolbar)
31 | var toolbar: Toolbar? = null
32 |
33 | private val isPhone: Boolean
34 | get() {
35 | val screenType = resources.getString(R.string.device)
36 | return screenType != "tablet"
37 | }
38 |
39 | override fun onCreate(savedInstanceState: Bundle?) {
40 | super.onCreate(savedInstanceState)
41 | setContentView(R.layout.activity_food_items)
42 | ButterKnife.bind(this)
43 | setSupportActionBar(toolbar)
44 | Toasty.info(applicationContext, "App developed by Bapusaheb Patil", 5000).show()
45 |
46 | if (isPhone)
47 | mFoodItemsRecyclerView!!.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
48 | else
49 | mFoodItemsRecyclerView!!.layoutManager = GridLayoutManager(this, 3)
50 | mAdapter = FoodItemsRecyclerViewAdapter(applicationContext, foodItemsList, this)
51 | mFoodItemsRecyclerView!!.adapter = mAdapter
52 | mFoodItemsRecyclerView!!.setHasFixedSize(true)
53 |
54 | fetchFoodItems()
55 | }
56 |
57 | private fun fetchFoodItems() {
58 | val bakingAPI = BakingAPI.retrofit.create(BakingAPI::class.java)
59 | val foodItemsCall = bakingAPI.foodItems
60 | foodItemsCall.enqueue(object : Callback> {
61 | override fun onResponse(call: Call>, response: Response>) {
62 | if (response.body() != null) {
63 | foodItemsList.addAll(response.body()!!)
64 | mAdapter!!.notifyDataSetChanged()
65 | } else {
66 | Toasty.error(applicationContext, "Couldn't load food items!", 5000).show()
67 | }
68 | }
69 |
70 | override fun onFailure(call: Call>, t: Throwable) {
71 | Toasty.error(applicationContext, "Couldn't load food items! " + t.message, 5000).show()
72 | }
73 | })
74 | }
75 |
76 | override fun onFoodItemClicked(position: Int, textView: TextView?) {
77 | Toasty.info(applicationContext, "This recipe serves 8 people", 5000).show()
78 | val foodItem = foodItemsList[position]
79 | val startRecipeActivity = Intent(this, RecipeActivity::class.java)
80 | startRecipeActivity.putExtra("foodItem", foodItem)
81 | val options = ActivityOptions.makeCustomAnimation(this, android.R.anim.fade_in, android.R.anim.fade_out)
82 | startActivity(startRecipeActivity, options.toBundle())
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/ui/RecipeActivity.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.ui
2 |
3 | import android.app.ActivityOptions
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import android.support.v4.app.FragmentManager
7 | import android.support.v7.app.AppCompatActivity
8 | import android.support.v7.widget.Toolbar
9 | import android.view.View
10 | import android.widget.TextView
11 | import bapspatil.captainchef.R
12 | import bapspatil.captainchef.model.FoodItem
13 | import bapspatil.captainchef.model.Ingredient
14 | import bapspatil.captainchef.model.RecipeStep
15 | import butterknife.BindView
16 | import butterknife.ButterKnife
17 | import java.util.*
18 |
19 | class RecipeActivity : AppCompatActivity(), StepsListFragment.OnStepClickListener, StepsDetailsFragment.OnButtonClickListener {
20 |
21 | private var ingredientsList: ArrayList? = ArrayList()
22 | private var recipeStepsList: ArrayList? = ArrayList()
23 | private lateinit var fragmentManager: FragmentManager
24 | private var mTwoPane: Boolean = false
25 | @BindView(R.id.toolbar)
26 | var toolbar: Toolbar? = null
27 | @BindView(R.id.recipe_toolbar_tv)
28 | var recipeToolbarTextView: TextView? = null
29 |
30 | private val isPhone: Boolean
31 | get() {
32 | val screenType = resources.getString(R.string.device)
33 | return screenType != "tablet"
34 | }
35 |
36 | override fun onCreate(savedInstanceState: Bundle?) {
37 | super.onCreate(savedInstanceState)
38 | setContentView(R.layout.activity_recipe)
39 | ButterKnife.bind(this)
40 | toolbar!!.title = ""
41 | setSupportActionBar(toolbar)
42 |
43 | fragmentManager = supportFragmentManager
44 |
45 | val (_, foodItemName, _, ingredients, steps) = intent.getParcelableExtra("foodItem")
46 |
47 | recipeToolbarTextView!!.text = foodItemName
48 |
49 | ingredientsList = ingredients
50 | recipeStepsList = steps
51 | if (isPhone) {
52 | mTwoPane = false
53 | if (savedInstanceState == null) {
54 | val stepsListFragment = StepsListFragment.newInstance(ingredientsList!!, recipeStepsList!!, foodItemName!!)
55 | fragmentManager.beginTransaction()
56 | .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
57 | .replace(R.id.recipe_container, stepsListFragment)
58 | .commit()
59 | }
60 | } else {
61 | mTwoPane = true
62 | if (savedInstanceState == null) {
63 | val stepsListFragment = StepsListFragment.newInstance(ingredientsList!!, recipeStepsList!!, foodItemName!!)
64 | fragmentManager.beginTransaction()
65 | .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
66 | .replace(R.id.recipe_container, stepsListFragment)
67 | .commit()
68 | }
69 | }
70 | }
71 |
72 | override fun onStepClicked(mRecipeStep: RecipeStep) {
73 | if (!mTwoPane) {
74 | val startRecipeDetailsActivity = Intent(this, RecipeDetailsActivity::class.java)
75 | startRecipeDetailsActivity.putExtra("recipeStep", mRecipeStep)
76 | startRecipeDetailsActivity.putParcelableArrayListExtra("recipeList", recipeStepsList)
77 | val options = ActivityOptions.makeCustomAnimation(applicationContext, android.R.anim.fade_in, android.R.anim.fade_out)
78 | startActivity(startRecipeDetailsActivity, options.toBundle())
79 | } else {
80 | val stepsDetailsFragment = StepsDetailsFragment.newInstance(mRecipeStep, recipeStepsList!!)
81 | fragmentManager = supportFragmentManager
82 | fragmentManager.beginTransaction()
83 | .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
84 | .replace(R.id.recipe_details_container, stepsDetailsFragment)
85 | .commit()
86 | }
87 | }
88 |
89 | override fun onBackPressed() {
90 | super.onBackPressed()
91 | this@RecipeActivity.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
92 | }
93 |
94 | override fun onButtonClicked(buttonClicked: Int, recipeStep: RecipeStep?, recipeSteps: ArrayList?, view: View) {
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/ui/RecipeDetailsActivity.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.ui
2 |
3 | import android.content.res.Configuration
4 | import android.os.Bundle
5 | import android.support.v4.app.FragmentManager
6 | import android.support.v7.app.AppCompatActivity
7 | import android.view.View
8 | import bapspatil.captainchef.R
9 | import bapspatil.captainchef.model.RecipeStep
10 | import butterknife.ButterKnife
11 | import java.util.*
12 |
13 | class RecipeDetailsActivity : AppCompatActivity(), StepsDetailsFragment.OnButtonClickListener {
14 | private var fragmentManager: FragmentManager? = null
15 | private var mRecipeStep: RecipeStep? = null
16 | private var mRecipeStepsList: ArrayList? = null
17 |
18 | private val isLandscape: Boolean
19 | get() = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
20 |
21 | override fun onCreate(savedInstanceState: Bundle?) {
22 | super.onCreate(savedInstanceState)
23 | setContentView(R.layout.activity_recipe_details)
24 | ButterKnife.bind(this)
25 |
26 | mRecipeStep = intent.getParcelableExtra("recipeStep")
27 | mRecipeStepsList = intent.getParcelableArrayListExtra("recipeList")
28 | fragmentManager = supportFragmentManager
29 | if (savedInstanceState == null) {
30 | val stepsDetailsFragment = StepsDetailsFragment.newInstance(mRecipeStep!!, mRecipeStepsList!!)
31 | fragmentManager!!.beginTransaction()
32 | .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
33 | .replace(R.id.recipe_details_container, stepsDetailsFragment)
34 | .commit()
35 | }
36 | }
37 |
38 | override fun onWindowFocusChanged(hasFocus: Boolean) {
39 | super.onWindowFocusChanged(hasFocus)
40 | if (hasFocus && isLandscape) {
41 | window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
42 | or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
43 | or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
44 | or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
45 | or View.SYSTEM_UI_FLAG_FULLSCREEN
46 | or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
47 | }
48 | }
49 |
50 | override fun onButtonClicked(buttonClicked: Int, recipeStep: RecipeStep?, recipeSteps: ArrayList?, view: View) {
51 | if (buttonClicked == StepsDetailsFragment.PREV_BUTTON) {
52 | var id = recipeStep!!.stepId
53 | id--
54 | val prevRecipeStep = recipeSteps!![id]
55 | val stepsDetailsFragment = StepsDetailsFragment.newInstance(prevRecipeStep, mRecipeStepsList!!)
56 | fragmentManager = supportFragmentManager
57 | fragmentManager!!.beginTransaction()
58 | .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
59 | .replace(R.id.recipe_details_container, stepsDetailsFragment)
60 | .commit()
61 | } else {
62 | var id = recipeStep!!.stepId
63 | id++
64 | val nextRecipeStep = recipeSteps!![id]
65 | val stepsDetailsFragment = StepsDetailsFragment.newInstance(nextRecipeStep, mRecipeStepsList!!)
66 | fragmentManager = supportFragmentManager
67 | fragmentManager!!.beginTransaction()
68 | .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
69 | .replace(R.id.recipe_details_container, stepsDetailsFragment)
70 | .commit()
71 | }
72 | }
73 |
74 | override fun onBackPressed() {
75 | super.onBackPressed()
76 | this@RecipeDetailsActivity.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/ui/SplashScreenActivity.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.ui
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import android.os.Handler
6 | import android.support.v7.app.AppCompatActivity
7 | import android.view.View
8 |
9 | import bapspatil.captainchef.R
10 |
11 | class SplashScreenActivity : AppCompatActivity() {
12 |
13 | override fun onCreate(savedInstanceState: Bundle?) {
14 | super.onCreate(savedInstanceState)
15 | setContentView(R.layout.activity_splash_screen)
16 | immersiveMode()
17 | val SPLASH_TIME_OUT = 1000
18 | Handler().postDelayed({
19 | val i = Intent(this@SplashScreenActivity, FoodItemsActivity::class.java)
20 | startActivity(i)
21 | finish()
22 | }, SPLASH_TIME_OUT.toLong())
23 | }
24 |
25 | private fun immersiveMode() {
26 | window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
27 | or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
28 | or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
29 | or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
30 |
31 | or View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
32 |
33 | or View.SYSTEM_UI_FLAG_IMMERSIVE)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/ui/StepsDetailsFragment.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.ui
2 |
3 | import android.content.Context
4 | import android.net.Uri
5 | import android.os.Bundle
6 | import android.os.Handler
7 | import android.support.v4.app.Fragment
8 | import android.support.v7.widget.CardView
9 | import android.view.LayoutInflater
10 | import android.view.View
11 | import android.view.ViewGroup
12 | import android.widget.Button
13 | import android.widget.TextView
14 | import bapspatil.captainchef.R
15 | import bapspatil.captainchef.model.RecipeStep
16 | import butterknife.BindView
17 | import butterknife.ButterKnife
18 | import butterknife.OnClick
19 | import butterknife.Unbinder
20 | import com.google.android.exoplayer2.ExoPlayerFactory
21 | import com.google.android.exoplayer2.SimpleExoPlayer
22 | import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
23 | import com.google.android.exoplayer2.source.ExtractorMediaSource
24 | import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection
25 | import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
26 | import com.google.android.exoplayer2.ui.SimpleExoPlayerView
27 | import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter
28 | import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
29 | import com.google.android.exoplayer2.util.Util
30 | import java.util.*
31 |
32 | /**
33 | * A simple [Fragment] subclass.
34 | */
35 | class StepsDetailsFragment : Fragment() {
36 | @BindView(R.id.step_description_tv)
37 | var mStepDescription: TextView? = null
38 | @BindView(R.id.video_exoplayer_view)
39 | var mPlayerView: SimpleExoPlayerView? = null
40 | @BindView(R.id.next_button)
41 | var nextButton: Button? = null
42 | @BindView(R.id.prev_button)
43 | var prevButton: Button? = null
44 | @BindView(R.id.next_card_view)
45 | var nextCardView: CardView? = null
46 | @BindView(R.id.prev_card_view)
47 | var prevCardView: CardView? = null
48 | private var mPlayer: SimpleExoPlayer? = null
49 | private var unbinder: Unbinder? = null
50 | private var recipeStep: RecipeStep? = null
51 | private var position: Long = -1
52 | private var videoUri: Uri? = null
53 | private var recipeStepsList: ArrayList? = null
54 | lateinit var mButtonListener: OnButtonClickListener
55 |
56 | override fun onCreateView(
57 | inflater: LayoutInflater,
58 | container: ViewGroup?,
59 | savedInstanceState: Bundle?
60 | ): View? {
61 | val rootView = inflater.inflate(R.layout.fragment_steps_details, container, false)
62 | unbinder = ButterKnife.bind(this, rootView)
63 |
64 | if (savedInstanceState != null)
65 | position = savedInstanceState.getLong("SAVED_POSITION")
66 | recipeStep = arguments!!.getParcelable("recipeStep")
67 | recipeStepsList = arguments!!.getParcelableArrayList("recipeList")
68 | if (recipeStep != null) {
69 | mStepDescription!!.text = recipeStep!!.info
70 | if (recipeStep!!.videoUrl == "" || recipeStep!!.videoUrl == null) {
71 | mPlayerView!!.visibility = View.GONE
72 | } else {
73 | getPlayer()
74 | }
75 | when {
76 | recipeStep!!.stepId == 0 -> {
77 | prevButton!!.visibility = View.INVISIBLE
78 | prevCardView!!.visibility = View.INVISIBLE
79 | }
80 | recipeStep!!.stepId == recipeStepsList!!.size - 1 -> {
81 | nextButton!!.visibility = View.INVISIBLE
82 | nextCardView!!.visibility = View.INVISIBLE
83 | }
84 | else -> {
85 | prevButton!!.visibility = View.VISIBLE
86 | nextButton!!.visibility = View.VISIBLE
87 | prevCardView!!.visibility = View.VISIBLE
88 | nextCardView!!.visibility = View.VISIBLE
89 | }
90 | }
91 | }
92 | return rootView
93 | }
94 |
95 | override fun onDestroyView() {
96 | super.onDestroyView()
97 | unbinder!!.unbind()
98 | }
99 |
100 | override fun onPause() {
101 | super.onPause()
102 | if (mPlayer != null) {
103 | position = mPlayer!!.currentPosition
104 | mPlayer!!.stop()
105 | mPlayer!!.release()
106 | mPlayer = null
107 | }
108 | }
109 |
110 | override fun onResume() {
111 | super.onResume()
112 | if (mPlayer != null) {
113 | if (position.toInt() != -1) mPlayer!!.seekTo(position)
114 | }
115 | }
116 |
117 | override fun onSaveInstanceState(outState: Bundle) {
118 | super.onSaveInstanceState(outState)
119 | outState.putLong("SAVED_POSITION", position)
120 | }
121 |
122 | @OnClick(R.id.prev_button)
123 | internal fun prevStep(view: View) {
124 | mButtonListener.onButtonClicked(PREV_BUTTON, recipeStep, recipeStepsList, view)
125 | }
126 |
127 | @OnClick(R.id.next_button)
128 | internal fun nextStep(view: View) {
129 | mButtonListener.onButtonClicked(NEXT_BUTTON, recipeStep, recipeStepsList, view)
130 | }
131 |
132 | private fun getPlayer() {
133 | val mainHandler = Handler()
134 | val bandwidthMeter = DefaultBandwidthMeter()
135 | val videoTrackSelectionFactory = AdaptiveTrackSelection.Factory(bandwidthMeter)
136 | val trackSelector = DefaultTrackSelector(videoTrackSelectionFactory)
137 | mPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector)
138 |
139 | mPlayerView!!.useController = true
140 | mPlayerView!!.requestFocus()
141 | mPlayerView!!.player = mPlayer
142 | // Measures bandwidth during playback. Can be null if not required.
143 | val defaultBandwidthMeter = DefaultBandwidthMeter()
144 | // Produces DataSource instances through which media data is loaded.
145 | val dataSourceFactory = DefaultDataSourceFactory(context!!,
146 | Util.getUserAgent(context, "CaptainChef"), defaultBandwidthMeter)
147 | // Produces Extractor instances for parsing the media data.
148 | val extractorsFactory = DefaultExtractorsFactory()
149 | // This is the MediaSource representing the media to be played.
150 | videoUri = Uri.parse(recipeStep!!.videoUrl)
151 | val videoSource = ExtractorMediaSource(videoUri,
152 | dataSourceFactory, extractorsFactory, null, null)
153 | // Prepare the player with the source.
154 | if (position.toInt() != -1)
155 | mPlayer!!.seekTo(position)
156 | mPlayer!!.prepare(videoSource)
157 | mPlayer!!.playWhenReady = true
158 | }
159 |
160 | interface OnButtonClickListener {
161 | fun onButtonClicked(buttonClicked: Int, recipeStep: RecipeStep?, recipeSteps: ArrayList?, view: View)
162 | }
163 |
164 | override fun onAttach(context: Context?) {
165 | super.onAttach(context)
166 | try {
167 | mButtonListener = context as OnButtonClickListener
168 | } catch (e: ClassCastException) {
169 | throw ClassCastException(context!!.toString() + " must implement OnButtonClickListener")
170 | }
171 | }
172 |
173 | companion object {
174 |
175 | val PREV_BUTTON = 0
176 | val NEXT_BUTTON = 1
177 |
178 | fun newInstance(recipeStep: RecipeStep, recipeStepArrayList: ArrayList): StepsDetailsFragment {
179 | val stepsDetailsFragment = StepsDetailsFragment()
180 | val bundle = Bundle()
181 | bundle.putParcelable("recipeStep", recipeStep)
182 | bundle.putParcelableArrayList("recipeList", recipeStepArrayList)
183 | stepsDetailsFragment.arguments = bundle
184 | return stepsDetailsFragment
185 | }
186 | }
187 | } // Required empty public constructor
188 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/ui/StepsListFragment.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.ui
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.support.v4.app.Fragment
6 | import android.support.v7.widget.LinearLayoutManager
7 | import android.view.LayoutInflater
8 | import android.view.View
9 | import android.view.ViewGroup
10 | import bapspatil.captainchef.R
11 | import bapspatil.captainchef.adapters.IngredientsRecyclerViewAdapter
12 | import bapspatil.captainchef.adapters.StepsListRecyclerViewAdapter
13 | import bapspatil.captainchef.model.Ingredient
14 | import bapspatil.captainchef.model.RecipeStep
15 | import bapspatil.captainchef.sync.UpdateRecipeService
16 | import butterknife.ButterKnife
17 | import butterknife.OnClick
18 | import butterknife.Unbinder
19 | import es.dmoral.toasty.Toasty
20 | import kotlinx.android.synthetic.main.fragment_steps_list.*
21 | import java.util.*
22 |
23 | /**
24 | * Created by bapspatil
25 | */
26 | class StepsListFragment : Fragment(), StepsListRecyclerViewAdapter.OnRecipeStepClickedListener {
27 |
28 | private var ingredientsList: ArrayList? = null
29 | private var mIngredientsAdapter: IngredientsRecyclerViewAdapter? = null
30 | private var recipeStepsList: ArrayList? = null
31 | private var mStepsListAdapter: StepsListRecyclerViewAdapter? = null
32 | private var foodItemName: String? = null
33 | private var unbinder: Unbinder? = null
34 | lateinit var mStepClickListener: OnStepClickListener
35 |
36 | override fun onRecipeStepClicked(recipeStep: RecipeStep) {
37 | mStepClickListener.onStepClicked(recipeStep)
38 | }
39 |
40 | interface OnStepClickListener {
41 | fun onStepClicked(mRecipeStep: RecipeStep)
42 | }
43 |
44 | @OnClick(R.id.add_to_widget_button)
45 | internal fun addToWidget(view: View) {
46 | // Start the UpdateRecipeService to update the ingredients list widget in the homescreen
47 | UpdateRecipeService.startRecipeWidgetService(context!!, ingredientsList!!, foodItemName!!)
48 |
49 | Toasty.info(context!!, "Recipe ingredients have been added to homescreen widget!", 5000).show()
50 | }
51 |
52 | override fun onStart() {
53 | super.onStart()
54 | ingredientsList = arguments!!.getParcelableArrayList("ingredientsList")
55 | recipeStepsList = arguments!!.getParcelableArrayList("recipeStepsList")
56 | foodItemName = arguments!!.getString("foodItemName")
57 |
58 | mIngredientsAdapter = IngredientsRecyclerViewAdapter(context!!, ingredientsList!!)
59 | mStepsListAdapter = StepsListRecyclerViewAdapter(context!!, recipeStepsList!!, this)
60 |
61 | ingredients_rv!!.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
62 | val linearLayoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
63 | steps_rv!!.layoutManager = linearLayoutManager
64 |
65 | ingredients_rv!!.adapter = mIngredientsAdapter!!
66 | steps_rv!!.adapter = mStepsListAdapter!!
67 | }
68 |
69 | override fun onCreateView(
70 | inflater: LayoutInflater,
71 | container: ViewGroup?,
72 | savedInstanceState: Bundle?
73 | ): View? {
74 | // Inflate the layout for this fragment
75 | val rootView = inflater.inflate(R.layout.fragment_steps_list, container, false)
76 | unbinder = ButterKnife.bind(this, rootView)
77 |
78 | return rootView
79 | }
80 |
81 | override fun onAttach(context: Context?) {
82 | super.onAttach(context)
83 |
84 | // This makes sure that the host activity has implemented the callback interface
85 | // If not, it throws an exception
86 | try {
87 | mStepClickListener = context as OnStepClickListener
88 | } catch (e: ClassCastException) {
89 | throw ClassCastException(context!!.toString() + " must implement OnStepClickListener")
90 | }
91 | }
92 |
93 | override fun onDestroyView() {
94 | super.onDestroyView()
95 | unbinder!!.unbind()
96 | }
97 |
98 | companion object {
99 |
100 | fun newInstance(mIngredientsList: ArrayList, mRecipeList: ArrayList, mFoodItemName: String): StepsListFragment {
101 | val stepsListFragment = StepsListFragment()
102 | val bundle = Bundle()
103 | bundle.putParcelableArrayList("ingredientsList", mIngredientsList)
104 | bundle.putParcelableArrayList("recipeStepsList", mRecipeList)
105 | bundle.putString("foodItemName", mFoodItemName)
106 | stepsListFragment.arguments = bundle
107 | return stepsListFragment
108 | }
109 | }
110 | } // Empty constructor
111 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/utils/CaptainChefGlideModule.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.utils
2 |
3 | import com.bumptech.glide.annotation.GlideModule
4 | import com.bumptech.glide.module.AppGlideModule
5 |
6 | /**
7 | * Created by bapspatil
8 | */
9 |
10 | @GlideModule
11 | class CaptainChefGlideModule : AppGlideModule()
12 |
--------------------------------------------------------------------------------
/app/src/main/java/bapspatil/captainchef/utils/EndlessScrollListener.kt:
--------------------------------------------------------------------------------
1 | package bapspatil.captainchef.utils
2 |
3 | import android.support.v7.widget.GridLayoutManager
4 | import android.support.v7.widget.LinearLayoutManager
5 | import android.support.v7.widget.RecyclerView
6 | import android.support.v7.widget.StaggeredGridLayoutManager
7 |
8 | /**
9 | * Created by bapspatil
10 | */
11 |
12 | abstract class EndlessScrollListener : RecyclerView.OnScrollListener {
13 | // The minimum amount of items to have below your current scroll position
14 | // before loading more.
15 | private var visibleThreshold = 5
16 | // The current offset index of data you have loaded
17 | private var currentPage = 1
18 | // The total number of items in the dataset after the last load
19 | private var previousTotalItemCount = 0
20 | // True if we are still waiting for the last set of data to load.
21 | private var loading = true
22 | // Sets the starting page index
23 | private val startingPageIndex = 0
24 |
25 | internal var mLayoutManager: RecyclerView.LayoutManager
26 |
27 | constructor(layoutManager: LinearLayoutManager) {
28 | this.mLayoutManager = layoutManager
29 | }
30 |
31 | constructor(layoutManager: GridLayoutManager) {
32 | this.mLayoutManager = layoutManager
33 | visibleThreshold = visibleThreshold * layoutManager.spanCount
34 | }
35 |
36 | constructor(layoutManager: StaggeredGridLayoutManager) {
37 | this.mLayoutManager = layoutManager
38 | visibleThreshold = visibleThreshold * layoutManager.spanCount
39 | }
40 |
41 | fun getLastVisibleItem(lastVisibleItemPositions: IntArray): Int {
42 | var maxSize = 0
43 | for (i in lastVisibleItemPositions.indices) {
44 | if (i == 0) {
45 | maxSize = lastVisibleItemPositions[i]
46 | } else if (lastVisibleItemPositions[i] > maxSize) {
47 | maxSize = lastVisibleItemPositions[i]
48 | }
49 | }
50 | return maxSize
51 | }
52 |
53 | // This happens many times a second during a scroll, so be wary of the code you place here.
54 | // We are given a few useful parameters to help us work out if we need to load some more data,
55 | // but first we check if we are waiting for the previous load to finish.
56 | override fun onScrolled(view: RecyclerView?, dx: Int, dy: Int) {
57 | var lastVisibleItemPosition = 0
58 | val totalItemCount = mLayoutManager.itemCount
59 |
60 | if (mLayoutManager is StaggeredGridLayoutManager) {
61 | val lastVisibleItemPositions = (mLayoutManager as StaggeredGridLayoutManager).findLastVisibleItemPositions(null)
62 | // get maximum element within the list
63 | lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions)
64 | } else if (mLayoutManager is LinearLayoutManager) {
65 | lastVisibleItemPosition = (mLayoutManager as LinearLayoutManager).findLastVisibleItemPosition()
66 | } else if (mLayoutManager is GridLayoutManager) {
67 | lastVisibleItemPosition = (mLayoutManager as GridLayoutManager).findLastVisibleItemPosition()
68 | }
69 |
70 | // If the total item count is zero and the previous isn't, assume the
71 | // list is invalidated and should be reset back to initial state
72 | if (totalItemCount < previousTotalItemCount) {
73 | this.currentPage = this.startingPageIndex
74 | this.previousTotalItemCount = totalItemCount
75 | if (totalItemCount == 0) {
76 | this.loading = true
77 | }
78 | }
79 | // If it’s still loading, we check to see if the dataset count has
80 | // changed, if so we conclude it has finished loading and update the current page
81 | // number and total item count.
82 | if (loading && totalItemCount > previousTotalItemCount) {
83 | loading = false
84 | previousTotalItemCount = totalItemCount
85 | }
86 |
87 | // If it isn’t currently loading, we check to see if we have breached
88 | // the visibleThreshold and need to reload more data.
89 | // If we do need to reload some more data, we execute onLoadMore to fetch the data.
90 | // threshold should reflect how many total columns there are too
91 | if (!loading && lastVisibleItemPosition + visibleThreshold > totalItemCount) {
92 | currentPage++
93 | onLoadMore(currentPage, totalItemCount)
94 | loading = true
95 | }
96 | }
97 |
98 | // Defines the process for actually loading more data based on page
99 | abstract fun onLoadMore(page: Int, totalItemsCount: Int)
100 | }
101 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/fallback_recipe_thumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/app/src/main/res/drawable-nodpi/fallback_recipe_thumbnail.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/recipe_widget_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/app/src/main/res/drawable-nodpi/recipe_widget_preview.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/splash_screen_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/app/src/main/res/drawable-nodpi/splash_screen_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/font/autour_one.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/app/src/main/res/font/autour_one.ttf
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/fragment_steps_details.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
15 |
16 |
19 |
20 |
30 |
31 |
43 |
44 |
45 |
46 |
50 |
51 |
61 |
62 |
73 |
74 |
75 |
76 |
89 |
90 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-sw600dp/activity_food_items.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
16 |
17 |
21 |
22 |
29 |
30 |
31 |
32 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-sw600dp/activity_recipe.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 | \
15 |
16 |
21 |
22 |
28 |
29 |
39 |
40 |
41 |
42 |
47 |
48 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-sw600dp/fragment_steps_details.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
12 |
13 |
18 |
19 |
29 |
30 |
43 |
44 |
45 |
46 |
51 |
52 |
62 |
63 |
74 |
75 |
76 |
77 |
90 |
91 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-sw600dp/rv_food_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
21 |
22 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_food_items.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
13 |
14 |
21 |
22 |
28 |
29 |
34 |
35 |
36 |
37 |
41 |
42 |
47 |
48 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_recipe.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
21 |
22 |
28 |
29 |
39 |
40 |
41 |
42 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_recipe_details.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
22 |
23 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_steps_details.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
12 |
13 |
17 |
18 |
29 |
30 |
43 |
44 |
45 |
46 |
51 |
52 |
62 |
63 |
75 |
76 |
77 |
78 |
91 |
92 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_steps_list.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
14 |
19 |
20 |
29 |
30 |
37 |
38 |
43 |
44 |
55 |
56 |
67 |
68 |
69 |
81 |
82 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recipe_widget_before_selection.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recipe_widget_list_item_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recipe_widget_provider.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
20 |
21 |
28 |
29 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_food_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
18 |
19 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_ingredients.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
26 |
27 |
38 |
39 |
50 |
51 |
52 |
53 |
59 |
60 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_steps_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
21 |
22 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-sw600dp/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CaptainChef
3 |
4 | This is the food item
5 | Which tasty dessert would you like to bake today?
6 | tablet
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v14/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 | 0dp
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #673AB7
4 | #512DA8
5 | #CDDC39
6 | #FFFFFF
7 | #000000
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 |
5 |
9 | 8dp
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CaptainChef
3 |
4 | This is the food item
5 | Which tasty dessert would you like to bake today?
6 | phone
7 |
8 | Hello blank fragment
9 | Ingredients
10 | Steps
11 | PREV STEP
12 | NEXT STEP
13 | Food item name
14 | Add widget
15 | Empty view
16 | Add ingredients list to widget
17 | Choose a food item from the app
18 | Recipe Item Image View
19 | foodItemNameTransition
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/recipe_widget_provider_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlinVer = '1.2.51'
5 | repositories {
6 | jcenter()
7 | google()
8 | mavenCentral()
9 | maven { url "https://jitpack.io" }
10 | }
11 | dependencies {
12 | classpath 'com.android.tools.build:gradle:3.1.3'
13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVer"
14 | // NOTE: Do not place your application dependencies here; they belong
15 | // in the individual module build.gradle files
16 | }
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | jcenter()
22 | google()
23 | mavenCentral()
24 | maven { url "https://jitpack.io" }
25 | maven { url 'https://clojars.org/repo/' }
26 | }
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/design/screen0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/design/screen0.png
--------------------------------------------------------------------------------
/design/screen1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/design/screen1.png
--------------------------------------------------------------------------------
/design/screen2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/design/screen2.png
--------------------------------------------------------------------------------
/design/screen3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/design/screen3.png
--------------------------------------------------------------------------------
/design/screen4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/design/screen4.png
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Enable Gradle Daemon
2 | org.gradle.daemon=true
3 | # Enable parallel builds
4 | org.gradle.parallel=true
5 | # Enable Build Cache
6 | android.enableBuildCache=true
7 | # Enable simple gradle caching
8 | org.gradle.caching=true
9 | # Increase memory allotted to JVM
10 | org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Dec 05 15:12:08 IST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/resources/baking.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": 1,
4 | "name": "Nutella Pie",
5 | "ingredients": [
6 | {
7 | "quantity": 2,
8 | "measure": "CUP",
9 | "ingredient": "Graham Cracker crumbs"
10 | },
11 | {
12 | "quantity": 6,
13 | "measure": "TBLSP",
14 | "ingredient": "unsalted butter, melted"
15 | },
16 | {
17 | "quantity": 1,
18 | "measure": "CUP",
19 | "ingredient": "granulated sugar"
20 | },
21 | {
22 | "quantity": 1.5,
23 | "measure": "TSP",
24 | "ingredient": "salt"
25 | },
26 | {
27 | "quantity": 5,
28 | "measure": "TBLSP",
29 | "ingredient": "vanilla"
30 | },
31 | {
32 | "quantity": 1,
33 | "measure": "K",
34 | "ingredient": "Nutella or other chocolate-hazelnut spread"
35 | },
36 | {
37 | "quantity": 500,
38 | "measure": "G",
39 | "ingredient": "Mascapone Cheese(room temperature)"
40 | },
41 | {
42 | "quantity": 1,
43 | "measure": "CUP",
44 | "ingredient": "heavy cream(cold)"
45 | },
46 | {
47 | "quantity": 4,
48 | "measure": "OZ",
49 | "ingredient": "cream cheese(softened)"
50 | }
51 | ],
52 | "steps": [
53 | {
54 | "id": 0,
55 | "shortDescription": "Recipe Introduction",
56 | "description": "Recipe Introduction",
57 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffd974_-intro-creampie/-intro-creampie.mp4",
58 | "thumbnailURL": ""
59 | },
60 | {
61 | "id": 1,
62 | "shortDescription": "Starting prep",
63 | "description": "1. Preheat the oven to 350\u00b0F. Butter a 9\" deep dish pie pan.",
64 | "videoURL": "",
65 | "thumbnailURL": ""
66 | },
67 | {
68 | "id": 2,
69 | "shortDescription": "Prep the cookie crust.",
70 | "description": "2. Whisk the graham cracker crumbs, 50 grams (1/4 cup) of sugar, and 1/2 teaspoon of salt together in a medium bowl. Pour the melted butter and 1 teaspoon of vanilla into the dry ingredients and stir together until evenly mixed.",
71 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffd9a6_2-mix-sugar-crackers-creampie/2-mix-sugar-crackers-creampie.mp4",
72 | "thumbnailURL": ""
73 | },
74 | {
75 | "id": 3,
76 | "shortDescription": "Press the crust into baking form.",
77 | "description": "3. Press the cookie crumb mixture into the prepared pie pan and bake for 12 minutes. Let crust cool to room temperature.",
78 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffd9cb_4-press-crumbs-in-pie-plate-creampie/4-press-crumbs-in-pie-plate-creampie.mp4",
79 | "thumbnailURL": ""
80 | },
81 | {
82 | "id": 4,
83 | "shortDescription": "Start filling prep",
84 | "description": "4. Beat together the nutella, mascarpone, 1 teaspoon of salt, and 1 tablespoon of vanilla on medium speed in a stand mixer or high speed with a hand mixer until fluffy.",
85 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffd97a_1-mix-marscapone-nutella-creampie/1-mix-marscapone-nutella-creampie.mp4",
86 | "thumbnailURL": ""
87 | },
88 | {
89 | "id": 5,
90 | "shortDescription": "Finish filling prep",
91 | "description": "5. Beat the cream cheese and 50 grams (1/4 cup) of sugar on medium speed in a stand mixer or high speed with a hand mixer for 3 minutes. Decrease the speed to medium-low and gradually add in the cold cream. Add in 2 teaspoons of vanilla and beat until stiff peaks form.",
92 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffda20_7-add-cream-mix-creampie/7-add-cream-mix-creampie.mp4",
93 | "thumbnailURL": ""
94 | },
95 | {
96 | "id": 6,
97 | "shortDescription": "Finishing Steps",
98 | "description": "6. Pour the filling into the prepared crust and smooth the top. Spread the whipped cream over the filling. Refrigerate the pie for at least 2 hours. Then it's ready to serve!",
99 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffda45_9-add-mixed-nutella-to-crust-creampie/9-add-mixed-nutella-to-crust-creampie.mp4",
100 | "thumbnailURL": ""
101 | }
102 | ],
103 | "servings": 8,
104 | "image": "https://raw.githubusercontent.com/bapspatil/CaptainChef/master/resources/nutella_pie.jpg"
105 | },
106 | {
107 | "id": 2,
108 | "name": "Brownies",
109 | "ingredients": [
110 | {
111 | "quantity": 350,
112 | "measure": "G",
113 | "ingredient": "Bittersweet chocolate (60-70% cacao)"
114 | },
115 | {
116 | "quantity": 226,
117 | "measure": "G",
118 | "ingredient": "unsalted butter"
119 | },
120 | {
121 | "quantity": 300,
122 | "measure": "G",
123 | "ingredient": "granulated sugar"
124 | },
125 | {
126 | "quantity": 100,
127 | "measure": "G",
128 | "ingredient": "light brown sugar"
129 | },
130 | {
131 | "quantity": 5,
132 | "measure": "UNIT",
133 | "ingredient": "large eggs"
134 | },
135 | {
136 | "quantity": 1,
137 | "measure": "TBLSP",
138 | "ingredient": "vanilla extract"
139 | },
140 | {
141 | "quantity": 140,
142 | "measure": "G",
143 | "ingredient": "all purpose flour"
144 | },
145 | {
146 | "quantity": 40,
147 | "measure": "G",
148 | "ingredient": "cocoa powder"
149 | },
150 | {
151 | "quantity": 1.5,
152 | "measure": "TSP",
153 | "ingredient": "salt"
154 | },
155 | {
156 | "quantity": 350,
157 | "measure": "G",
158 | "ingredient": "semisweet chocolate chips"
159 | }
160 | ],
161 | "steps": [
162 | {
163 | "id": 0,
164 | "shortDescription": "Recipe Introduction",
165 | "description": "Recipe Introduction",
166 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffdc33_-intro-brownies/-intro-brownies.mp4",
167 | "thumbnailURL": ""
168 | },
169 | {
170 | "id": 1,
171 | "shortDescription": "Starting prep",
172 | "description": "1. Preheat the oven to 350�F. Butter the bottom and sides of a 9\"x13\" pan.",
173 | "videoURL": "",
174 | "thumbnailURL": ""
175 | },
176 | {
177 | "id": 2,
178 | "shortDescription": "Melt butter and bittersweet chocolate.",
179 | "description": "2. Melt the butter and bittersweet chocolate together in a microwave or a double boiler. If microwaving, heat for 30 seconds at a time, removing bowl and stirring ingredients in between.",
180 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffdc43_1-melt-choclate-chips-and-butter-brownies/1-melt-choclate-chips-and-butter-brownies.mp4",
181 | "thumbnailURL": ""
182 | },
183 | {
184 | "id": 3,
185 | "shortDescription": "Add sugars to wet mixture.",
186 | "description": "3. Mix both sugars into the melted chocolate in a large mixing bowl until mixture is smooth and uniform.",
187 | "videoURL": "",
188 | "thumbnailURL": ""
189 | },
190 | {
191 | "id": 4,
192 | "shortDescription": "Mix together dry ingredients.",
193 | "description": "4. Sift together the flour, cocoa, and salt in a small bowl and whisk until mixture is uniform and no clumps remain. ",
194 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffdc9e_4-sift-flower-add-coco-powder-salt-brownies/4-sift-flower-add-coco-powder-salt-brownies.mp4",
195 | "thumbnailURL": ""
196 | },
197 | {
198 | "id": 5,
199 | "shortDescription": "Add eggs.",
200 | "description": "5. Crack 3 eggs into the chocolate mixture and carefully fold them in. Crack the other 2 eggs in and carefully fold them in. Fold in the vanilla.",
201 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffdc62_2-mix-egss-with-choclate-butter-brownies/2-mix-egss-with-choclate-butter-brownies.mp4",
202 | "thumbnailURL": ""
203 | },
204 | {
205 | "id": 6,
206 | "shortDescription": "Add dry mixture to wet mixture.",
207 | "description": "6. Dump half of flour mixture into chocolate mixture and carefully fold in, just until no streaks remain. Repeat with the rest of the flour mixture. Fold in the chocolate chips.",
208 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffdcc8_5-mix-wet-and-cry-batter-together-brownies/5-mix-wet-and-cry-batter-together-brownies.mp4",
209 | "thumbnailURL": ""
210 | },
211 | {
212 | "id": 7,
213 | "shortDescription": "Add batter to pan.",
214 | "description": "7. Pour the batter into the prepared pan and bake for 30 minutes.",
215 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffdcf4_8-put-brownies-in-oven-to-bake-brownies/8-put-brownies-in-oven-to-bake-brownies.mp4",
216 | "thumbnailURL": ""
217 | },
218 | {
219 | "id": 8,
220 | "shortDescription": "Remove pan from oven.",
221 | "description": "8. Remove the pan from the oven and let cool until room temperature. If you want to speed this up, you can feel free to put the pan in a freezer for a bit.",
222 | "videoURL": "",
223 | "thumbnailURL": ""
224 | },
225 | {
226 | "id": 9,
227 | "shortDescription": "Cut and serve.",
228 | "description": "9. Cut and serve.",
229 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffdcf9_9-final-product-brownies/9-final-product-brownies.mp4",
230 | "thumbnailURL": ""
231 | }
232 | ],
233 | "servings": 8,
234 | "image": "https://raw.githubusercontent.com/bapspatil/CaptainChef/master/resources/brownie.jpg"
235 | },
236 | {
237 | "id": 3,
238 | "name": "Yellow Cake",
239 | "ingredients": [
240 | {
241 | "quantity": 400,
242 | "measure": "G",
243 | "ingredient": "sifted cake flour"
244 | },
245 | {
246 | "quantity": 700,
247 | "measure": "G",
248 | "ingredient": "granulated sugar"
249 | },
250 | {
251 | "quantity": 4,
252 | "measure": "TSP",
253 | "ingredient": "baking powder"
254 | },
255 | {
256 | "quantity": 1.5,
257 | "measure": "TSP",
258 | "ingredient": "salt"
259 | },
260 | {
261 | "quantity": 2,
262 | "measure": "TBLSP",
263 | "ingredient": "vanilla extract, divided"
264 | },
265 | {
266 | "quantity": 8,
267 | "measure": "UNIT",
268 | "ingredient": "egg yolks"
269 | },
270 | {
271 | "quantity": 323,
272 | "measure": "G",
273 | "ingredient": "whole milk"
274 | },
275 | {
276 | "quantity": 961,
277 | "measure": "G",
278 | "ingredient": "unsalted butter, softened and cut into 1 in. cubes"
279 | },
280 | {
281 | "quantity": 6,
282 | "measure": "UNIT",
283 | "ingredient": "egg whites"
284 | },
285 | {
286 | "quantity": 283,
287 | "measure": "G",
288 | "ingredient": "melted and cooled bittersweet or semisweet chocolate"
289 | }
290 | ],
291 | "steps": [
292 | {
293 | "id": 0,
294 | "shortDescription": "Recipe Introduction",
295 | "description": "Recipe Introduction",
296 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffddf0_-intro-yellow-cake/-intro-yellow-cake.mp4",
297 | "thumbnailURL": ""
298 | },
299 | {
300 | "id": 1,
301 | "shortDescription": "Starting prep",
302 | "description": "1. Preheat the oven to 350\u00b0F. Butter the bottoms and sides of two 9\" round pans with 2\"-high sides. Cover the bottoms of the pans with rounds of parchment paper, and butter the paper as well.",
303 | "videoURL": "",
304 | "thumbnailURL": ""
305 | },
306 | {
307 | "id": 2,
308 | "shortDescription": "Combine dry ingredients.",
309 | "description": "2. Combine the cake flour, 400 grams (2 cups) of sugar, baking powder, and 1 teaspoon of salt in the bowl of a stand mixer. Using the paddle attachment, beat at low speed until the dry ingredients are mixed together, about one minute",
310 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffde28_1-mix-all-dry-ingredients-yellow-cake/1-mix-all-dry-ingredients-yellow-cake.mp4",
311 | "thumbnailURL": ""
312 | },
313 | {
314 | "id": 3,
315 | "shortDescription": "Prepare wet ingredients.",
316 | "description": "3. Lightly beat together the egg yolks, 1 tablespoon of vanilla, and 80 grams (1/3 cup) of the milk in a small bowl.",
317 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffde36_2-mix-all-wet-ingredients-yellow-cake/2-mix-all-wet-ingredients-yellow-cake.mp4",
318 | "thumbnailURL": ""
319 | },
320 | {
321 | "id": 4,
322 | "shortDescription": "Add butter and milk to dry ingredients.",
323 | "description": "4. Add 283 grams (20 tablespoons) of butter and 243 grams (1 cup) of milk to the dry ingredients. Beat at low speed until the dry ingredients are fully moistened, using a spatula to help with the incorporation if necessary. Then beat at medium speed for 90 seconds.",
324 | "videoURL": "",
325 | "thumbnailURL": ""
326 | },
327 | {
328 | "id": 5,
329 | "shortDescription": "Add egg mixture to batter.",
330 | "description": "5. Scrape down the sides of the bowl. Add the egg mixture to the batter in three batches, beating for 20 seconds each time and then scraping down the sides.",
331 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffde36_2-mix-all-wet-ingredients-yellow-cake/2-mix-all-wet-ingredients-yellow-cake.mp4",
332 | "thumbnailURL": ""
333 | },
334 | {
335 | "id": 6,
336 | "shortDescription": "Pour batter into pans.",
337 | "description": "6. Pour the mixture in two even batches into the prepared pans. Bake for 25 minutes or until a tester comes out of the cake clean. The cake should only start to shrink away from the sides of the pan after it comes out of the oven.",
338 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffde43_5-add-mixed-batter-to-baking-pans-yellow-cake/5-add-mixed-batter-to-baking-pans-yellow-cake.mp4",
339 | "thumbnailURL": ""
340 | },
341 | {
342 | "id": 7,
343 | "shortDescription": "Begin making buttercream.",
344 | "description": "7. Once the cake is cool, it's time to make the buttercream. You'll start by bringing an inch of water to a boil in a small saucepan. You'll want to use a saucepan that is small enough that when you set the bowl of your stand mixer in it, the bowl does not touch the bottom of the pot.",
345 | "videoURL": "",
346 | "thumbnailURL": ""
347 | },
348 | {
349 | "id": 8,
350 | "shortDescription": "Prepare egg whites.",
351 | "description": "8. Whisk together the egg whites and remaining 300 grams (1.5 cups) of sugar in the bowl of a stand mixer until combined. Set the bowl over the top of the boiling water and continue whisking the egg white mixture until it feels hot to the touch and the sugar is totally dissolved (if you have a reliable thermometer, it should read 150\u00b0F). ",
352 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/5901299d_6-srir-egg-whites-for-frosting-yellow-cake/6-srir-egg-whites-for-frosting-yellow-cake.mp4",
353 | "thumbnailURL": ""
354 | },
355 | {
356 | "id": 9,
357 | "shortDescription": "Beat egg whites to stiff peaks.",
358 | "description": "9. Remove the bowl from the pot, and using the whisk attachment of your stand mixer, beat the egg white mixture on medium-high speed until stiff peaks form and the outside of the bowl reaches room temperature.",
359 | "videoURL": "",
360 | "thumbnailURL": ""
361 | },
362 | {
363 | "id": 10,
364 | "shortDescription": "Add butter to egg white mixture.",
365 | "description": "10. Keeping the mixer at medium speed, add the butter one piece at a time to the egg white mixture, waiting 5 to 10 seconds between additions. If the mixture starts to look curdled, just keep beating it! It will come together once it has been mixed enough and has enough butter added. ",
366 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/590129a3_9-mix-in-butter-for-frosting-yellow-cake/9-mix-in-butter-for-frosting-yellow-cake.mp4",
367 | "thumbnailURL": ""
368 | },
369 | {
370 | "id": 11,
371 | "shortDescription": "Finish buttercream icing.",
372 | "description": "11. With the mixer still running, pour the melted chocolate into the buttercream. Then add the remaining tablespoon of vanilla and 1/2 teaspoon of salt. Beat at high speed for 30 seconds to ensure the buttercream is well-mixed.",
373 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/590129a5_10-mix-in-melted-chocolate-for-frosting-yellow-cake/10-mix-in-melted-chocolate-for-frosting-yellow-cake.mp4",
374 | "thumbnailURL": ""
375 | },
376 | {
377 | "id": 12,
378 | "shortDescription": "Frost cakes.",
379 | "description": "12. Frost your cake! Use a serrated knife to cut each cooled cake layer in half (so that you have 4 cake layers). Frost in between the layers, the sides of the cake, and the top of the cake. Then eat it!",
380 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/590129ad_17-frost-all-around-cake-yellow-cake/17-frost-all-around-cake-yellow-cake.mp4",
381 | "thumbnailURL": ""
382 | }
383 | ],
384 | "servings": 8,
385 | "image": "https://raw.githubusercontent.com/bapspatil/CaptainChef/master/resources/yellow_cake.jpg"
386 | },
387 | {
388 | "id": 4,
389 | "name": "Cheesecake",
390 | "ingredients": [
391 | {
392 | "quantity": 2,
393 | "measure": "CUP",
394 | "ingredient": "Graham Cracker crumbs"
395 | },
396 | {
397 | "quantity": 6,
398 | "measure": "TBLSP",
399 | "ingredient": "unsalted butter, melted"
400 | },
401 | {
402 | "quantity": 250,
403 | "measure": "G",
404 | "ingredient": "granulated sugar"
405 | },
406 | {
407 | "quantity": 1,
408 | "measure": "TSP",
409 | "ingredient": "salt"
410 | },
411 | {
412 | "quantity": 4,
413 | "measure": "TSP",
414 | "ingredient": "vanilla,divided"
415 | },
416 | {
417 | "quantity": 680,
418 | "measure": "G",
419 | "ingredient": "cream cheese, softened"
420 | },
421 | {
422 | "quantity": 3,
423 | "measure": "UNIT",
424 | "ingredient": "large whole eggs"
425 | },
426 | {
427 | "quantity": 2,
428 | "measure": "UNIT",
429 | "ingredient": "large egg yolks"
430 | },
431 | {
432 | "quantity": 250,
433 | "measure": "G",
434 | "ingredient": "heavy cream"
435 | }
436 | ],
437 | "steps": [
438 | {
439 | "id": 0,
440 | "shortDescription": "Recipe Introduction",
441 | "description": "Recipe Introduction",
442 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffdae8_-intro-cheesecake/-intro-cheesecake.mp4",
443 | "thumbnailURL": ""
444 | },
445 | {
446 | "id": 1,
447 | "shortDescription": "Starting prep.",
448 | "description": "1. Preheat the oven to 350\u00b0F. Grease the bottom of a 9-inch round springform pan with butter. ",
449 | "videoURL": "",
450 | "thumbnailURL": ""
451 | },
452 | {
453 | "id": 2,
454 | "shortDescription": "Prep the cookie crust.",
455 | "description": "2. To assemble the crust, whisk together the cookie crumbs, 50 grams (1/4 cup) of sugar, and 1/2 teaspoon of salt for the crust in a medium bowl. Stir in the melted butter and 1 teaspoon of vanilla extract until uniform. ",
456 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffdb1d_2-form-crust-to-bottom-of-pan-cheesecake/2-form-crust-to-bottom-of-pan-cheesecake.mp4",
457 | "thumbnailURL": ""
458 | },
459 | {
460 | "id": 3,
461 | "shortDescription": "Start water bath.",
462 | "description": "3. Fill a large roasting pan with a few inches of hot water and place it on the bottom rack of the oven.",
463 | "videoURL": "",
464 | "thumbnailURL": ""
465 | },
466 | {
467 | "id": 4,
468 | "shortDescription": "Prebake cookie crust. ",
469 | "description": "4. Press the cookie mixture into the bottom and slightly up the sides of the prepared pan. Bake for 11 minutes and then let cool.",
470 | "videoURL": "",
471 | "thumbnailURL": ""
472 | },
473 | {
474 | "id": 5,
475 | "shortDescription": "Mix cream cheese and dry ingredients.",
476 | "description": "5. Beat the cream cheese, remaining 200 grams (1 cup) of sugar, and remaining 1/2 teaspoon salt on medium speed in a stand mixer with the paddle attachment for 3 minutes (or high speed if using a hand mixer). ",
477 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffdb3a_3-mix-sugar-salt-together-cheesecake/3-mix-sugar-salt-together-cheesecake.mp4",
478 | "thumbnailURL": ""
479 | },
480 | {
481 | "id": 6,
482 | "shortDescription": "Add eggs.",
483 | "description": "6. Scrape down the sides of the pan. Add in the eggs one at a time, beating each one on medium-low speed just until incorporated. Scrape down the sides and bottom of the bowl. Add in both egg yolks and beat until just incorporated. ",
484 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffdb55_4-add-eggs-mix-cheesecake/4-add-eggs-mix-cheesecake.mp4",
485 | "thumbnailURL": ""
486 | },
487 | {
488 | "id": 7,
489 | "shortDescription": "Add heavy cream and vanilla.",
490 | "description": "7. Add the cream and remaining tablespoon of vanilla to the batter and beat on medium-low speed until just incorporated. ",
491 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffdb72_5-mix-vanilla-cream-together-cheesecake/5-mix-vanilla-cream-together-cheesecake.mp4",
492 | "thumbnailURL": ""
493 | },
494 | {
495 | "id": 8,
496 | "shortDescription": "Pour batter in pan.",
497 | "description": "8. Pour the batter into the cooled cookie crust. Bang the pan on a counter or sturdy table a few times to release air bubbles from the batter.",
498 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffdb88_6-add-the-batter-to-the-pan-w-the-crumbs-cheesecake/6-add-the-batter-to-the-pan-w-the-crumbs-cheesecake.mp4",
499 | "thumbnailURL": ""
500 | },
501 | {
502 | "id": 9,
503 | "shortDescription": "Bake the cheesecake.",
504 | "description": "9. Bake the cheesecake on a middle rack of the oven above the roasting pan full of water for 50 minutes. ",
505 | "videoURL": "",
506 | "thumbnailURL": ""
507 | },
508 | {
509 | "id": 10,
510 | "shortDescription": "Turn off oven and leave cake in.",
511 | "description": "10. Turn off the oven but keep the cheesecake in the oven with the door closed for 50 more minutes.",
512 | "videoURL": "",
513 | "thumbnailURL": ""
514 | },
515 | {
516 | "id": 11,
517 | "shortDescription": "Remove from oven and cool at room temperature.",
518 | "description": "11. Take the cheesecake out of the oven. It should look pale yellow or golden on top and be set but still slightly jiggly. Let it cool to room temperature. ",
519 | "videoURL": "",
520 | "thumbnailURL": ""
521 | },
522 | {
523 | "id": 12,
524 | "shortDescription": "Final cooling and set.",
525 | "description": "12. Cover the cheesecake with plastic wrap, not allowing the plastic to touch the top of the cake, and refrigerate it for at least 8 hours. Then it's ready to serve!",
526 | "videoURL": "https://d17h27t6h515a5.cloudfront.net/topher/2017/April/58ffdbac_9-finished-product-cheesecake/9-finished-product-cheesecake.mp4",
527 | "thumbnailURL": ""
528 | }
529 | ],
530 | "servings": 8,
531 | "image": "https://raw.githubusercontent.com/bapspatil/CaptainChef/master/resources/cheesecake.jpg"
532 | }
533 | ]
534 |
--------------------------------------------------------------------------------
/resources/brownie.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/resources/brownie.jpg
--------------------------------------------------------------------------------
/resources/cheesecake.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/resources/cheesecake.jpg
--------------------------------------------------------------------------------
/resources/fallback_recipe_thumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/resources/fallback_recipe_thumbnail.png
--------------------------------------------------------------------------------
/resources/nutella_pie.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/resources/nutella_pie.jpg
--------------------------------------------------------------------------------
/resources/yellow_cake.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bapspatil/CaptainChef/2ecdd8e3d13a9f434d1649d0cd55c91c1c2db78a/resources/yellow_cake.jpg
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------