├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ ├── assets
│ │ ├── ingredient_analysis.json
│ │ ├── more_items_search_result.json
│ │ ├── recipe.json
│ │ ├── recipe_analysis.json
│ │ ├── search_result.json
│ │ └── search_result_empty.json
│ └── java
│ │ └── com
│ │ └── mlsdev
│ │ └── recipefinder
│ │ ├── AssetUtils.java
│ │ ├── MainActivityTest.java
│ │ ├── MockApp.java
│ │ ├── TestRunner.java
│ │ ├── di
│ │ ├── MockApplicationComponent.java
│ │ ├── MockApplicationInjector.java
│ │ └── module
│ │ │ ├── MockApiModule.java
│ │ │ └── MockDataSourceModule.java
│ │ └── view
│ │ ├── analysenutrition
│ │ ├── ingredient
│ │ │ └── IngredientAnalysisFragmentTest.java
│ │ └── recipe
│ │ │ └── RecipeAnalysisFragmentTest.java
│ │ └── searchrecipes
│ │ └── SearchRecipesFragmentTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ ├── 1.png
│ │ ├── 10.png
│ │ ├── 11.png
│ │ ├── 2.png
│ │ ├── 3.png
│ │ ├── 4.png
│ │ ├── 5.png
│ │ ├── 6.png
│ │ ├── 7.png
│ │ ├── 8.png
│ │ └── 9.png
│ ├── ic_launcher-web.png
│ ├── java
│ │ └── com
│ │ │ └── mlsdev
│ │ │ └── recipefinder
│ │ │ ├── RecipeApplication.java
│ │ │ ├── data
│ │ │ ├── entity
│ │ │ │ ├── nutrition
│ │ │ │ │ ├── Nutrient.java
│ │ │ │ │ ├── NutritionAnalysisResult.java
│ │ │ │ │ ├── RecipeAnalysisParams.java
│ │ │ │ │ └── TotalNutrients.java
│ │ │ │ └── recipe
│ │ │ │ │ ├── Error.java
│ │ │ │ │ ├── Hit.java
│ │ │ │ │ ├── Ingredient.java
│ │ │ │ │ ├── Params.java
│ │ │ │ │ ├── Recipe.java
│ │ │ │ │ ├── SearchResult.java
│ │ │ │ │ ├── TotalDaily.java
│ │ │ │ │ └── stringwrapper
│ │ │ │ │ ├── DietLabel.java
│ │ │ │ │ ├── HealthLabel.java
│ │ │ │ │ └── Label.java
│ │ │ └── source
│ │ │ │ ├── BaseDataSource.java
│ │ │ │ ├── BaseObserver.java
│ │ │ │ ├── DataSource.java
│ │ │ │ ├── local
│ │ │ │ ├── LocalDataSource.java
│ │ │ │ └── roomdb
│ │ │ │ │ ├── AppDatabase.java
│ │ │ │ │ ├── converter
│ │ │ │ │ └── Converter.java
│ │ │ │ │ └── dao
│ │ │ │ │ ├── IngredientDao.java
│ │ │ │ │ ├── NutrientDao.java
│ │ │ │ │ ├── RecipeDao.java
│ │ │ │ │ └── TotalNutrientsDao.java
│ │ │ │ ├── remote
│ │ │ │ ├── NutritionAnalysisService.java
│ │ │ │ ├── ParameterKeys.java
│ │ │ │ ├── PathConstants.java
│ │ │ │ ├── RemoteDataSource.java
│ │ │ │ └── SearchRecipesService.java
│ │ │ │ └── repository
│ │ │ │ └── DataRepository.java
│ │ │ ├── di
│ │ │ ├── ApplicationInjector.java
│ │ │ ├── Injectable.java
│ │ │ ├── component
│ │ │ │ └── ApplicationComponent.java
│ │ │ └── module
│ │ │ │ ├── ApiModule.java
│ │ │ │ ├── DataSourceModule.java
│ │ │ │ ├── DatabaseModule.java
│ │ │ │ ├── FragmentBuilderModule.java
│ │ │ │ ├── MainActivityModule.java
│ │ │ │ ├── RecipeAnalysisActivityModule.java
│ │ │ │ ├── UtilsModule.java
│ │ │ │ ├── ViewModelKey.java
│ │ │ │ └── ViewModelModule.java
│ │ │ └── view
│ │ │ ├── ActionListener.java
│ │ │ ├── BaseActivity.java
│ │ │ ├── BottomNavigationItemSelectedListener.java
│ │ │ ├── Extras.java
│ │ │ ├── MainActivity.java
│ │ │ ├── NavigationController.java
│ │ │ ├── OnKeyboardStateChangedListener.java
│ │ │ ├── analysenutrition
│ │ │ ├── AnalyseNutritionFragment.java
│ │ │ ├── adapter
│ │ │ │ ├── BaseViewHolder.java
│ │ │ │ └── ProgressViewHolder.java
│ │ │ ├── ingredient
│ │ │ │ ├── IngredientAnalysisFragment.java
│ │ │ │ └── IngredientAnalysisViewModel.java
│ │ │ └── recipe
│ │ │ │ ├── AddIngredientDialogFragment.java
│ │ │ │ ├── IngredientsAdapter.java
│ │ │ │ ├── OnAddIngredientClickListener.java
│ │ │ │ ├── RecipeAnalysisDetailsActivity.java
│ │ │ │ ├── RecipeAnalysisDetailsViewModel.java
│ │ │ │ ├── RecipeAnalysisFragment.java
│ │ │ │ └── RecipeAnalysisViewModel.java
│ │ │ ├── bindingutils
│ │ │ └── DataBinder.java
│ │ │ ├── enums
│ │ │ └── TabItemType.java
│ │ │ ├── favoriterecipes
│ │ │ ├── FavoriteRecipesFragment.java
│ │ │ └── FavoritesViewModel.java
│ │ │ ├── fragment
│ │ │ ├── BaseFragment.java
│ │ │ └── RecipeListFragment.java
│ │ │ ├── fragments
│ │ │ └── TabFragment.java
│ │ │ ├── listener
│ │ │ ├── OnDataLoadedListener.java
│ │ │ └── OnIngredientAnalyzedListener.java
│ │ │ ├── message
│ │ │ ├── Message.java
│ │ │ ├── ProgressDialogMessage.java
│ │ │ └── SnackbarMessage.java
│ │ │ ├── recipedetails
│ │ │ ├── RecipeDetailsFragment.java
│ │ │ └── RecipeViewModel.java
│ │ │ ├── searchrecipes
│ │ │ ├── FilterDialogFragment.java
│ │ │ ├── RecipeListAdapter.java
│ │ │ ├── RecipeListItemViewModel.java
│ │ │ ├── SearchRecipeFragment.java
│ │ │ └── SearchViewModel.java
│ │ │ ├── utils
│ │ │ ├── DiagramUtils.java
│ │ │ ├── ParamsHelper.java
│ │ │ └── UtilsUI.java
│ │ │ └── viewmodel
│ │ │ ├── BaseViewModel.java
│ │ │ └── ViewModelFactory.java
│ └── res
│ │ ├── anim
│ │ ├── fade_in.xml
│ │ └── fade_out.xml
│ │ ├── color
│ │ └── tab_item_text_color.xml
│ │ ├── drawable-v21
│ │ ├── recipe_list_item_foreground.xml
│ │ ├── tab_item_background.xml
│ │ └── toolbar_item_selector.xml
│ │ ├── drawable-xxhdpi
│ │ ├── btn_cancel.png
│ │ ├── ic_favorite_checked.png
│ │ ├── ic_favorite_normal.png
│ │ ├── ic_navigation_analyse.png
│ │ ├── ic_navigation_favorites.png
│ │ ├── ic_navigation_search.png
│ │ └── ic_nothing_found.png
│ │ ├── drawable-xxxhdpi
│ │ ├── ic_close.png
│ │ ├── ic_empty_view.png
│ │ ├── ic_filter.png
│ │ └── ic_search.png
│ │ ├── drawable
│ │ ├── primary_color_shape.xml
│ │ ├── primary_dark_color_shape.xml
│ │ ├── progress_bar_background.xml
│ │ ├── progress_drawable.xml
│ │ ├── recipe_item_title_bg.xml
│ │ ├── recipe_list_item_foreground.xml
│ │ ├── tab_item_background.xml
│ │ ├── toolbar_item_selector.xml
│ │ └── top_shadow.xml
│ │ ├── layout-land
│ │ ├── fragment_ingredient_analysis.xml
│ │ └── fragment_recipe_analysis.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── activity_recipe_analysis_details.xml
│ │ ├── add_ingredient_button.xml
│ │ ├── dialog_fragment_add_ingredient.xml
│ │ ├── dialog_fragment_search_filter.xml
│ │ ├── fragment_analyse_nutrition.xml
│ │ ├── fragment_favorite_recipes.xml
│ │ ├── fragment_ingredient_analysis.xml
│ │ ├── fragment_recipe_analysis.xml
│ │ ├── fragment_recipe_details.xml
│ │ ├── fragment_search_recipes.xml
│ │ ├── ingredient_list_item.xml
│ │ ├── progress_view.xml
│ │ └── recipe_list_item.xml
│ │ ├── menu
│ │ ├── navigation.xml
│ │ └── options_menu.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── transition
│ │ └── change_image_transform.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── mlsdev
│ └── recipefinder
│ ├── NutrientTest.java
│ └── ParamsHelperTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/*
5 | .DS_Store
6 | /build
7 | /captures
8 | .externalNativeBuild
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | jdk: oraclejdk8
3 | android:
4 | components:
5 | - tools
6 | - platform-tools
7 | - build-tools-25.0.3
8 | - android-25
9 | - extra-google-m2repository
10 | - extra-android-m2repository
11 | licenses:
12 | - android-sdk-preview-license-.+
13 | - android-sdk-license-.+
14 | - google-gdk-license-.+
15 | script:
16 | - ./gradlew build
17 | before_install:
18 | - chmod +x gradlew
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Sergey Glebov
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # RecipeFinder
4 |
5 | This is a sample app with **MVVM**, **RxJava** and **Data Binding**
6 |
7 | ## [Kotlin version](https://github.com/MLSDev/RecipeFinderKotlinVersion)
8 |
9 | ## Authors
10 | * [Sergey Petrosyuk](mailto:petrosyuk@mlsdev.com), MLSDev
11 |
12 |
13 |
14 | ## Used libraries
15 | * [MockWebServer](https://github.com/square/okhttp/tree/master/mockwebserver): mock a server responses
16 | * [OkHttp](https://github.com/square/okhttp)
17 | * [Retrofit](http://square.github.io/retrofit/): for the network requests
18 | * [RxJava 2](https://github.com/ReactiveX/RxJava)
19 | * [RxAndroid 2](https://github.com/ReactiveX/RxAndroid)
20 | * [Glide](https://github.com/bumptech/glide): for image loading
21 | * [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart): charts and diagrams
22 | * [ORMLite](http://ormlite.com/): local data storage
23 |
24 | ## Authors
25 | * [Sergey Petrosyuk](mailto:petrosyuk@mlsdev.com), MLSDev
26 |
27 | ## About MLSDev
28 |
29 | [
][mlsdev]
30 |
31 | RecipeFinder is maintained by MLSDev, Inc. We specialize in providing all-in-one solution in mobile and web development. Our team follows Lean principles and works according to agile methodologies to deliver the best results reducing the budget for development and its timeline.
32 |
33 | Find out more [here][mlsdev] and don't hesitate to [contact us][contact]!
34 |
35 | [mlsdev]: http://mlsdev.com
36 | [contact]: http://mlsdev.com/contact_us
37 | [github-frederikos]: https://github.com/SerhiyPetrosyuk
38 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/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 /Users/serhii/Library/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 |
--------------------------------------------------------------------------------
/app/src/androidTest/assets/search_result_empty.json:
--------------------------------------------------------------------------------
1 | {
2 | "q": "chicken",
3 | "from": 0,
4 | "to": 10,
5 | "params": {
6 | "sane": [],
7 | "to": [
8 | "10"
9 | ],
10 | "q": [
11 | "chicken"
12 | ],
13 | "app_id": [
14 | "75347af5"
15 | ],
16 | "app_key": [
17 | "c12154e41f974c51a56fad5a256c27f2"
18 | ],
19 | "from": [
20 | "0"
21 | ]
22 | },
23 | "more": true,
24 | "count": 1000,
25 | "hits": []
26 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/mlsdev/recipefinder/AssetUtils.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder;
2 |
3 | import android.content.Context;
4 |
5 | import com.google.gson.Gson;
6 | import com.mlsdev.recipefinder.data.entity.nutrition.NutritionAnalysisResult;
7 | import com.mlsdev.recipefinder.data.entity.recipe.Hit;
8 | import com.mlsdev.recipefinder.data.entity.recipe.Recipe;
9 | import com.mlsdev.recipefinder.data.entity.recipe.SearchResult;
10 |
11 | import java.io.IOException;
12 | import java.io.InputStream;
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | public class AssetUtils {
17 |
18 | public static SearchResult getSearchResult(Context context) {
19 | return new Gson().fromJson(getSearchResultJsonData(context), SearchResult.class);
20 | }
21 |
22 | public static List getRecipeList(Context context) {
23 | return getResipesFromSearchResult(getSearchResult(context));
24 | }
25 |
26 | public static String getSearchResultJsonData(Context context) {
27 | return getJsonStringFromAssets(context, "search_result.json");
28 | }
29 |
30 | public static String getEmptySearchResultJsonData(Context context) {
31 | return getJsonStringFromAssets(context, "search_result_empty.json");
32 | }
33 |
34 | public static String getMoreRecipesJsonData(Context context) {
35 | return getJsonStringFromAssets(context, "more_items_search_result.json");
36 | }
37 |
38 | public static List getMoreRecipeList(Context context) {
39 | return getResipesFromSearchResult(new Gson().fromJson(getMoreRecipesJsonData(context), SearchResult.class));
40 | }
41 |
42 | public static Recipe getRecipeEntity(Context context) {
43 | return new Gson().fromJson(getJsonStringFromAssets(context, "recipe.json"), Recipe.class);
44 | }
45 |
46 | public static String getIngredientAnalysisJsonData(Context context) {
47 | return getJsonStringFromAssets(context, "ingredient_analysis.json");
48 | }
49 |
50 | public static NutritionAnalysisResult getNutritionAnalysisResult(Context context) {
51 | return new Gson().fromJson(getIngredientAnalysisJsonData(context), NutritionAnalysisResult.class);
52 | }
53 |
54 | public static String getRecipeAnalysisJsonData(Context context) {
55 | return getJsonStringFromAssets(context, "recipe_analysis.json");
56 | }
57 |
58 | public static NutritionAnalysisResult getRecipeAnalysisResult(Context context) {
59 | return new Gson().fromJson(getRecipeAnalysisJsonData(context), NutritionAnalysisResult.class);
60 | }
61 |
62 | private static List getResipesFromSearchResult(SearchResult searchResult) {
63 | List recipes = new ArrayList<>();
64 | for (Hit hit : searchResult.getHits())
65 | recipes.add(hit.getRecipe());
66 | return recipes;
67 | }
68 |
69 | private static String getJsonStringFromAssets(Context context, String fileName) {
70 | String json = null;
71 | try {
72 | InputStream inputStream = context.getAssets().open(fileName);
73 | int size = inputStream.available();
74 | byte[] buffer = new byte[size];
75 | inputStream.read(buffer);
76 | inputStream.close();
77 | json = new String(buffer, "UTF-8");
78 | } catch (IOException e) {
79 | e.printStackTrace();
80 | }
81 |
82 | return json;
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/mlsdev/recipefinder/MainActivityTest.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder;
2 |
3 | import android.support.annotation.IdRes;
4 | import android.support.test.espresso.Espresso;
5 | import android.support.test.espresso.action.ViewActions;
6 | import android.support.test.espresso.assertion.ViewAssertions;
7 | import android.support.test.espresso.matcher.ViewMatchers;
8 | import android.support.test.rule.ActivityTestRule;
9 |
10 | import com.mlsdev.recipefinder.view.MainActivity;
11 |
12 | import org.junit.Rule;
13 | import org.junit.Test;
14 |
15 | public class MainActivityTest {
16 | @Rule
17 | public ActivityTestRule testRule = new ActivityTestRule<>(MainActivity.class);
18 |
19 | @Test
20 | public void testSelectNavigationTab() {
21 | // Select the Analyse Nutrition tab
22 | performClickUponTab(R.id.action_analyse_nutrition);
23 | assertTabOpened(R.id.ll_analyse_nutrition);
24 |
25 | // Select the Favorite Recipes tab
26 | performClickUponTab(R.id.action_favorites);
27 | assertTabOpened(R.id.rl_favorite_recipes);
28 |
29 | // Select the Search Recipes tab
30 | performClickUponTab(R.id.action_search_recipe);
31 | assertTabOpened(R.id.cl_search_recipes);
32 | }
33 |
34 | private void performClickUponTab(@IdRes int tabId) {
35 | Espresso.onView(ViewMatchers.withId(tabId)).perform(ViewActions.click());
36 | }
37 |
38 | private void assertTabOpened(@IdRes int layoutId) {
39 | Espresso.onView(ViewMatchers.withId(layoutId))
40 | .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/mlsdev/recipefinder/MockApp.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder;
2 |
3 | import com.mlsdev.recipefinder.di.MockApplicationComponent;
4 | import com.mlsdev.recipefinder.di.MockApplicationInjector;
5 |
6 | public class MockApp extends RecipeApplication {
7 | private MockApplicationComponent component;
8 |
9 | @Override
10 | public void onCreate() {
11 | super.onCreate();
12 | instance = this;
13 | component = MockApplicationInjector.init(this);
14 | }
15 |
16 | public MockApplicationComponent getComponent() {
17 | return component;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/mlsdev/recipefinder/TestRunner.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 | import android.os.IBinder;
7 | import android.support.test.runner.AndroidJUnitRunner;
8 |
9 | import java.lang.reflect.Method;
10 |
11 | import static android.content.pm.PackageManager.PERMISSION_GRANTED;
12 |
13 | public class TestRunner extends AndroidJUnitRunner {
14 |
15 | @Override
16 | public Application newApplication(ClassLoader cl, String className, Context context)
17 | throws InstantiationException, IllegalAccessException, ClassNotFoundException {
18 | return super.newApplication(cl, MockApp.class.getName(), context);
19 | }
20 |
21 | /*
22 | *Fix android emulator issues on CIs
23 | */
24 | @Override
25 | public void onStart() {
26 | runOnMainSync(new Runnable() {
27 | @Override
28 | public void run() {
29 | Context app = TestRunner.this.getTargetContext().getApplicationContext();
30 | TestRunner.this.disableAnimations(app);
31 | }
32 | });
33 |
34 | super.onStart();
35 | }
36 |
37 |
38 | @Override
39 | public void finish(int resultCode, Bundle results) {
40 | super.finish(resultCode, results);
41 | enableAnimations(getContext());
42 | }
43 |
44 |
45 | void disableAnimations(Context context) {
46 | int permStatus = context.checkCallingOrSelfPermission(android.Manifest.permission.SET_ANIMATION_SCALE);
47 | if (permStatus == PERMISSION_GRANTED) {
48 | setSystemAnimationsScale(0.0f);
49 | }
50 | }
51 |
52 | void enableAnimations(Context context) {
53 | int permStatus = context.checkCallingOrSelfPermission(android.Manifest.permission.SET_ANIMATION_SCALE);
54 | if (permStatus == PERMISSION_GRANTED) {
55 | setSystemAnimationsScale(1.0f);
56 | }
57 | }
58 |
59 | private void setSystemAnimationsScale(float animationScale) {
60 | try {
61 | Class> windowManagerStubClazz = Class.forName("android.view.IWindowManager$Stub");
62 | Method asInterface = windowManagerStubClazz.getDeclaredMethod("asInterface", IBinder.class);
63 | Class> serviceManagerClazz = Class.forName("android.os.ServiceManager");
64 | Method getService = serviceManagerClazz.getDeclaredMethod("getService", String.class);
65 | Class> windowManagerClazz = Class.forName("android.view.IWindowManager");
66 | Method setAnimationScales = windowManagerClazz.getDeclaredMethod("setAnimationScales", float[].class);
67 | Method getAnimationScales = windowManagerClazz.getDeclaredMethod("getAnimationScales");
68 |
69 | IBinder windowManagerBinder = (IBinder) getService.invoke(null, "window");
70 | Object windowManagerObj = asInterface.invoke(null, windowManagerBinder);
71 | float[] currentScales = (float[]) getAnimationScales.invoke(windowManagerObj);
72 | for (int i = 0; i < currentScales.length; i++) {
73 | currentScales[i] = animationScale;
74 | }
75 | setAnimationScales.invoke(windowManagerObj, new Object[]{currentScales});
76 | } catch (Exception e) {
77 | }
78 | }
79 |
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/mlsdev/recipefinder/di/MockApplicationComponent.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di;
2 |
3 | import android.app.Application;
4 |
5 | import com.mlsdev.recipefinder.di.module.MockApiModule;
6 | import com.mlsdev.recipefinder.MockApp;
7 | import com.mlsdev.recipefinder.di.module.MockDataSourceModule;
8 | import com.mlsdev.recipefinder.di.module.DatabaseModule;
9 | import com.mlsdev.recipefinder.di.module.MainActivityModule;
10 | import com.mlsdev.recipefinder.di.module.RecipeAnalysisActivityModule;
11 | import com.mlsdev.recipefinder.di.module.UtilsModule;
12 | import com.mlsdev.recipefinder.di.module.ViewModelModule;
13 | import com.mlsdev.recipefinder.view.analysenutrition.ingredient.IngredientAnalysisFragmentTest;
14 | import com.mlsdev.recipefinder.view.analysenutrition.recipe.RecipeAnalysisFragmentTest;
15 | import com.mlsdev.recipefinder.view.searchrecipes.SearchRecipesFragmentTest;
16 |
17 | import javax.inject.Singleton;
18 |
19 | import dagger.BindsInstance;
20 | import dagger.Component;
21 | import dagger.android.AndroidInjectionModule;
22 |
23 | @Singleton
24 | @Component(modules = {
25 | AndroidInjectionModule.class,
26 | UtilsModule.class,
27 | MockDataSourceModule.class,
28 | DatabaseModule.class,
29 | MockApiModule.class,
30 | MainActivityModule.class,
31 | RecipeAnalysisActivityModule.class,
32 | ViewModelModule.class})
33 | public interface MockApplicationComponent {
34 |
35 | @Component.Builder
36 | interface Builder {
37 | @BindsInstance
38 | Builder application(Application application);
39 |
40 | MockApplicationComponent build();
41 | }
42 |
43 | void inject(MockApp application);
44 | void inject(SearchRecipesFragmentTest fragmentTest);
45 | void inject(IngredientAnalysisFragmentTest fragmentTest);
46 | void inject(RecipeAnalysisFragmentTest fragmentTest);
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/mlsdev/recipefinder/di/MockApplicationInjector.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di;
2 |
3 | import android.app.Activity;
4 | import android.app.Application;
5 | import android.os.Bundle;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.app.FragmentActivity;
8 | import android.support.v4.app.FragmentManager;
9 |
10 | import com.mlsdev.recipefinder.MockApp;
11 |
12 | import dagger.android.AndroidInjection;
13 | import dagger.android.support.AndroidSupportInjection;
14 | import dagger.android.support.HasSupportFragmentInjector;
15 |
16 | public class MockApplicationInjector {
17 |
18 | private MockApplicationInjector() {
19 | }
20 |
21 | public static MockApplicationComponent init(MockApp application) {
22 | MockApplicationComponent component = DaggerMockApplicationComponent.builder()
23 | .application(application)
24 | .build();
25 |
26 | component.inject(application);
27 |
28 | application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
29 | @Override
30 | public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
31 | handleActivity(activity);
32 | }
33 |
34 | @Override
35 | public void onActivityStarted(Activity activity) {
36 |
37 | }
38 |
39 | @Override
40 | public void onActivityResumed(Activity activity) {
41 |
42 | }
43 |
44 | @Override
45 | public void onActivityPaused(Activity activity) {
46 |
47 | }
48 |
49 | @Override
50 | public void onActivityStopped(Activity activity) {
51 |
52 | }
53 |
54 | @Override
55 | public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
56 |
57 | }
58 |
59 | @Override
60 | public void onActivityDestroyed(Activity activity) {
61 |
62 | }
63 | });
64 |
65 | return component;
66 | }
67 |
68 | private static void handleActivity(Activity activity) {
69 |
70 | if (activity instanceof HasSupportFragmentInjector) {
71 | AndroidInjection.inject(activity);
72 | }
73 |
74 | if (activity instanceof FragmentActivity) {
75 | ((FragmentActivity) activity).getSupportFragmentManager()
76 | .registerFragmentLifecycleCallbacks(new FragmentManager.FragmentLifecycleCallbacks() {
77 | @Override
78 | public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
79 | if (f instanceof Injectable)
80 | AndroidSupportInjection.inject(f);
81 | }
82 | }, true);
83 | }
84 |
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/mlsdev/recipefinder/di/module/MockApiModule.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di.module;
2 |
3 | import com.mlsdev.recipefinder.data.source.remote.NutritionAnalysisService;
4 | import com.mlsdev.recipefinder.data.source.remote.SearchRecipesService;
5 | import com.mlsdev.recipefinder.di.module.ApiModule;
6 |
7 | import org.mockito.Mockito;
8 |
9 | import javax.inject.Singleton;
10 |
11 | import dagger.Module;
12 | import dagger.Provides;
13 |
14 | @Module
15 | public class MockApiModule extends ApiModule {
16 |
17 | @Provides
18 | @Singleton
19 | SearchRecipesService provideSearchRecipesService() {
20 | return Mockito.mock(SearchRecipesService.class);
21 | }
22 |
23 | @Provides
24 | @Singleton
25 | NutritionAnalysisService provideNutritionAnalysisService() {
26 | return Mockito.mock(NutritionAnalysisService.class);
27 | }
28 |
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/mlsdev/recipefinder/di/module/MockDataSourceModule.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di.module;
2 |
3 | import com.mlsdev.recipefinder.data.source.DataSource;
4 | import com.mlsdev.recipefinder.data.source.local.LocalDataSource;
5 | import com.mlsdev.recipefinder.data.source.local.roomdb.AppDatabase;
6 | import com.mlsdev.recipefinder.data.source.remote.RemoteDataSource;
7 | import com.mlsdev.recipefinder.data.source.repository.DataRepository;
8 |
9 | import org.mockito.Mockito;
10 |
11 | import javax.inject.Named;
12 | import javax.inject.Singleton;
13 |
14 | import dagger.Module;
15 | import dagger.Provides;
16 |
17 | @Module
18 | public class MockDataSourceModule {
19 | public static final String LOCAL_DATA_SOURCE = "local_data_source";
20 | public static final String REMOTE_DATA_SOURCE = "remote_data_source";
21 |
22 | @Provides
23 | @Singleton
24 | DataRepository provideDataRepository(@Named(LOCAL_DATA_SOURCE) DataSource local,
25 | @Named(REMOTE_DATA_SOURCE) DataSource remote) {
26 | return Mockito.mock(DataRepository.class);
27 | }
28 |
29 | @Provides
30 | @Singleton
31 | @Named(LOCAL_DATA_SOURCE)
32 | DataSource provideLocalDataSource(AppDatabase database) {
33 | return Mockito.mock(LocalDataSource.class);
34 | }
35 |
36 | @Provides
37 | @Singleton
38 | @Named(REMOTE_DATA_SOURCE)
39 | DataSource provideRemoteDataSource() {
40 | return Mockito.mock(RemoteDataSource.class);
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/assets/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/assets/1.png
--------------------------------------------------------------------------------
/app/src/main/assets/10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/assets/10.png
--------------------------------------------------------------------------------
/app/src/main/assets/11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/assets/11.png
--------------------------------------------------------------------------------
/app/src/main/assets/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/assets/2.png
--------------------------------------------------------------------------------
/app/src/main/assets/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/assets/3.png
--------------------------------------------------------------------------------
/app/src/main/assets/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/assets/4.png
--------------------------------------------------------------------------------
/app/src/main/assets/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/assets/5.png
--------------------------------------------------------------------------------
/app/src/main/assets/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/assets/6.png
--------------------------------------------------------------------------------
/app/src/main/assets/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/assets/7.png
--------------------------------------------------------------------------------
/app/src/main/assets/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/assets/8.png
--------------------------------------------------------------------------------
/app/src/main/assets/9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/assets/9.png
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/RecipeApplication.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder;
2 |
3 | import android.app.Activity;
4 | import android.app.Application;
5 |
6 | import com.mlsdev.recipefinder.di.ApplicationInjector;
7 |
8 | import javax.inject.Inject;
9 |
10 | import dagger.android.DispatchingAndroidInjector;
11 | import dagger.android.HasActivityInjector;
12 |
13 | public class RecipeApplication extends Application implements HasActivityInjector {
14 | protected static RecipeApplication instance;
15 |
16 | public static RecipeApplication getInstance() {
17 | return instance;
18 | }
19 |
20 | @Inject
21 | DispatchingAndroidInjector dispatchingAndroidInjector;
22 |
23 | @Override
24 | public void onCreate() {
25 | super.onCreate();
26 | instance = this;
27 | ApplicationInjector.init(this);
28 | }
29 |
30 | @Override
31 | public DispatchingAndroidInjector activityInjector() {
32 | return dispatchingAndroidInjector;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/entity/nutrition/Nutrient.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.entity.nutrition;
2 |
3 | import android.arch.persistence.room.Entity;
4 | import android.arch.persistence.room.Ignore;
5 | import android.arch.persistence.room.PrimaryKey;
6 | import android.os.Parcel;
7 | import android.os.Parcelable;
8 |
9 | import com.mlsdev.recipefinder.view.utils.UtilsUI;
10 |
11 | @Entity(tableName = "nutrients")
12 | public class Nutrient implements Parcelable{
13 | @PrimaryKey(autoGenerate = true)
14 | private long id;
15 | private String label;
16 | private double quantity;
17 | private String unit;
18 |
19 | public Nutrient() {
20 | }
21 |
22 | @Ignore
23 | public Nutrient(String label, double quantity, String unit) {
24 | this.label = label;
25 | this.quantity = quantity;
26 | this.unit = unit;
27 | }
28 |
29 | // region Getters
30 | public long getId() {
31 | return id;
32 | }
33 |
34 | public String getLabel() {
35 | return label;
36 | }
37 |
38 | public double getQuantity() {
39 | return quantity;
40 | }
41 |
42 | public String getUnit() {
43 | return unit;
44 | }
45 | //endregion
46 |
47 | // region Setters
48 | public void setId(long id) {
49 | this.id = id;
50 | }
51 |
52 | public void setLabel(String label) {
53 | this.label = label;
54 | }
55 |
56 | public void setQuantity(double quantity) {
57 | this.quantity = quantity;
58 | }
59 |
60 | public void setUnit(String unit) {
61 | this.unit = unit;
62 | }
63 | // endregion
64 |
65 | public String getFormattedFullText() {
66 | return label + " " + UtilsUI.formatDecimalToString(quantity) + " " + unit;
67 | }
68 |
69 | @Override
70 | public int describeContents() {
71 | return 0;
72 | }
73 |
74 | @Override
75 | public void writeToParcel(Parcel dest, int flags) {
76 | dest.writeLong(this.id);
77 | dest.writeString(this.label);
78 | dest.writeDouble(this.quantity);
79 | dest.writeString(this.unit);
80 | }
81 |
82 | protected Nutrient(Parcel in) {
83 | this.id = in.readLong();
84 | this.label = in.readString();
85 | this.quantity = in.readDouble();
86 | this.unit = in.readString();
87 | }
88 |
89 | public static final Creator CREATOR = new Creator() {
90 | @Override
91 | public Nutrient createFromParcel(Parcel source) {
92 | return new Nutrient(source);
93 | }
94 |
95 | @Override
96 | public Nutrient[] newArray(int size) {
97 | return new Nutrient[size];
98 | }
99 | };
100 | }
101 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/entity/nutrition/NutritionAnalysisResult.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.entity.nutrition;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | public class NutritionAnalysisResult implements Parcelable {
10 | private String uri;
11 | private int calories;
12 | private double totalWeight;
13 | private double yield;
14 | private List dietLabels = new ArrayList<>();
15 | private List healthLabels = new ArrayList<>();
16 | private List cautions = new ArrayList<>();
17 | private TotalNutrients totalNutrients;
18 |
19 | public String getUri() {
20 | return uri;
21 | }
22 |
23 | public int getCalories() {
24 | return calories;
25 | }
26 |
27 | public TotalNutrients getTotalNutrients() {
28 | return totalNutrients;
29 | }
30 |
31 | public double getYield() {
32 | return yield;
33 | }
34 |
35 | public NutritionAnalysisResult() {
36 | }
37 |
38 | @Override
39 | public int describeContents() {
40 | return 0;
41 | }
42 |
43 | @Override
44 | public void writeToParcel(Parcel dest, int flags) {
45 | dest.writeString(this.uri);
46 | dest.writeInt(this.calories);
47 | dest.writeDouble(this.totalWeight);
48 | dest.writeDouble(this.yield);
49 | dest.writeStringList(this.dietLabels);
50 | dest.writeStringList(this.healthLabels);
51 | dest.writeStringList(this.cautions);
52 | dest.writeParcelable(this.totalNutrients, flags);
53 | }
54 |
55 | protected NutritionAnalysisResult(Parcel in) {
56 | this.uri = in.readString();
57 | this.calories = in.readInt();
58 | this.totalWeight = in.readDouble();
59 | this.yield = in.readDouble();
60 | this.dietLabels = in.createStringArrayList();
61 | this.healthLabels = in.createStringArrayList();
62 | this.cautions = in.createStringArrayList();
63 | this.totalNutrients = in.readParcelable(TotalNutrients.class.getClassLoader());
64 | }
65 |
66 | public static final Creator CREATOR = new Creator() {
67 | @Override
68 | public NutritionAnalysisResult createFromParcel(Parcel source) {
69 | return new NutritionAnalysisResult(source);
70 | }
71 |
72 | @Override
73 | public NutritionAnalysisResult[] newArray(int size) {
74 | return new NutritionAnalysisResult[size];
75 | }
76 | };
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/entity/nutrition/RecipeAnalysisParams.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.entity.nutrition;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class RecipeAnalysisParams {
7 | private String title;
8 | private String prep;
9 | private String yield;
10 | private List ingr = new ArrayList<>();
11 |
12 | public void setTitle(String title) {
13 | this.title = title;
14 | }
15 |
16 | public void setPrep(String prep) {
17 | this.prep = prep;
18 | }
19 |
20 | public void setYield(String yield) {
21 | this.yield = yield;
22 | }
23 |
24 | public void setIngr(List ingr) {
25 | this.ingr = ingr;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/entity/recipe/Error.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.entity.recipe;
2 |
3 | import com.google.gson.annotations.Expose;
4 | import com.google.gson.annotations.SerializedName;
5 |
6 | public class Error {
7 | @SerializedName("error")
8 | @Expose
9 | private String error;
10 |
11 | public String getError() {
12 | return error;
13 | }
14 |
15 | public void setError(String error) {
16 | this.error = error;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/entity/recipe/Hit.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.entity.recipe;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | public class Hit {
6 | @SerializedName("recipe")
7 | private Recipe recipe;
8 | @SerializedName("bookmarked")
9 | private boolean bookmarked;
10 | @SerializedName("bought")
11 | private boolean bought;
12 |
13 | public void setRecipe(Recipe recipe) {
14 | this.recipe = recipe;
15 | }
16 |
17 | public void setBookmarked(boolean bookmarked) {
18 | this.bookmarked = bookmarked;
19 | }
20 |
21 | public void setBought(boolean bought) {
22 | this.bought = bought;
23 | }
24 |
25 | public Recipe getRecipe() {
26 | return recipe;
27 | }
28 |
29 | public boolean isBookmarked() {
30 | return bookmarked;
31 | }
32 |
33 | public boolean isBought() {
34 | return bought;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/entity/recipe/Ingredient.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.entity.recipe;
2 |
3 |
4 | import android.arch.persistence.room.ColumnInfo;
5 | import android.arch.persistence.room.Entity;
6 | import android.arch.persistence.room.PrimaryKey;
7 |
8 | import java.io.Serializable;
9 |
10 | @Entity(tableName = "ingredients")
11 | public class Ingredient implements Serializable {
12 | @PrimaryKey(autoGenerate = true)
13 | private long id;
14 |
15 | @ColumnInfo(name = "recipe_uri", index = true)
16 | private String recipeUri;
17 |
18 | private String text;
19 | private double weight;
20 |
21 | public Ingredient() {
22 | }
23 |
24 | public void setRecipeUri(String recipeUri) {
25 | this.recipeUri = recipeUri;
26 | }
27 |
28 | public void setId(long id) {
29 | this.id = id;
30 | }
31 |
32 | public void setText(String text) {
33 | this.text = text;
34 | }
35 |
36 | public void setWeight(double weight) {
37 | this.weight = weight;
38 | }
39 |
40 | public String getRecipeUri() {
41 | return recipeUri;
42 | }
43 |
44 | public long getId() {
45 | return id;
46 | }
47 |
48 | public String getText() {
49 | return text;
50 | }
51 |
52 | public double getWeight() {
53 | return weight;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/entity/recipe/Params.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.entity.recipe;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | public class Params {
9 | @SerializedName("sane")
10 | private List sane = new ArrayList<>();
11 | @SerializedName("to")
12 | private List to = new ArrayList<>();
13 | @SerializedName("from")
14 | private List from = new ArrayList<>();
15 | @SerializedName("q")
16 | private List queries = new ArrayList<>();
17 | @SerializedName("calories")
18 | private List calories = new ArrayList<>();
19 | @SerializedName("health")
20 | private List health = new ArrayList<>();
21 |
22 | public List getSane() {
23 | return sane;
24 | }
25 |
26 | public List getTo() {
27 | return to;
28 | }
29 |
30 | public List getFrom() {
31 | return from;
32 | }
33 |
34 | public List getQueries() {
35 | return queries;
36 | }
37 |
38 | public List getCalories() {
39 | return calories;
40 | }
41 |
42 | public List getHealth() {
43 | return health;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/entity/recipe/Recipe.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.entity.recipe;
2 |
3 | import android.arch.persistence.room.ColumnInfo;
4 | import android.arch.persistence.room.Entity;
5 | import android.arch.persistence.room.ForeignKey;
6 | import android.arch.persistence.room.Ignore;
7 | import android.arch.persistence.room.Index;
8 | import android.arch.persistence.room.PrimaryKey;
9 | import android.arch.persistence.room.TypeConverters;
10 |
11 | import com.google.gson.annotations.SerializedName;
12 | import com.mlsdev.recipefinder.data.entity.nutrition.TotalNutrients;
13 | import com.mlsdev.recipefinder.data.source.local.roomdb.converter.Converter;
14 |
15 | import java.io.Serializable;
16 | import java.util.ArrayList;
17 | import java.util.List;
18 |
19 | @Entity(tableName = "recipes",
20 | foreignKeys = {
21 | @ForeignKey(
22 | entity = TotalNutrients.class,
23 | parentColumns = "id",
24 | childColumns = "total_nutrients_id")},
25 | indices = {@Index("total_nutrients_id")}
26 | )
27 | @TypeConverters(Converter.class)
28 | public class Recipe implements Serializable {
29 | @PrimaryKey
30 | private String uri;
31 | private String label;
32 | private String image;
33 | private String source;
34 | private double yield;
35 | private double calories;
36 |
37 | @SerializedName("totalWeight")
38 | private double totalWeight;
39 |
40 | @Ignore
41 | @SerializedName("totalNutrients")
42 | private TotalNutrients totalNutrients;
43 |
44 | @ColumnInfo(name = "total_nutrients_id")
45 | private long totalNutrientsId;
46 |
47 | @ColumnInfo(name = "diet_labels")
48 | @SerializedName("dietLabels")
49 | private List dietLabels = new ArrayList<>();
50 |
51 | @ColumnInfo(name = "health_labels")
52 | @SerializedName("healthLabels")
53 | private List healthLabels = new ArrayList<>();
54 |
55 | @Ignore
56 | @SerializedName("ingredients")
57 | private List ingredients = new ArrayList<>();
58 |
59 | public Recipe() {
60 | }
61 |
62 | @Ignore
63 | public Recipe(long totalNutrientsId) {
64 | this.totalNutrientsId = totalNutrientsId;
65 | }
66 |
67 | // region Getters
68 |
69 | public String getUri() {
70 | return uri;
71 | }
72 |
73 | public String getLabel() {
74 | return label;
75 | }
76 |
77 | public String getImage() {
78 | return image;
79 | }
80 |
81 | public String getSource() {
82 | return source;
83 | }
84 |
85 | public double getYield() {
86 | return yield;
87 | }
88 |
89 | public double getCalories() {
90 | return calories;
91 | }
92 |
93 | public double getTotalWeight() {
94 | return totalWeight;
95 | }
96 |
97 | public TotalNutrients getTotalNutrients() {
98 | return totalNutrients;
99 | }
100 |
101 | public long getTotalNutrientsId() {
102 | return totalNutrientsId;
103 | }
104 |
105 | public List getDietLabels() {
106 | return dietLabels;
107 | }
108 |
109 | public List getHealthLabels() {
110 | return healthLabels;
111 | }
112 |
113 | public List getIngredients() {
114 | return ingredients;
115 | }
116 | // endregion
117 |
118 | // region Setters
119 |
120 | public void setUri(String uri) {
121 | this.uri = uri;
122 | }
123 |
124 | public void setLabel(String label) {
125 | this.label = label;
126 | }
127 |
128 | public void setImage(String image) {
129 | this.image = image;
130 | }
131 |
132 | public void setSource(String source) {
133 | this.source = source;
134 | }
135 |
136 | public void setYield(double yield) {
137 | this.yield = yield;
138 | }
139 |
140 | public void setCalories(double calories) {
141 | this.calories = calories;
142 | }
143 |
144 | public void setTotalWeight(double totalWeight) {
145 | this.totalWeight = totalWeight;
146 | }
147 |
148 | public void setTotalNutrients(TotalNutrients totalNutrients) {
149 | this.totalNutrients = totalNutrients;
150 | }
151 |
152 | public void setTotalNutrientsId(long totalNutrientsId) {
153 | this.totalNutrientsId = totalNutrientsId;
154 | }
155 |
156 | public void setDietLabels(List dietLabels) {
157 | this.dietLabels = dietLabels;
158 | }
159 |
160 | public void setHealthLabels(List healthLabels) {
161 | this.healthLabels = healthLabels;
162 | }
163 |
164 | public void setIngredients(List ingredients) {
165 | this.ingredients = ingredients;
166 | }
167 |
168 | // endregion
169 |
170 | }
171 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/entity/recipe/SearchResult.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.entity.recipe;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | public class SearchResult {
9 | @SerializedName("q")
10 | private String query;
11 | @SerializedName("from")
12 | private int from;
13 | @SerializedName("to")
14 | private int to;
15 | @SerializedName("params")
16 | private Params params;
17 | @SerializedName("more")
18 | private boolean more;
19 | @SerializedName("count")
20 | private int count;
21 | @SerializedName("hits")
22 | private List hits = new ArrayList<>();
23 |
24 | public String getQuery() {
25 | return query;
26 | }
27 |
28 | public int getFrom() {
29 | return from;
30 | }
31 |
32 | public int getTo() {
33 | return to;
34 | }
35 |
36 | public Params getParams() {
37 | return params;
38 | }
39 |
40 | public boolean isMore() {
41 | return more;
42 | }
43 |
44 | public int getCount() {
45 | return count;
46 | }
47 |
48 | public List getHits() {
49 | return hits;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/entity/recipe/TotalDaily.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.entity.recipe;
2 |
3 | import java.io.Serializable;
4 |
5 | public class TotalDaily implements Serializable {
6 |
7 | public TotalDaily() {
8 | }
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/entity/recipe/stringwrapper/DietLabel.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.entity.recipe.stringwrapper;
2 |
3 | import com.mlsdev.recipefinder.data.entity.recipe.Recipe;
4 |
5 | public class DietLabel extends Label {
6 | public DietLabel() {
7 | }
8 |
9 | public DietLabel(String value, Recipe recipe) {
10 | super(value, recipe);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/entity/recipe/stringwrapper/HealthLabel.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.entity.recipe.stringwrapper;
2 |
3 | import com.mlsdev.recipefinder.data.entity.recipe.Recipe;
4 |
5 | public class HealthLabel extends Label {
6 | public HealthLabel(String value, Recipe recipe) {
7 | super(value, recipe);
8 | }
9 |
10 | public HealthLabel() {
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/entity/recipe/stringwrapper/Label.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.entity.recipe.stringwrapper;
2 |
3 | import com.mlsdev.recipefinder.data.entity.recipe.Recipe;
4 |
5 | import java.io.Serializable;
6 |
7 | public abstract class Label implements Serializable {
8 | protected Recipe recipe;
9 | protected long id;
10 | protected String value;
11 |
12 | public Label() {
13 | }
14 |
15 | public Label(String value, Recipe recipe) {
16 | this.recipe = recipe;
17 | this.value = value;
18 | }
19 |
20 | public String getValue() {
21 | return value;
22 | }
23 |
24 | public void setValue(String value) {
25 | this.value = value;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/source/BaseDataSource.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.source;
2 |
3 | import com.mlsdev.recipefinder.data.entity.nutrition.NutritionAnalysisResult;
4 | import com.mlsdev.recipefinder.data.entity.nutrition.RecipeAnalysisParams;
5 | import com.mlsdev.recipefinder.data.entity.recipe.Recipe;
6 | import com.mlsdev.recipefinder.data.entity.recipe.SearchResult;
7 |
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | import io.reactivex.Completable;
12 | import io.reactivex.Flowable;
13 | import io.reactivex.Single;
14 |
15 | public abstract class BaseDataSource implements DataSource {
16 | @Override
17 | public Single searchRecipes(Map params) {
18 | return null;
19 | }
20 |
21 | @Override
22 | public Single getIngredientData(Map params) {
23 | return null;
24 | }
25 |
26 | @Override
27 | public Flowable> getFavorites() {
28 | return null;
29 | }
30 |
31 | @Override
32 | public Completable addToFavorites(Recipe favoriteRecipe) {
33 | return null;
34 | }
35 |
36 | @Override
37 | public Completable removeFromFavorites(Recipe removedRecipe) {
38 | return null;
39 | }
40 |
41 | @Override
42 | public Single isInFavorites(Recipe recipe) {
43 | return null;
44 | }
45 |
46 | @Override
47 | public Single getRecipeAnalysingResult(RecipeAnalysisParams params) {
48 | return null;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/source/BaseObserver.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.source;
2 |
3 | import android.util.Log;
4 |
5 | import com.mlsdev.recipefinder.view.MainActivity;
6 |
7 | import io.reactivex.SingleObserver;
8 | import io.reactivex.annotations.NonNull;
9 | import io.reactivex.disposables.Disposable;
10 |
11 | public abstract class BaseObserver implements SingleObserver {
12 | public static final int SERVER_ERROR = 500;
13 |
14 | @Override
15 | public void onSubscribe(@NonNull Disposable d) {
16 |
17 | }
18 |
19 | @Override
20 | public void onSuccess(@NonNull T t) {
21 |
22 | }
23 |
24 | @Override
25 | public void onError(Throwable e) {
26 | Log.e(MainActivity.LOG_TAG, e.getMessage());
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/source/DataSource.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.source;
2 |
3 | import com.mlsdev.recipefinder.data.entity.nutrition.NutritionAnalysisResult;
4 | import com.mlsdev.recipefinder.data.entity.nutrition.RecipeAnalysisParams;
5 | import com.mlsdev.recipefinder.data.entity.recipe.Recipe;
6 | import com.mlsdev.recipefinder.data.entity.recipe.SearchResult;
7 |
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | import io.reactivex.Completable;
12 | import io.reactivex.Flowable;
13 | import io.reactivex.Single;
14 |
15 | public interface DataSource {
16 | Single searchRecipes(Map params);
17 |
18 | Single getIngredientData(Map params);
19 |
20 | Flowable> getFavorites();
21 |
22 | Completable addToFavorites(Recipe favoriteRecipe);
23 |
24 | Completable removeFromFavorites(Recipe removedRecipe);
25 |
26 | Single isInFavorites(Recipe recipe);
27 |
28 | Single getRecipeAnalysingResult(RecipeAnalysisParams params);
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/source/local/roomdb/AppDatabase.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.source.local.roomdb;
2 |
3 | import android.arch.persistence.room.Database;
4 | import android.arch.persistence.room.Room;
5 | import android.arch.persistence.room.RoomDatabase;
6 | import android.content.Context;
7 |
8 | import com.mlsdev.recipefinder.data.entity.nutrition.Nutrient;
9 | import com.mlsdev.recipefinder.data.entity.nutrition.TotalNutrients;
10 | import com.mlsdev.recipefinder.data.entity.recipe.Ingredient;
11 | import com.mlsdev.recipefinder.data.entity.recipe.Recipe;
12 | import com.mlsdev.recipefinder.data.source.local.roomdb.dao.IngredientDao;
13 | import com.mlsdev.recipefinder.data.source.local.roomdb.dao.NutrientDao;
14 | import com.mlsdev.recipefinder.data.source.local.roomdb.dao.RecipeDao;
15 | import com.mlsdev.recipefinder.data.source.local.roomdb.dao.TotalNutrientsDao;
16 |
17 | @Database(
18 | entities = {
19 | Recipe.class,
20 | TotalNutrients.class,
21 | Nutrient.class,
22 | Ingredient.class},
23 | version = 1,
24 | exportSchema = false)
25 | public abstract class AppDatabase extends RoomDatabase {
26 | private static AppDatabase INSTANCE;
27 |
28 | public abstract RecipeDao recipeDao();
29 |
30 | public abstract NutrientDao nutrientDao();
31 |
32 | public abstract TotalNutrientsDao totalNutrientsDao();
33 |
34 | public abstract IngredientDao ingredientDao();
35 |
36 | public static AppDatabase getDb() {
37 | return INSTANCE;
38 | }
39 |
40 | public static AppDatabase init(Context context) {
41 | if (INSTANCE == null) {
42 | INSTANCE =
43 | Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "recipes.db")
44 | .build();
45 | }
46 |
47 | return INSTANCE;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/source/local/roomdb/converter/Converter.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.source.local.roomdb.converter;
2 |
3 | import android.arch.persistence.room.TypeConverter;
4 | import android.arch.persistence.room.util.StringUtil;
5 |
6 | import java.util.Arrays;
7 | import java.util.Collections;
8 | import java.util.List;
9 |
10 | public class Converter {
11 |
12 | @TypeConverter
13 | public static String stringListToString(List stringList) {
14 | if (stringList == null) return null;
15 |
16 | String listAsString = stringList.toString().replaceAll(" ", "");
17 | return listAsString.substring(1, listAsString.length() - 1);
18 | }
19 |
20 | @TypeConverter
21 | public static List stringToStringList(String string) {
22 |
23 | if (string == null) return null;
24 |
25 | return Arrays.asList(string.split(","));
26 | }
27 |
28 | @TypeConverter
29 | public static String integersListToString(List longs) {
30 |
31 | if (longs == null) return null;
32 |
33 | return StringUtil.joinIntoString(longs);
34 | }
35 |
36 | @TypeConverter
37 | public static List stringToIntegerList(String string) {
38 |
39 | if (string == null) return Collections.emptyList();
40 |
41 | return StringUtil.splitToIntList(string);
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/source/local/roomdb/dao/IngredientDao.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.source.local.roomdb.dao;
2 |
3 | import android.arch.persistence.room.Dao;
4 | import android.arch.persistence.room.Insert;
5 | import android.arch.persistence.room.OnConflictStrategy;
6 | import android.arch.persistence.room.Query;
7 |
8 | import com.mlsdev.recipefinder.data.entity.recipe.Ingredient;
9 |
10 | import java.util.List;
11 |
12 | @Dao
13 | public interface IngredientDao {
14 | @Insert(onConflict = OnConflictStrategy.REPLACE)
15 | void insert(List ingredients);
16 |
17 | @Insert(onConflict = OnConflictStrategy.REPLACE)
18 | void insert(Ingredient ingredient);
19 |
20 | @Insert(onConflict = OnConflictStrategy.IGNORE)
21 | void createIfNotExist(Ingredient ingredient);
22 |
23 | @Query("select * from ingredients where recipe_uri = :uri")
24 | List loadByRecipeUri(String uri);
25 |
26 | @Query("delete from ingredients where recipe_uri = :uri")
27 | void deleteByRecipeUri(String uri);
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/source/local/roomdb/dao/NutrientDao.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.source.local.roomdb.dao;
2 |
3 | import android.arch.persistence.room.Dao;
4 | import android.arch.persistence.room.Delete;
5 | import android.arch.persistence.room.Insert;
6 | import android.arch.persistence.room.OnConflictStrategy;
7 | import android.arch.persistence.room.Query;
8 |
9 | import com.mlsdev.recipefinder.data.entity.nutrition.Nutrient;
10 |
11 | import java.util.List;
12 |
13 | @Dao
14 | public interface NutrientDao {
15 |
16 | @Insert(onConflict = OnConflictStrategy.REPLACE)
17 | void insert(List nutrients);
18 |
19 | @Insert(onConflict = OnConflictStrategy.IGNORE)
20 | long createIfNotExist(Nutrient nutrient);
21 |
22 | @Query("select * from nutrients where id = :id")
23 | Nutrient loadById(long id);
24 |
25 | @Query("select * from nutrients where id in (:ids)")
26 | List loadByIds(List ids);
27 |
28 | @Query("delete from nutrients where id = :nutrientId")
29 | void deleteById(long nutrientId);
30 |
31 | @Delete
32 | void delete(Nutrient Nutrient);
33 |
34 | @Delete
35 | void delete(List nutrients);
36 |
37 | @Query("delete from nutrients where id in (:ids)")
38 | void deleteByIds(List ids);
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/source/local/roomdb/dao/RecipeDao.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.source.local.roomdb.dao;
2 |
3 | import android.arch.persistence.room.Dao;
4 | import android.arch.persistence.room.Delete;
5 | import android.arch.persistence.room.Insert;
6 | import android.arch.persistence.room.OnConflictStrategy;
7 | import android.arch.persistence.room.Query;
8 |
9 | import com.mlsdev.recipefinder.data.entity.recipe.Recipe;
10 |
11 | import java.util.List;
12 |
13 | import io.reactivex.Flowable;
14 |
15 | @Dao
16 | public interface RecipeDao {
17 |
18 | @Insert(onConflict = OnConflictStrategy.REPLACE)
19 | long insert(Recipe recipe);
20 |
21 | @Query("select uri from recipes where uri = :recipeUri")
22 | Flowable loadByUri(String recipeUri);
23 |
24 | @Query("select * from recipes")
25 | Flowable> loadAll();
26 |
27 | @Delete
28 | int delete(Recipe recipe);
29 |
30 | @Delete
31 | void delete(List recipes);
32 |
33 | @Query("delete from recipes where uri = :uri")
34 | void deleteByIds(String uri);
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/source/local/roomdb/dao/TotalNutrientsDao.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.source.local.roomdb.dao;
2 |
3 | import android.arch.persistence.room.Dao;
4 | import android.arch.persistence.room.Delete;
5 | import android.arch.persistence.room.Insert;
6 | import android.arch.persistence.room.OnConflictStrategy;
7 | import android.arch.persistence.room.Query;
8 |
9 | import com.mlsdev.recipefinder.data.entity.nutrition.TotalNutrients;
10 |
11 | @Dao
12 | public interface TotalNutrientsDao {
13 |
14 | @Insert(onConflict = OnConflictStrategy.REPLACE)
15 | long createIfNotExist(TotalNutrients totalNutrients);
16 |
17 | @Query("select * from total_nutrients where id = :totalNutrientsId")
18 | TotalNutrients loadById(long totalNutrientsId);
19 |
20 | @Query("delete from total_nutrients where id = :totalNutrientsId")
21 | void deleteById(long totalNutrientsId);
22 |
23 | @Delete
24 | void delete(TotalNutrients totalNutrients);
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/source/remote/NutritionAnalysisService.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.source.remote;
2 |
3 | import com.mlsdev.recipefinder.data.entity.nutrition.NutritionAnalysisResult;
4 | import com.mlsdev.recipefinder.data.entity.nutrition.RecipeAnalysisParams;
5 |
6 | import java.util.Map;
7 |
8 | import io.reactivex.Single;
9 | import retrofit2.http.Body;
10 | import retrofit2.http.GET;
11 | import retrofit2.http.POST;
12 | import retrofit2.http.QueryMap;
13 |
14 | public interface NutritionAnalysisService {
15 |
16 | @GET(PathConstants.NUTRITION_DATA)
17 | Single analyzeIngredient(@QueryMap Map params);
18 |
19 | @POST(PathConstants.NUTRITION_DETAILS)
20 | Single analyzeRecipe(@Body RecipeAnalysisParams params,
21 | @QueryMap Map credentials);
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/source/remote/ParameterKeys.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.source.remote;
2 |
3 | public class ParameterKeys {
4 | public static final String APP_ID = "app_id";
5 | public static final String APP_KEY = "app_key";
6 | public static final String QUERY = "q";
7 | public static final String FROM = "from";
8 | public static final String TO = "to";
9 | public static final String HEALTH = "health";
10 | public static final String DIET = "diet";
11 | public static final String INGREDIENT = "ingr";
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/source/remote/PathConstants.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.source.remote;
2 |
3 | public class PathConstants {
4 | public static final String BASE_URL = "https://api.edamam.com/";
5 | public static final String SEARCH = "search";
6 | public static final String NUTRITION_DATA = "api/nutrition-data";
7 | public static final String NUTRITION_DETAILS = "api/nutrition-details";
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/source/remote/RemoteDataSource.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.source.remote;
2 |
3 | import android.support.v4.util.ArrayMap;
4 |
5 | import com.mlsdev.recipefinder.BuildConfig;
6 | import com.mlsdev.recipefinder.data.entity.nutrition.NutritionAnalysisResult;
7 | import com.mlsdev.recipefinder.data.entity.nutrition.RecipeAnalysisParams;
8 | import com.mlsdev.recipefinder.data.entity.recipe.SearchResult;
9 | import com.mlsdev.recipefinder.data.source.BaseDataSource;
10 | import com.mlsdev.recipefinder.data.source.DataSource;
11 |
12 | import java.util.Map;
13 |
14 | import io.reactivex.Single;
15 | import okhttp3.OkHttpClient;
16 | import okhttp3.logging.HttpLoggingInterceptor;
17 | import retrofit2.Retrofit;
18 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
19 | import retrofit2.converter.gson.GsonConverterFactory;
20 |
21 | public class RemoteDataSource extends BaseDataSource implements DataSource {
22 | private static String baseUrl = PathConstants.BASE_URL;
23 | private SearchRecipesService searchRecipesService;
24 | private NutritionAnalysisService nutritionAnalysisService;
25 | private static RemoteDataSource instance;
26 |
27 | public RemoteDataSource() {
28 | initApiServices();
29 | }
30 |
31 | public static RemoteDataSource getInstance() {
32 | if (instance == null)
33 | instance = new RemoteDataSource();
34 |
35 | return instance;
36 | }
37 |
38 | public static void setBaseUrl(String url) {
39 | baseUrl = url;
40 | instance = null;
41 | }
42 |
43 | private void initApiServices() {
44 | HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
45 | interceptor.setLevel(BuildConfig.DEBUG ? HttpLoggingInterceptor.Level.BODY : HttpLoggingInterceptor.Level.NONE);
46 |
47 | OkHttpClient client = new OkHttpClient.Builder()
48 | .addInterceptor(interceptor)
49 | .build();
50 |
51 | Retrofit retrofit = new Retrofit.Builder()
52 | .client(client)
53 | .baseUrl(baseUrl)
54 | .addConverterFactory(GsonConverterFactory.create())
55 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
56 | .build();
57 |
58 | searchRecipesService = retrofit.create(SearchRecipesService.class);
59 | nutritionAnalysisService = retrofit.create(NutritionAnalysisService.class);
60 | }
61 |
62 | @Override
63 | public Single searchRecipes(Map params) {
64 | setCredentials(params, true);
65 | return searchRecipesService.searchRecipes(params);
66 | }
67 |
68 | @Override
69 | public Single getIngredientData(Map params) {
70 | setCredentials(params, false);
71 | return nutritionAnalysisService.analyzeIngredient(params);
72 | }
73 |
74 | @Override
75 | public Single getRecipeAnalysingResult(RecipeAnalysisParams params) {
76 | Map credentials = new ArrayMap<>();
77 | setCredentials(credentials, false);
78 | return nutritionAnalysisService.analyzeRecipe(params, credentials);
79 | }
80 |
81 | private void setCredentials(Map params, boolean search) {
82 | params.put(ParameterKeys.APP_ID, search ? BuildConfig.SEARCH_APP_ID : BuildConfig.ANALYSE_APP_ID);
83 | params.put(ParameterKeys.APP_KEY, search ? BuildConfig.SEARCH_APP_KEY : BuildConfig.ANALYSE_APP_KEY);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/source/remote/SearchRecipesService.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.source.remote;
2 |
3 | import com.mlsdev.recipefinder.data.entity.recipe.SearchResult;
4 |
5 | import java.util.Map;
6 |
7 | import io.reactivex.Single;
8 | import retrofit2.http.GET;
9 | import retrofit2.http.QueryMap;
10 |
11 | public interface SearchRecipesService {
12 |
13 | @GET(PathConstants.SEARCH)
14 | Single searchRecipes(@QueryMap Map params);
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/data/source/repository/DataRepository.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.data.source.repository;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import com.mlsdev.recipefinder.data.entity.nutrition.NutritionAnalysisResult;
6 | import com.mlsdev.recipefinder.data.entity.nutrition.RecipeAnalysisParams;
7 | import com.mlsdev.recipefinder.data.entity.recipe.Hit;
8 | import com.mlsdev.recipefinder.data.entity.recipe.Recipe;
9 | import com.mlsdev.recipefinder.data.entity.recipe.SearchResult;
10 | import com.mlsdev.recipefinder.data.source.DataSource;
11 | import com.mlsdev.recipefinder.data.source.remote.ParameterKeys;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 | import java.util.Map;
16 |
17 | import io.reactivex.Completable;
18 | import io.reactivex.Flowable;
19 | import io.reactivex.Single;
20 | import io.reactivex.SingleSource;
21 | import io.reactivex.functions.Consumer;
22 | import io.reactivex.functions.Function;
23 |
24 | public class DataRepository {
25 | private final int offset = 10;
26 | private int from = 0;
27 | private int to = offset;
28 | private boolean more = true;
29 |
30 | private DataSource localDataSource;
31 | private DataSource remoteDataSource;
32 |
33 | private List cachedRecipes;
34 | private boolean cacheIsDirty = false;
35 |
36 | public DataRepository(DataSource local, DataSource remote) {
37 | localDataSource = local;
38 | remoteDataSource = remote;
39 | cachedRecipes = new ArrayList<>();
40 | }
41 |
42 | public void setCacheIsDirty() {
43 | cacheIsDirty = true;
44 | }
45 |
46 | public Single> searchRecipes(Map params) {
47 | if (!cacheIsDirty) {
48 | return Single.just(cachedRecipes);
49 | }
50 |
51 | more = true;
52 | cachedRecipes.clear();
53 |
54 | params.put(ParameterKeys.FROM, String.valueOf(0));
55 | params.put(ParameterKeys.TO, String.valueOf(offset));
56 |
57 | return getRecipes(params);
58 | }
59 |
60 | public Single> loadMore(Map params) {
61 |
62 | if (!more)
63 | return Single.amb(new ArrayList>>());
64 |
65 | params.put(ParameterKeys.FROM, String.valueOf(from));
66 | params.put(ParameterKeys.TO, String.valueOf(to));
67 |
68 | return getRecipes(params);
69 | }
70 |
71 | @NonNull
72 | private Single> getRecipes(Map params) {
73 | return remoteDataSource.searchRecipes(params)
74 | .map(new Function>() {
75 | @Override
76 | public List apply(@io.reactivex.annotations.NonNull SearchResult searchResult) throws Exception {
77 | from = searchResult.getTo();
78 | to = from + offset;
79 | more = searchResult.isMore();
80 |
81 | List recipes = new ArrayList<>();
82 | for (Hit hit : searchResult.getHits())
83 | recipes.add(hit.getRecipe());
84 |
85 | cachedRecipes.addAll(recipes);
86 |
87 | return recipes;
88 | }
89 | })
90 | .doOnSuccess(new Consumer>() {
91 | @Override
92 | public void accept(@io.reactivex.annotations.NonNull List recipes) throws Exception {
93 | cacheIsDirty = false;
94 | }
95 | });
96 | }
97 |
98 | public Flowable> getFavoriteRecipes() {
99 | return localDataSource.getFavorites();
100 | }
101 |
102 | public Completable addToFavorites(Recipe favoriteRecipe) {
103 | return localDataSource.addToFavorites(favoriteRecipe);
104 | }
105 |
106 | public Completable removeFromFavorites(Recipe removedRecipe) {
107 | return localDataSource.removeFromFavorites(removedRecipe);
108 | }
109 |
110 | public Single isInFavorites(Recipe recipe) {
111 | return localDataSource.isInFavorites(recipe);
112 | }
113 |
114 | public Single getIngredientData(final Map params) {
115 | return remoteDataSource.getIngredientData(params);
116 | }
117 |
118 | public Single getRecipeAnalysisData(final RecipeAnalysisParams params) {
119 | return remoteDataSource.getRecipeAnalysingResult(params);
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/di/ApplicationInjector.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di;
2 |
3 | import android.app.Activity;
4 | import android.app.Application;
5 | import android.os.Bundle;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.app.FragmentActivity;
8 | import android.support.v4.app.FragmentManager;
9 |
10 | import com.mlsdev.recipefinder.RecipeApplication;
11 | import com.mlsdev.recipefinder.di.component.DaggerApplicationComponent;
12 |
13 | import dagger.android.AndroidInjection;
14 | import dagger.android.support.AndroidSupportInjection;
15 | import dagger.android.support.HasSupportFragmentInjector;
16 |
17 | public class ApplicationInjector {
18 |
19 | private ApplicationInjector() {
20 | }
21 |
22 | public static void init(RecipeApplication application) {
23 | DaggerApplicationComponent.builder()
24 | .application(application)
25 | .build()
26 | .inject(application);
27 |
28 | application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
29 | @Override
30 | public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
31 | handleActivity(activity);
32 | }
33 |
34 | @Override
35 | public void onActivityStarted(Activity activity) {
36 |
37 | }
38 |
39 | @Override
40 | public void onActivityResumed(Activity activity) {
41 |
42 | }
43 |
44 | @Override
45 | public void onActivityPaused(Activity activity) {
46 |
47 | }
48 |
49 | @Override
50 | public void onActivityStopped(Activity activity) {
51 |
52 | }
53 |
54 | @Override
55 | public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
56 |
57 | }
58 |
59 | @Override
60 | public void onActivityDestroyed(Activity activity) {
61 |
62 | }
63 | });
64 | }
65 |
66 | private static void handleActivity(Activity activity) {
67 |
68 | if (activity instanceof HasSupportFragmentInjector) {
69 | AndroidInjection.inject(activity);
70 | }
71 |
72 | if (activity instanceof FragmentActivity) {
73 | ((FragmentActivity) activity).getSupportFragmentManager()
74 | .registerFragmentLifecycleCallbacks(new FragmentManager.FragmentLifecycleCallbacks() {
75 | @Override
76 | public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
77 | if (f instanceof Injectable)
78 | AndroidSupportInjection.inject(f);
79 | }
80 | }, true);
81 | }
82 |
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/di/Injectable.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di;
2 |
3 | public interface Injectable {
4 | }
5 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/di/component/ApplicationComponent.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di.component;
2 |
3 | import android.app.Application;
4 |
5 | import com.mlsdev.recipefinder.RecipeApplication;
6 | import com.mlsdev.recipefinder.di.module.ApiModule;
7 | import com.mlsdev.recipefinder.di.module.DataSourceModule;
8 | import com.mlsdev.recipefinder.di.module.DatabaseModule;
9 | import com.mlsdev.recipefinder.di.module.MainActivityModule;
10 | import com.mlsdev.recipefinder.di.module.RecipeAnalysisActivityModule;
11 | import com.mlsdev.recipefinder.di.module.UtilsModule;
12 | import com.mlsdev.recipefinder.di.module.ViewModelModule;
13 |
14 | import javax.inject.Singleton;
15 |
16 | import dagger.BindsInstance;
17 | import dagger.Component;
18 | import dagger.android.AndroidInjectionModule;
19 |
20 | @Singleton
21 | @Component(modules = {
22 | AndroidInjectionModule.class,
23 | UtilsModule.class,
24 | DataSourceModule.class,
25 | DatabaseModule.class,
26 | ApiModule.class,
27 | MainActivityModule.class,
28 | RecipeAnalysisActivityModule.class,
29 | ViewModelModule.class})
30 | public interface ApplicationComponent {
31 |
32 | @Component.Builder
33 | interface Builder {
34 | @BindsInstance
35 | Builder application(Application application);
36 |
37 | ApplicationComponent build();
38 | }
39 |
40 | void inject(RecipeApplication application);
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/di/module/ApiModule.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di.module;
2 |
3 | import com.google.gson.Gson;
4 | import com.mlsdev.recipefinder.BuildConfig;
5 | import com.mlsdev.recipefinder.data.source.remote.NutritionAnalysisService;
6 | import com.mlsdev.recipefinder.data.source.remote.PathConstants;
7 | import com.mlsdev.recipefinder.data.source.remote.SearchRecipesService;
8 |
9 | import javax.inject.Named;
10 | import javax.inject.Singleton;
11 |
12 | import dagger.Module;
13 | import dagger.Provides;
14 | import okhttp3.Interceptor;
15 | import okhttp3.OkHttpClient;
16 | import okhttp3.logging.HttpLoggingInterceptor;
17 | import retrofit2.Retrofit;
18 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
19 | import retrofit2.converter.gson.GsonConverterFactory;
20 |
21 | @Module
22 | public class ApiModule {
23 | public static final String HTTP_LOGGING = "http_logging_interceptor";
24 | public String baseUrl = PathConstants.BASE_URL;
25 |
26 | @Provides
27 | @Singleton
28 | Gson provideGson() {
29 | return new Gson();
30 | }
31 |
32 | @Provides
33 | @Named(HTTP_LOGGING)
34 | Interceptor provideHttpLoggingInterceptor() {
35 | HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
36 | interceptor.setLevel(BuildConfig.DEBUG ? HttpLoggingInterceptor.Level.BODY : HttpLoggingInterceptor.Level.NONE);
37 | return interceptor;
38 | }
39 |
40 | @Provides
41 | @Singleton
42 | OkHttpClient provideOkHttpClient(@Named(HTTP_LOGGING) Interceptor httpLoggingInterceptor) {
43 | return new OkHttpClient.Builder()
44 | .addInterceptor(httpLoggingInterceptor)
45 | .build();
46 | }
47 |
48 | @Provides
49 | @Singleton
50 | Retrofit provideRetrofit(OkHttpClient okHttpClient) {
51 | return new Retrofit.Builder()
52 | .client(okHttpClient)
53 | .baseUrl(baseUrl)
54 | .addConverterFactory(GsonConverterFactory.create())
55 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
56 | .build();
57 | }
58 |
59 | @Provides
60 | @Singleton
61 | SearchRecipesService provideSearchRecipesService(Retrofit retrofit) {
62 | return retrofit.create(SearchRecipesService.class);
63 | }
64 |
65 | @Provides
66 | @Singleton
67 | NutritionAnalysisService provideNutritionAnalysisService(Retrofit retrofit) {
68 | return retrofit.create(NutritionAnalysisService.class);
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/di/module/DataSourceModule.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di.module;
2 |
3 | import com.mlsdev.recipefinder.data.source.DataSource;
4 | import com.mlsdev.recipefinder.data.source.local.LocalDataSource;
5 | import com.mlsdev.recipefinder.data.source.local.roomdb.AppDatabase;
6 | import com.mlsdev.recipefinder.data.source.remote.RemoteDataSource;
7 | import com.mlsdev.recipefinder.data.source.repository.DataRepository;
8 |
9 | import javax.inject.Named;
10 | import javax.inject.Singleton;
11 |
12 | import dagger.Module;
13 | import dagger.Provides;
14 |
15 | @Module
16 | public class DataSourceModule {
17 | public static final String LOCAL_DATA_SOURCE = "local_data_source";
18 | public static final String REMOTE_DATA_SOURCE = "remote_data_source";
19 |
20 | @Provides
21 | @Singleton
22 | DataRepository provideDataRepository(@Named(LOCAL_DATA_SOURCE) DataSource local,
23 | @Named(REMOTE_DATA_SOURCE) DataSource remote) {
24 | return new DataRepository(local, remote);
25 | }
26 |
27 | @Provides
28 | @Singleton
29 | @Named(LOCAL_DATA_SOURCE)
30 | DataSource provideLocalDataSource(AppDatabase database) {
31 | return new LocalDataSource(database);
32 | }
33 |
34 | @Provides
35 | @Singleton
36 | @Named(REMOTE_DATA_SOURCE)
37 | DataSource provideRemoteDataSource() {
38 | return new RemoteDataSource();
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/di/module/DatabaseModule.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di.module;
2 |
3 | import android.app.Application;
4 | import android.arch.persistence.room.Room;
5 |
6 | import com.mlsdev.recipefinder.data.source.local.roomdb.AppDatabase;
7 |
8 | import javax.inject.Singleton;
9 |
10 | import dagger.Module;
11 | import dagger.Provides;
12 |
13 | @Module
14 | public class DatabaseModule {
15 |
16 | @Provides
17 | @Singleton
18 | AppDatabase provideDatabase(Application application) {
19 | return Room.databaseBuilder(application.getApplicationContext(), AppDatabase.class, "recipes.db")
20 | .build();
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/di/module/FragmentBuilderModule.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di.module;
2 |
3 | import com.mlsdev.recipefinder.view.analysenutrition.ingredient.IngredientAnalysisFragment;
4 | import com.mlsdev.recipefinder.view.analysenutrition.recipe.RecipeAnalysisFragment;
5 | import com.mlsdev.recipefinder.view.favoriterecipes.FavoriteRecipesFragment;
6 | import com.mlsdev.recipefinder.view.recipedetails.RecipeDetailsFragment;
7 | import com.mlsdev.recipefinder.view.searchrecipes.SearchRecipeFragment;
8 |
9 | import dagger.Module;
10 | import dagger.android.ContributesAndroidInjector;
11 |
12 | @Module
13 | public abstract class FragmentBuilderModule {
14 |
15 | @ContributesAndroidInjector
16 | abstract SearchRecipeFragment contributeSearchRecipeFragment();
17 |
18 | @ContributesAndroidInjector
19 | abstract FavoriteRecipesFragment contributeFavoriteRecipesFragment();
20 |
21 | @ContributesAndroidInjector
22 | abstract IngredientAnalysisFragment contributeIngredientAnalysisFragment();
23 |
24 | @ContributesAndroidInjector
25 | abstract RecipeAnalysisFragment contributeRecipeAnalysisFragment();
26 |
27 | @ContributesAndroidInjector
28 | abstract RecipeDetailsFragment contribureRecipeDetailsFragment();
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/di/module/MainActivityModule.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di.module;
2 |
3 | import com.mlsdev.recipefinder.view.MainActivity;
4 |
5 | import dagger.Module;
6 | import dagger.android.ContributesAndroidInjector;
7 |
8 | @Module
9 | public abstract class MainActivityModule {
10 |
11 | @ContributesAndroidInjector(modules = {FragmentBuilderModule.class})
12 | abstract MainActivity contributeMainActivityInjector();
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/di/module/RecipeAnalysisActivityModule.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di.module;
2 |
3 | import com.mlsdev.recipefinder.view.analysenutrition.recipe.RecipeAnalysisDetailsActivity;
4 |
5 | import dagger.Module;
6 | import dagger.android.ContributesAndroidInjector;
7 |
8 | @Module
9 | public abstract class RecipeAnalysisActivityModule {
10 | @ContributesAndroidInjector(modules = {FragmentBuilderModule.class})
11 | abstract RecipeAnalysisDetailsActivity contributeActivity();
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/di/module/UtilsModule.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di.module;
2 |
3 | import com.mlsdev.recipefinder.view.utils.DiagramUtils;
4 | import com.mlsdev.recipefinder.view.utils.ParamsHelper;
5 | import com.mlsdev.recipefinder.view.utils.UtilsUI;
6 |
7 | import javax.inject.Singleton;
8 |
9 | import dagger.Module;
10 | import dagger.Provides;
11 |
12 | @Module
13 | public class UtilsModule {
14 |
15 | @Provides
16 | @Singleton
17 | DiagramUtils provideDiagramUtils(UtilsUI utilsUI) {
18 | return new DiagramUtils(utilsUI);
19 | }
20 |
21 | @Provides
22 | @Singleton
23 | UtilsUI provideUtilsUI() {
24 | return new UtilsUI();
25 | }
26 |
27 | @Provides
28 | @Singleton
29 | ParamsHelper provideParamsHelper() {
30 | return new ParamsHelper();
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/di/module/ViewModelKey.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di.module;
2 |
3 | import android.arch.lifecycle.ViewModel;
4 |
5 | import java.lang.annotation.Documented;
6 | import java.lang.annotation.ElementType;
7 | import java.lang.annotation.Retention;
8 | import java.lang.annotation.RetentionPolicy;
9 | import java.lang.annotation.Target;
10 |
11 | import dagger.MapKey;
12 |
13 | @Documented
14 | @Target(ElementType.METHOD)
15 | @Retention(RetentionPolicy.RUNTIME)
16 | @MapKey
17 | @interface ViewModelKey {
18 | Class extends ViewModel> value();
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/di/module/ViewModelModule.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.di.module;
2 |
3 | import android.arch.lifecycle.ViewModel;
4 | import android.arch.lifecycle.ViewModelProvider;
5 |
6 | import com.mlsdev.recipefinder.view.analysenutrition.ingredient.IngredientAnalysisViewModel;
7 | import com.mlsdev.recipefinder.view.analysenutrition.recipe.RecipeAnalysisDetailsViewModel;
8 | import com.mlsdev.recipefinder.view.analysenutrition.recipe.RecipeAnalysisViewModel;
9 | import com.mlsdev.recipefinder.view.favoriterecipes.FavoritesViewModel;
10 | import com.mlsdev.recipefinder.view.recipedetails.RecipeViewModel;
11 | import com.mlsdev.recipefinder.view.searchrecipes.SearchViewModel;
12 | import com.mlsdev.recipefinder.view.viewmodel.ViewModelFactory;
13 |
14 | import dagger.Binds;
15 | import dagger.Module;
16 | import dagger.multibindings.IntoMap;
17 |
18 | @Module
19 | public abstract class ViewModelModule {
20 |
21 | @Binds
22 | @IntoMap
23 | @ViewModelKey(SearchViewModel.class)
24 | abstract ViewModel bindSearchViewModel(SearchViewModel searchViewModel);
25 |
26 | @Binds
27 | @IntoMap
28 | @ViewModelKey(FavoritesViewModel.class)
29 | abstract ViewModel bindFavoritesViewModel(FavoritesViewModel favoritesViewModel);
30 |
31 | @Binds
32 | @IntoMap
33 | @ViewModelKey(IngredientAnalysisViewModel.class)
34 | abstract ViewModel bindIngredientAnalysisViewModel(IngredientAnalysisViewModel ingredientAnalysisViewModel);
35 |
36 | @Binds
37 | @IntoMap
38 | @ViewModelKey(RecipeAnalysisViewModel.class)
39 | abstract ViewModel bindRecipeAnalysisViewModel(RecipeAnalysisViewModel recipeAnalysisViewModel);
40 |
41 | @Binds
42 | @IntoMap
43 | @ViewModelKey(RecipeViewModel.class)
44 | abstract ViewModel bindRecipeViewModel(RecipeViewModel recipeViewModel);
45 |
46 | @Binds
47 | @IntoMap
48 | @ViewModelKey(RecipeAnalysisDetailsViewModel.class)
49 | abstract ViewModel bindRecipeAnalysisDetailsViewModel(RecipeAnalysisDetailsViewModel viewModel);
50 |
51 | @Binds
52 | abstract ViewModelProvider.Factory bindViewModelFactory(ViewModelFactory factory);
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/ActionListener.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view;
2 |
3 | import android.support.annotation.StringRes;
4 | import android.view.View;
5 |
6 | public interface ActionListener {
7 |
8 | void onStartFilter();
9 |
10 | void showProgressDialog(boolean show, String message);
11 |
12 | void showSnackbar(@StringRes int message);
13 |
14 | void showSnackbar(String message);
15 |
16 | void showSnackbar(String message, String action, View.OnClickListener listener);
17 |
18 | void showSnackbar(@StringRes int message, @StringRes int action, View.OnClickListener listener);
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.support.annotation.Nullable;
8 | import android.support.annotation.StringRes;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.view.MenuItem;
11 | import android.view.View;
12 | import android.view.inputmethod.InputMethodManager;
13 |
14 | import com.mlsdev.recipefinder.view.message.ProgressDialogMessage;
15 | import com.mlsdev.recipefinder.view.message.SnackbarMessage;
16 |
17 | public class BaseActivity extends AppCompatActivity implements NavigationController, ActionListener {
18 | private ProgressDialogMessage progressDialogMessage;
19 | private SnackbarMessage snackbarMessage;
20 |
21 | @Override
22 | public void onCreate(@Nullable Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | progressDialogMessage = new ProgressDialogMessage(this);
25 | snackbarMessage = new SnackbarMessage(this);
26 | }
27 |
28 | @Override
29 | public boolean onOptionsItemSelected(MenuItem item) {
30 | if (item.getItemId() == android.R.id.home)
31 | onBackPressed();
32 | return super.onOptionsItemSelected(item);
33 | }
34 |
35 | public void hideSoftKeyboard() {
36 | View view = getCurrentFocus();
37 |
38 | if (view != null) {
39 | InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
40 | inputMethodManager.hideSoftInputFromInputMethod(view.getWindowToken(), 0);
41 | }
42 | }
43 |
44 | public void showSoftKeyboard() {
45 | InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
46 | imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
47 | }
48 |
49 | @Override
50 | public void launchActivity(Intent intent) {
51 | startActivity(intent);
52 | }
53 |
54 | @Override
55 | public void launchActivityForResult(Intent intent, int requestCode) {
56 | startActivityForResult(intent, requestCode);
57 | }
58 |
59 | @Override
60 | public void finishCurrentActivity() {
61 | finish();
62 | }
63 |
64 | @Override
65 | public void finishWithResult(Intent data) {
66 | setActivityResult(data);
67 | finish();
68 | }
69 |
70 | @Override
71 | public void setActivityResult(Intent data) {
72 | setResult(Activity.RESULT_OK, data);
73 | }
74 |
75 | @Override
76 | public void onStartFilter() {
77 |
78 | }
79 |
80 | @Override
81 | public void showProgressDialog(boolean show, String message) {
82 | progressDialogMessage.showProgressDialog(show, message);
83 | }
84 |
85 | @Override
86 | public void showSnackbar(@StringRes int message) {
87 | snackbarMessage.showSnackbar(message);
88 | }
89 |
90 | @Override
91 | public void showSnackbar(String message) {
92 | snackbarMessage.showSnackbar(message);
93 | }
94 |
95 | @Override
96 | public void showSnackbar(String message, String action, View.OnClickListener listener) {
97 | snackbarMessage.showSnackbar(message, action, listener);
98 | }
99 |
100 | @Override
101 | public void showSnackbar(@StringRes int message, @StringRes int action, View.OnClickListener listener) {
102 | snackbarMessage.showSnackbar(message, action, listener);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/BottomNavigationItemSelectedListener.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view;
2 |
3 | import android.arch.lifecycle.Lifecycle;
4 | import android.arch.lifecycle.LifecycleObserver;
5 | import android.arch.lifecycle.OnLifecycleEvent;
6 | import android.support.annotation.NonNull;
7 | import android.support.v4.app.FragmentManager;
8 | import android.support.v4.app.FragmentTransaction;
9 | import android.view.MenuItem;
10 |
11 | import com.mlsdev.recipefinder.R;
12 | import com.mlsdev.recipefinder.view.fragments.TabFragment;
13 |
14 | import javax.inject.Inject;
15 |
16 | import static android.support.design.widget.BottomNavigationView.OnNavigationItemSelectedListener;
17 | import static com.mlsdev.recipefinder.view.enums.TabItemType.ANALYSE;
18 | import static com.mlsdev.recipefinder.view.enums.TabItemType.FAVORITES;
19 | import static com.mlsdev.recipefinder.view.enums.TabItemType.SEARCH;
20 |
21 | public class BottomNavigationItemSelectedListener implements OnNavigationItemSelectedListener,
22 | LifecycleObserver {
23 | private FragmentManager fragmentManager;
24 | private TabFragment analyseNutritionFragment;
25 | private TabFragment searchRecipesFragment;
26 | private TabFragment favoriteRecipesFragment;
27 | private TabFragment currentFragment;
28 | private int checkedItemId = -1;
29 | private MenuItem currentMenuItem;
30 |
31 | @Inject
32 | public BottomNavigationItemSelectedListener() {
33 | analyseNutritionFragment = TabFragment.getNewInstance(ANALYSE);
34 | searchRecipesFragment = TabFragment.getNewInstance(SEARCH);
35 | favoriteRecipesFragment = TabFragment.getNewInstance(FAVORITES);
36 | }
37 |
38 | public void setFragmentManager(FragmentManager fragmentManager) {
39 | this.fragmentManager = fragmentManager;
40 | }
41 |
42 | public void setCurrentMenuItem(MenuItem currentMenuItem) {
43 | if (this.currentMenuItem == null)
44 | this.currentMenuItem = currentMenuItem;
45 | }
46 |
47 | @OnLifecycleEvent(Lifecycle.Event.ON_START)
48 | void start() {
49 | if (currentMenuItem != null)
50 | onNavigationItemSelected(currentMenuItem);
51 | }
52 |
53 | @Override
54 | public boolean onNavigationItemSelected(@NonNull MenuItem item) {
55 | currentMenuItem = item;
56 |
57 | if (checkedItemId == item.getItemId()) {
58 | currentFragment.scrollToTop();
59 | return true;
60 | }
61 |
62 | checkedItemId = item.getItemId();
63 |
64 | switch (item.getItemId()) {
65 | case R.id.action_analyse_nutrition:
66 | replaceFragment(analyseNutritionFragment);
67 | return true;
68 | case R.id.action_search_recipe:
69 | replaceFragment(searchRecipesFragment);
70 | return true;
71 | case R.id.action_favorites:
72 | replaceFragment(favoriteRecipesFragment);
73 | return true;
74 | default:
75 | return false;
76 |
77 | }
78 |
79 | }
80 |
81 | private void replaceFragment(TabFragment fragment) {
82 | currentFragment = fragment;
83 |
84 | clearBackStack();
85 |
86 | fragmentManager.beginTransaction()
87 | .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
88 | .replace(R.id.fl_content, fragment)
89 | .commit();
90 | }
91 |
92 | private void clearBackStack() {
93 | if (fragmentManager.getBackStackEntryCount() > 0) {
94 | fragmentManager.popBackStackImmediate();
95 | clearBackStack();
96 | }
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/Extras.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view;
2 |
3 | public class Extras {
4 | public static final String ALERT_DIALOG_TITLE = "alert_dialog_title";
5 | public static final String ALERT_DIALOG_MESSAGE = "alert_dialog_message";
6 | public static final String IMAGE_DATA = "image_data";
7 | public static final String DATA = "data";
8 | public static final String IMAGE_TRANSITION_NAME = "image_transition_name";
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view;
2 |
3 | import android.arch.lifecycle.LifecycleRegistry;
4 | import android.arch.lifecycle.LifecycleRegistryOwner;
5 | import android.content.BroadcastReceiver;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.IntentFilter;
9 | import android.databinding.DataBindingUtil;
10 | import android.os.Bundle;
11 | import android.support.v4.app.Fragment;
12 | import android.support.v4.content.LocalBroadcastManager;
13 | import android.support.v7.app.AlertDialog;
14 |
15 | import com.mlsdev.recipefinder.R;
16 | import com.mlsdev.recipefinder.databinding.ActivityMainBinding;
17 |
18 | import javax.inject.Inject;
19 |
20 | import dagger.android.AndroidInjection;
21 | import dagger.android.DispatchingAndroidInjector;
22 | import dagger.android.support.HasSupportFragmentInjector;
23 |
24 | public class MainActivity extends BaseActivity implements LifecycleRegistryOwner,
25 | HasSupportFragmentInjector {
26 | public static final String LOG_TAG = "RECIPE_FINDER";
27 | private ActivityMainBinding binding;
28 | private AppBroadcastReceiver broadcastReceiver;
29 | private LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);
30 |
31 | @Inject
32 | DispatchingAndroidInjector supportFragmentInjector;
33 |
34 | @Inject
35 | BottomNavigationItemSelectedListener bottomNavigationItemSelectedListener;
36 |
37 | @Override
38 | public void onCreate(Bundle savedInstanceState) {
39 | AndroidInjection.inject(this);
40 | super.onCreate(savedInstanceState);
41 | binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
42 | broadcastReceiver = new AppBroadcastReceiver();
43 | initNavigation();
44 | }
45 |
46 | @Override
47 | protected void onStart() {
48 | super.onStart();
49 | LocalBroadcastManager.getInstance(this)
50 | .registerReceiver(broadcastReceiver, new IntentFilter(AppBroadcastReceiver.SHOW_ERROR_ACTION));
51 | }
52 |
53 | @Override
54 | protected void onStop() {
55 | super.onStop();
56 | LocalBroadcastManager.getInstance(this)
57 | .unregisterReceiver(broadcastReceiver);
58 | }
59 |
60 | private void initNavigation() {
61 | getLifecycle().addObserver(bottomNavigationItemSelectedListener);
62 | bottomNavigationItemSelectedListener.setCurrentMenuItem(binding.bnvNavigationView.getMenu().getItem(0));
63 | bottomNavigationItemSelectedListener.setFragmentManager(getSupportFragmentManager());
64 | binding.bnvNavigationView.setOnNavigationItemSelectedListener(bottomNavigationItemSelectedListener);
65 | }
66 |
67 | @Override
68 | public LifecycleRegistry getLifecycle() {
69 | return lifecycleRegistry;
70 | }
71 |
72 | @Override
73 | public DispatchingAndroidInjector supportFragmentInjector() {
74 | return supportFragmentInjector;
75 | }
76 |
77 | public class AppBroadcastReceiver extends BroadcastReceiver {
78 | public static final String SHOW_ERROR_ACTION = "show_error";
79 |
80 | @Override
81 | public void onReceive(Context context, Intent intent) {
82 | if (intent.getAction().equals(SHOW_ERROR_ACTION)) {
83 | AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this, R.style.AlertDialogAppCompat);
84 |
85 | if (intent.hasExtra(Extras.ALERT_DIALOG_TITLE))
86 | builder.setTitle(intent.getStringExtra(Extras.ALERT_DIALOG_TITLE));
87 |
88 | if (intent.hasExtra(Extras.ALERT_DIALOG_MESSAGE))
89 | builder.setMessage(intent.getStringExtra(Extras.ALERT_DIALOG_MESSAGE));
90 |
91 | builder.setPositiveButton(android.R.string.ok, null);
92 | builder.create().show();
93 | }
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/NavigationController.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view;
2 |
3 | import android.content.Intent;
4 |
5 | public interface NavigationController {
6 |
7 | void launchActivity(Intent intent);
8 |
9 | void launchActivityForResult(Intent intent, int requestCode);
10 |
11 | void finishCurrentActivity();
12 |
13 | void finishWithResult(Intent data);
14 |
15 | void setActivityResult(Intent data);
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/OnKeyboardStateChangedListener.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view;
2 |
3 | public interface OnKeyboardStateChangedListener {
4 |
5 | void showKeyboard();
6 |
7 | void hideKeyboard();
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/analysenutrition/AnalyseNutritionFragment.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.analysenutrition;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.app.FragmentManager;
8 | import android.support.v4.app.FragmentPagerAdapter;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 |
13 | import com.mlsdev.recipefinder.R;
14 | import com.mlsdev.recipefinder.databinding.FragmentAnalyseNutritionBinding;
15 | import com.mlsdev.recipefinder.view.analysenutrition.ingredient.IngredientAnalysisFragment;
16 | import com.mlsdev.recipefinder.view.analysenutrition.recipe.RecipeAnalysisFragment;
17 | import com.mlsdev.recipefinder.view.fragments.TabFragment;
18 |
19 | public class AnalyseNutritionFragment extends TabFragment {
20 | public static final int INGREDIENT_ANALYSIS_FRAGMENT = 0;
21 | public static final int RECIPE_ANALYSIS_FRAGMENT = 1;
22 | public static final int PAGES_NUMBER = 2;
23 | private FragmentAnalyseNutritionBinding binding;
24 | private ViewPagerAdapter pagerAdapter;
25 |
26 | @Nullable
27 | @Override
28 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
29 | @Nullable Bundle savedInstanceState) {
30 |
31 | binding = DataBindingUtil.inflate(inflater, R.layout.fragment_analyse_nutrition, container, false);
32 | initViewPager();
33 | return binding.getRoot();
34 | }
35 |
36 | private void initViewPager() {
37 | pagerAdapter = new ViewPagerAdapter(getChildFragmentManager());
38 | binding.vpAnalysisPages.setAdapter(pagerAdapter);
39 | binding.vpAnalysisPages.setOffscreenPageLimit(PAGES_NUMBER);
40 | binding.tlAnalysisTabs.setupWithViewPager(binding.vpAnalysisPages);
41 | }
42 |
43 | public class ViewPagerAdapter extends FragmentPagerAdapter {
44 | Fragment nutritionAnalysisFragment;
45 | Fragment recipeAnalysisFragment;
46 |
47 | public ViewPagerAdapter(FragmentManager fm) {
48 | super(fm);
49 | nutritionAnalysisFragment = new IngredientAnalysisFragment();
50 | recipeAnalysisFragment = new RecipeAnalysisFragment();
51 | }
52 |
53 | @Override
54 | public Fragment getItem(int position) {
55 | return position == RECIPE_ANALYSIS_FRAGMENT
56 | ? recipeAnalysisFragment
57 | : nutritionAnalysisFragment;
58 | }
59 |
60 | @Override
61 | public int getCount() {
62 | return PAGES_NUMBER;
63 | }
64 |
65 | @Override
66 | public CharSequence getPageTitle(int position) {
67 | return getString(position == RECIPE_ANALYSIS_FRAGMENT
68 | ? R.string.tab_recipe_analysis
69 | : R.string.tab_nutrition_analysis);
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/analysenutrition/adapter/BaseViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.analysenutrition.adapter;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.View;
5 |
6 |
7 | public abstract class BaseViewHolder extends RecyclerView.ViewHolder {
8 | public BaseViewHolder(View itemView) {
9 | super(itemView);
10 | }
11 |
12 | public abstract void bindViewModel();
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/analysenutrition/adapter/ProgressViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.analysenutrition.adapter;
2 |
3 | import com.mlsdev.recipefinder.databinding.ProgressViewBinding;
4 |
5 | public class ProgressViewHolder extends BaseViewHolder {
6 |
7 | public ProgressViewHolder(ProgressViewBinding binding) {
8 | super(binding.getRoot());
9 | }
10 |
11 | @Override
12 | public void bindViewModel() {
13 |
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/analysenutrition/ingredient/IngredientAnalysisFragment.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.analysenutrition.ingredient;
2 |
3 | import android.arch.lifecycle.ViewModelProvider;
4 | import android.arch.lifecycle.ViewModelProviders;
5 | import android.databinding.DataBindingUtil;
6 | import android.os.Bundle;
7 | import android.support.annotation.Nullable;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 |
12 | import com.github.mikephil.charting.data.PieData;
13 | import com.mlsdev.recipefinder.R;
14 | import com.mlsdev.recipefinder.databinding.FragmentIngredientAnalysisBinding;
15 | import com.mlsdev.recipefinder.di.Injectable;
16 | import com.mlsdev.recipefinder.view.MainActivity;
17 | import com.mlsdev.recipefinder.view.OnKeyboardStateChangedListener;
18 | import com.mlsdev.recipefinder.view.fragment.BaseFragment;
19 | import com.mlsdev.recipefinder.view.listener.OnIngredientAnalyzedListener;
20 | import com.mlsdev.recipefinder.view.utils.DiagramUtils;
21 |
22 | import javax.inject.Inject;
23 |
24 | public class IngredientAnalysisFragment extends BaseFragment implements OnIngredientAnalyzedListener,
25 | OnKeyboardStateChangedListener, Injectable {
26 | private FragmentIngredientAnalysisBinding binding;
27 | private IngredientAnalysisViewModel viewModel;
28 |
29 | @Inject
30 | ViewModelProvider.Factory viewModelFactory;
31 |
32 | @Inject
33 | DiagramUtils diagramUtils;
34 |
35 | @Override
36 | public void onCreate(@Nullable Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | }
39 |
40 | @Override
41 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
42 | binding = DataBindingUtil.inflate(inflater, R.layout.fragment_ingredient_analysis, container, false);
43 |
44 | if (viewModel == null)
45 | viewModel = ViewModelProviders.of(this, viewModelFactory).get(IngredientAnalysisViewModel.class);
46 |
47 | getLifecycle().addObserver(viewModel);
48 | viewModel.setKeyboardListener(this);
49 | viewModel.setOnIngredientAnalyzedListener(this);
50 | viewModel.setActionListener(this);
51 |
52 | binding.setViewModel(viewModel);
53 | diagramUtils.preparePieChart(binding.pieChart);
54 | return binding.getRoot();
55 | }
56 |
57 | @Override
58 | public void onStop() {
59 | super.onStop();
60 | binding.etIngredientInput.clearFocus();
61 | }
62 |
63 | @Override
64 | public void onIngredientAnalyzed(PieData diagramData) {
65 | diagramUtils.setData(binding.pieChart, diagramData);
66 | }
67 |
68 | @Override
69 | public void showKeyboard() {
70 | ((MainActivity) getActivity()).showSoftKeyboard();
71 | }
72 |
73 | @Override
74 | public void hideKeyboard() {
75 | ((MainActivity) getActivity()).hideSoftKeyboard();
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/analysenutrition/recipe/AddIngredientDialogFragment.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.analysenutrition.recipe;
2 |
3 | import android.app.Activity;
4 | import android.app.Dialog;
5 | import android.content.DialogInterface;
6 | import android.content.Intent;
7 | import android.databinding.DataBindingUtil;
8 | import android.os.Bundle;
9 | import android.support.v4.app.DialogFragment;
10 | import android.support.v7.app.AlertDialog;
11 | import android.view.LayoutInflater;
12 |
13 | import com.mlsdev.recipefinder.R;
14 | import com.mlsdev.recipefinder.databinding.DialogFragmentAddIngredientBinding;
15 | import com.mlsdev.recipefinder.view.BaseActivity;
16 |
17 | public class AddIngredientDialogFragment extends DialogFragment {
18 | public static final String INGREDIENT_TITLE_KEY = "ingredient_label_key";
19 | private DialogFragmentAddIngredientBinding binding;
20 |
21 | @Override
22 | public Dialog onCreateDialog(Bundle savedInstanceState) {
23 | binding = DataBindingUtil
24 | .inflate(LayoutInflater.from(getActivity()), R.layout.dialog_fragment_add_ingredient, null, false);
25 |
26 | ((BaseActivity) getActivity()).showSoftKeyboard();
27 |
28 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AlertDialogAppCompat);
29 | builder.setTitle("Add Ingredient")
30 | .setView(binding.getRoot())
31 | .setNegativeButton(android.R.string.cancel, null)
32 | .setPositiveButton(R.string.btn_add, new DialogInterface.OnClickListener() {
33 | @Override
34 | public void onClick(DialogInterface dialogInterface, int i) {
35 | Intent data = new Intent();
36 | data.putExtra(INGREDIENT_TITLE_KEY, binding.etIngredientInput.getText().toString());
37 |
38 | if (getTargetFragment() != null) {
39 | getTargetFragment().onActivityResult(
40 | RecipeAnalysisViewModel.ADD_INGREDIENT_REQUEST_CODE,
41 | Activity.RESULT_OK,
42 | data);
43 | }
44 |
45 | dismiss();
46 | }
47 | });
48 |
49 | return builder.create();
50 | }
51 |
52 | @Override
53 | public void onDismiss(DialogInterface dialog) {
54 | if (getActivity() != null)
55 | ((BaseActivity) getActivity()).hideSoftKeyboard();
56 | super.onDismiss(dialog);
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/analysenutrition/recipe/OnAddIngredientClickListener.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.analysenutrition.recipe;
2 |
3 | public interface OnAddIngredientClickListener {
4 | void onAddIngredientButtonClick();
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/analysenutrition/recipe/RecipeAnalysisDetailsActivity.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.analysenutrition.recipe;
2 |
3 | import android.arch.lifecycle.LifecycleRegistry;
4 | import android.arch.lifecycle.LifecycleRegistryOwner;
5 | import android.arch.lifecycle.ViewModelProvider;
6 | import android.arch.lifecycle.ViewModelProviders;
7 | import android.databinding.DataBindingUtil;
8 | import android.os.Bundle;
9 | import android.support.v4.app.Fragment;
10 | import android.view.MenuItem;
11 |
12 | import com.github.mikephil.charting.data.PieData;
13 | import com.mlsdev.recipefinder.R;
14 | import com.mlsdev.recipefinder.databinding.ActivityRecipeAnalysisDetailsBinding;
15 | import com.mlsdev.recipefinder.view.BaseActivity;
16 | import com.mlsdev.recipefinder.view.listener.OnDataLoadedListener;
17 | import com.mlsdev.recipefinder.view.utils.DiagramUtils;
18 |
19 | import javax.inject.Inject;
20 |
21 | import dagger.android.DispatchingAndroidInjector;
22 | import dagger.android.support.HasSupportFragmentInjector;
23 |
24 | public class RecipeAnalysisDetailsActivity extends BaseActivity implements HasSupportFragmentInjector, LifecycleRegistryOwner, OnDataLoadedListener {
25 | public static final String RECIPE_ANALYSING_RESULT_KEY = "recipe_analysing_result";
26 | private ActivityRecipeAnalysisDetailsBinding binding;
27 | private LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);
28 | private RecipeAnalysisDetailsViewModel viewModel;
29 |
30 | @Inject
31 | ViewModelProvider.Factory viewModelFactory;
32 |
33 | @Inject
34 | DiagramUtils diagramUtils;
35 |
36 | @Inject
37 | DispatchingAndroidInjector supportFragmentInjector;
38 |
39 | @Override
40 | public void onCreate(Bundle savedInstanceState) {
41 | super.onCreate(savedInstanceState);
42 | binding = DataBindingUtil.setContentView(this, R.layout.activity_recipe_analysis_details);
43 |
44 | if (viewModel == null) {
45 | viewModel = ViewModelProviders.of(this, viewModelFactory).get(RecipeAnalysisDetailsViewModel.class);
46 | viewModel.setData(getIntent().getExtras());
47 | }
48 |
49 | getLifecycle().addObserver(viewModel);
50 | viewModel.setOnDataLoadedListener(this);
51 | binding.setViewModel(viewModel);
52 | diagramUtils.preparePieChart(binding.pieChart);
53 |
54 | setSupportActionBar(binding.toolbar);
55 |
56 | if (getSupportActionBar() != null)
57 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
58 | }
59 |
60 | @Override
61 | public boolean onOptionsItemSelected(MenuItem item) {
62 | if (item.getItemId() == android.R.id.home)
63 | onBackPressed();
64 | return super.onOptionsItemSelected(item);
65 | }
66 |
67 | @Override
68 | public DispatchingAndroidInjector supportFragmentInjector() {
69 | return supportFragmentInjector;
70 | }
71 |
72 | @Override
73 | public LifecycleRegistry getLifecycle() {
74 | return lifecycleRegistry;
75 | }
76 |
77 | @Override
78 | public void onDataLoaded(PieData pieData) {
79 | diagramUtils.setData(binding.pieChart, pieData);
80 | }
81 |
82 | @Override
83 | public void onMoreDataLoaded(PieData moreRecipes) {
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/analysenutrition/recipe/RecipeAnalysisDetailsViewModel.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.analysenutrition.recipe;
2 |
3 | import android.arch.lifecycle.Lifecycle;
4 | import android.arch.lifecycle.LifecycleObserver;
5 | import android.arch.lifecycle.OnLifecycleEvent;
6 | import android.databinding.ObservableField;
7 | import android.databinding.ObservableInt;
8 | import android.os.Bundle;
9 | import android.util.Log;
10 | import android.view.View;
11 |
12 | import com.github.mikephil.charting.data.PieData;
13 | import com.github.mikephil.charting.data.PieDataSet;
14 | import com.github.mikephil.charting.data.PieEntry;
15 | import com.mlsdev.recipefinder.R;
16 | import com.mlsdev.recipefinder.data.entity.nutrition.NutritionAnalysisResult;
17 | import com.mlsdev.recipefinder.view.listener.OnDataLoadedListener;
18 | import com.mlsdev.recipefinder.view.utils.DiagramUtils;
19 | import com.mlsdev.recipefinder.view.viewmodel.BaseViewModel;
20 |
21 | import java.util.List;
22 |
23 | import javax.inject.Inject;
24 |
25 | public class RecipeAnalysisDetailsViewModel extends BaseViewModel implements LifecycleObserver {
26 |
27 | public final ObservableField calories = new ObservableField<>();
28 | public final ObservableField yield = new ObservableField<>();
29 | public final ObservableInt chartVisibility = new ObservableInt(View.GONE);
30 | private DiagramUtils diagramUtils;
31 | private PieData pieData;
32 | private OnDataLoadedListener onDataLoadedListener;
33 |
34 | @Inject
35 | public RecipeAnalysisDetailsViewModel(DiagramUtils diagramUtils) {
36 | this.diagramUtils = diagramUtils;
37 | }
38 |
39 | public void setOnDataLoadedListener(OnDataLoadedListener onDataLoadedListener) {
40 | this.onDataLoadedListener = onDataLoadedListener;
41 | }
42 |
43 | @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
44 | void start() {
45 | if (onDataLoadedListener != null)
46 | onDataLoadedListener.onDataLoaded(pieData);
47 | }
48 |
49 | @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
50 | void stop() {
51 | Log.d("RF", "lifecycle stop");
52 | }
53 |
54 | public void setData(Bundle recipeAnalysingData) {
55 | NutritionAnalysisResult nutritionAnalysisResult = recipeAnalysingData
56 | .getParcelable(RecipeAnalysisDetailsActivity.RECIPE_ANALYSING_RESULT_KEY);
57 |
58 | showResults(nutritionAnalysisResult);
59 | }
60 |
61 | private void showResults(NutritionAnalysisResult nutritionAnalysisResult) {
62 | if (nutritionAnalysisResult == null)
63 | return;
64 |
65 | calories.set(context.getString(R.string.calories, nutritionAnalysisResult.getCalories()));
66 | yield.set(context.getString(R.string.yields, String.valueOf(nutritionAnalysisResult.getYield())));
67 |
68 | List pieEntries = diagramUtils.preparePieEntries(nutritionAnalysisResult.getTotalNutrients());
69 | chartVisibility.set(pieEntries.isEmpty() ? View.GONE : View.VISIBLE);
70 |
71 | if (pieEntries.isEmpty())
72 | return;
73 |
74 | PieDataSet pieDataSet = diagramUtils.createPieDataSet(pieEntries, "Nutrients", null);
75 | pieData = diagramUtils.createPieData(pieDataSet);
76 |
77 | if (onDataLoadedListener != null)
78 | onDataLoadedListener.onDataLoaded(pieData);
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/analysenutrition/recipe/RecipeAnalysisFragment.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.analysenutrition.recipe;
2 |
3 | import android.app.Activity;
4 | import android.arch.lifecycle.ViewModelProvider;
5 | import android.arch.lifecycle.ViewModelProviders;
6 | import android.content.Intent;
7 | import android.databinding.DataBindingUtil;
8 | import android.os.Bundle;
9 | import android.support.annotation.Nullable;
10 | import android.support.v7.widget.LinearLayoutManager;
11 | import android.view.LayoutInflater;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 |
15 | import com.mlsdev.recipefinder.R;
16 | import com.mlsdev.recipefinder.databinding.FragmentRecipeAnalysisBinding;
17 | import com.mlsdev.recipefinder.di.Injectable;
18 | import com.mlsdev.recipefinder.view.fragment.BaseFragment;
19 | import com.mlsdev.recipefinder.view.listener.OnDataLoadedListener;
20 |
21 | import java.util.List;
22 |
23 | import javax.inject.Inject;
24 |
25 | public class RecipeAnalysisFragment extends BaseFragment implements OnAddIngredientClickListener,
26 | OnDataLoadedListener>, Injectable {
27 | private FragmentRecipeAnalysisBinding binding;
28 | private RecipeAnalysisViewModel viewModel;
29 | private IngredientsAdapter adapter;
30 |
31 | @Inject
32 | ViewModelProvider.Factory viewModelFactory;
33 |
34 | @Override
35 | public void onCreate(@Nullable Bundle savedInstanceState) {
36 | super.onCreate(savedInstanceState);
37 | }
38 |
39 | @Override
40 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
41 | binding = DataBindingUtil.inflate(inflater, R.layout.fragment_recipe_analysis, container, false);
42 |
43 | if (viewModel == null)
44 | viewModel = ViewModelProviders.of(this, viewModelFactory).get(RecipeAnalysisViewModel.class);
45 |
46 | viewModel.setAddIngredientListener(this);
47 | viewModel.setDataLoadedListener(this);
48 | viewModel.setActionListener(this);
49 |
50 | getLifecycle().addObserver(viewModel);
51 |
52 | binding.setViewModel(viewModel);
53 | initRecyclerView();
54 | return binding.getRoot();
55 | }
56 |
57 | private void initRecyclerView() {
58 | adapter = new IngredientsAdapter(this);
59 | binding.rvIngredients.setHasFixedSize(true);
60 | binding.rvIngredients.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
61 | binding.rvIngredients.setAdapter(adapter);
62 | }
63 |
64 | @Override
65 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
66 |
67 | if (requestCode == RecipeAnalysisViewModel.ADD_INGREDIENT_REQUEST_CODE
68 | && resultCode == Activity.RESULT_OK && data != null) {
69 | adapter.addItem(data);
70 | binding.rvIngredients.smoothScrollToPosition(adapter.getItemCount());
71 | viewModel.setIngredients(adapter.getIngredientList());
72 | }
73 |
74 | }
75 |
76 | @Override
77 | public void onAddIngredientButtonClick() {
78 | AddIngredientDialogFragment dialogFragment = new AddIngredientDialogFragment();
79 | dialogFragment.setTargetFragment(this, RecipeAnalysisViewModel.ADD_INGREDIENT_REQUEST_CODE);
80 | dialogFragment.show(getFragmentManager(), "add_ingredient");
81 | }
82 |
83 | @Override
84 | public void onDataLoaded(List ingredients) {
85 | adapter.setData(ingredients);
86 | }
87 |
88 | @Override
89 | public void onMoreDataLoaded(List moreData) {
90 |
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/analysenutrition/recipe/RecipeAnalysisViewModel.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.analysenutrition.recipe;
2 |
3 | import android.arch.lifecycle.Lifecycle;
4 | import android.arch.lifecycle.LifecycleObserver;
5 | import android.arch.lifecycle.OnLifecycleEvent;
6 | import android.content.Intent;
7 | import android.databinding.ObservableField;
8 | import android.util.Log;
9 | import android.view.View;
10 |
11 | import com.mlsdev.recipefinder.R;
12 | import com.mlsdev.recipefinder.data.entity.nutrition.NutritionAnalysisResult;
13 | import com.mlsdev.recipefinder.data.entity.nutrition.RecipeAnalysisParams;
14 | import com.mlsdev.recipefinder.data.source.BaseObserver;
15 | import com.mlsdev.recipefinder.data.source.repository.DataRepository;
16 | import com.mlsdev.recipefinder.view.MainActivity;
17 | import com.mlsdev.recipefinder.view.listener.OnDataLoadedListener;
18 | import com.mlsdev.recipefinder.view.viewmodel.BaseViewModel;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | import javax.inject.Inject;
24 |
25 | import io.reactivex.android.schedulers.AndroidSchedulers;
26 | import io.reactivex.disposables.Disposable;
27 | import io.reactivex.schedulers.Schedulers;
28 |
29 | public class RecipeAnalysisViewModel extends BaseViewModel implements LifecycleObserver {
30 | public static final int ADD_INGREDIENT_REQUEST_CODE = 0;
31 | public final ObservableField title = new ObservableField<>();
32 | public final ObservableField preparation = new ObservableField<>();
33 | public final ObservableField yield = new ObservableField<>();
34 | private List ingredients = new ArrayList<>();
35 | private OnAddIngredientClickListener addIngredientListener;
36 | private OnDataLoadedListener> dataLoadedListener;
37 |
38 | @Inject
39 | public RecipeAnalysisViewModel(DataRepository repository) {
40 | this.repository = repository;
41 | }
42 |
43 | public void setDataLoadedListener(OnDataLoadedListener> dataLoadedListener) {
44 | this.dataLoadedListener = dataLoadedListener;
45 | }
46 |
47 | public void setAddIngredientListener(OnAddIngredientClickListener addIngredientListener) {
48 | this.addIngredientListener = addIngredientListener;
49 | }
50 |
51 | @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
52 | void start() {
53 | dataLoadedListener.onDataLoaded(ingredients);
54 | }
55 |
56 | @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
57 | void stop() {
58 | Log.d("RF", "lifecycle stop");
59 | }
60 |
61 | public void onAnalyzeButtonClick(View view) {
62 | if (ingredients.isEmpty()) {
63 | View.OnClickListener listener = new View.OnClickListener() {
64 | @Override
65 | public void onClick(View v) {
66 | addIngredientListener.onAddIngredientButtonClick();
67 | }
68 | };
69 |
70 | actionListener.showSnackbar(R.string.no_ingredients_error_message, R.string.btn_add, listener);
71 | return;
72 | }
73 |
74 |
75 | actionListener.showProgressDialog(true, "Analysing...");
76 |
77 | RecipeAnalysisParams recipeAnalysisParams = new RecipeAnalysisParams();
78 | recipeAnalysisParams.setTitle(title.get());
79 | recipeAnalysisParams.setYield(yield.get());
80 | recipeAnalysisParams.setPrep(preparation.get());
81 | recipeAnalysisParams.setIngr(ingredients);
82 |
83 | subscriptions.clear();
84 |
85 | repository.getRecipeAnalysisData(recipeAnalysisParams)
86 | .observeOn(AndroidSchedulers.mainThread())
87 | .subscribeOn(Schedulers.io())
88 | .subscribe(new BaseObserver() {
89 | @Override
90 | public void onSuccess(@io.reactivex.annotations.NonNull NutritionAnalysisResult nutritionAnalysisResult) {
91 | actionListener.showProgressDialog(false, null);
92 | Log.d(MainActivity.LOG_TAG, "onNext()");
93 | Intent intent = new Intent(context, RecipeAnalysisDetailsActivity.class);
94 | intent.putExtra(RecipeAnalysisDetailsActivity.RECIPE_ANALYSING_RESULT_KEY, nutritionAnalysisResult);
95 | context.startActivity(intent);
96 | }
97 |
98 | @Override
99 | public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
100 | subscriptions.add(d);
101 | }
102 |
103 | @Override
104 | public void onError(Throwable e) {
105 | super.onError(e);
106 | showError(e);
107 | }
108 | });
109 |
110 | }
111 |
112 | public void setIngredients(List ingredients) {
113 | this.ingredients = ingredients;
114 | }
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/bindingutils/DataBinder.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.bindingutils;
2 |
3 | import android.animation.ObjectAnimator;
4 | import android.databinding.BindingAdapter;
5 | import android.support.design.widget.TextInputEditText;
6 | import android.support.v4.widget.ContentLoadingProgressBar;
7 | import android.widget.ImageView;
8 |
9 | import com.bumptech.glide.Glide;
10 | import com.mlsdev.recipefinder.R;
11 |
12 | public final class DataBinder {
13 |
14 | public DataBinder() {
15 | }
16 |
17 | @BindingAdapter("imageUrl")
18 | public static void setImageUrl(ImageView imageView, String imageUrl) {
19 | if (imageUrl.isEmpty())
20 | return;
21 |
22 | Glide.with(imageView.getContext())
23 | .load(imageUrl)
24 | .override(600, 400)
25 | .error(R.mipmap.ic_launcher)
26 | .into(imageView);
27 | }
28 |
29 | @BindingAdapter("progressValue")
30 | public static void setProgressValue(ContentLoadingProgressBar progressBar, int progressValue) {
31 | ObjectAnimator objectAnimator = ObjectAnimator.ofInt(progressBar, "progress", 0, progressValue);
32 | objectAnimator.setDuration(350);
33 | objectAnimator.setStartDelay(250);
34 | objectAnimator.start();
35 | }
36 |
37 | @BindingAdapter("focused")
38 | public static void setFocused(TextInputEditText editText, boolean requestFocus) {
39 | if (requestFocus)
40 | editText.requestFocus();
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/enums/TabItemType.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.enums;
2 |
3 | public enum TabItemType {
4 | ANALYSE, SEARCH, FAVORITES
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/favoriterecipes/FavoriteRecipesFragment.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.favoriterecipes;
2 |
3 | import android.arch.lifecycle.ViewModelProvider;
4 | import android.arch.lifecycle.ViewModelProviders;
5 | import android.databinding.DataBindingUtil;
6 | import android.os.Bundle;
7 | import android.support.annotation.Nullable;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 |
12 | import com.mlsdev.recipefinder.R;
13 | import com.mlsdev.recipefinder.databinding.FragmentFavoriteRecipesBinding;
14 | import com.mlsdev.recipefinder.di.Injectable;
15 | import com.mlsdev.recipefinder.view.fragment.RecipeListFragment;
16 |
17 | import javax.inject.Inject;
18 |
19 | import static com.mlsdev.recipefinder.view.searchrecipes.RecipeListAdapter.OnLastItemShownListener;
20 |
21 | public class FavoriteRecipesFragment extends RecipeListFragment implements OnLastItemShownListener,
22 | Injectable {
23 | private FragmentFavoriteRecipesBinding binding;
24 | private FavoritesViewModel viewModel;
25 |
26 | @Inject
27 | ViewModelProvider.Factory viewModelFactory;
28 |
29 | @Override
30 | public void onCreate(@Nullable Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | }
33 |
34 | @Override
35 | public View onCreateView(LayoutInflater inflater,
36 | @Nullable ViewGroup container,
37 | @Nullable Bundle savedInstanceState) {
38 |
39 | binding = DataBindingUtil.inflate(inflater, R.layout.fragment_favorite_recipes, container, false);
40 | initRecyclerView(binding.rvRecipeList);
41 |
42 | if (viewModel == null)
43 | viewModel = ViewModelProviders.of(this, viewModelFactory).get(FavoritesViewModel.class);
44 |
45 | getLifecycle().addObserver(viewModel);
46 | viewModel.setOnDataLoadedListener(this);
47 | binding.setViewModel(viewModel);
48 |
49 | return binding.getRoot();
50 | }
51 |
52 | @Override
53 | public void scrollToTop() {
54 | binding.rvRecipeList.smoothScrollToPosition(0);
55 | }
56 |
57 | @Override
58 | public void onDestroy() {
59 | super.onDestroy();
60 | viewModel.onDestroy();
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/favoriterecipes/FavoritesViewModel.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.favoriterecipes;
2 |
3 | import android.arch.lifecycle.Lifecycle;
4 | import android.arch.lifecycle.LifecycleObserver;
5 | import android.arch.lifecycle.OnLifecycleEvent;
6 | import android.databinding.ObservableInt;
7 | import android.view.View;
8 |
9 | import com.mlsdev.recipefinder.data.entity.recipe.Recipe;
10 | import com.mlsdev.recipefinder.data.source.repository.DataRepository;
11 | import com.mlsdev.recipefinder.view.listener.OnDataLoadedListener;
12 | import com.mlsdev.recipefinder.view.viewmodel.BaseViewModel;
13 |
14 | import java.util.List;
15 |
16 | import javax.inject.Inject;
17 |
18 | import io.reactivex.android.schedulers.AndroidSchedulers;
19 | import io.reactivex.annotations.NonNull;
20 | import io.reactivex.disposables.Disposable;
21 | import io.reactivex.functions.Consumer;
22 | import io.reactivex.schedulers.Schedulers;
23 |
24 | public class FavoritesViewModel extends BaseViewModel implements LifecycleObserver {
25 | private OnDataLoadedListener> onDataLoadedListener;
26 | public final ObservableInt emptyViewVisibility;
27 |
28 | @Inject
29 | public FavoritesViewModel(DataRepository repository) {
30 | this.repository = repository;
31 | emptyViewVisibility = new ObservableInt(View.VISIBLE);
32 | }
33 |
34 | public void setOnDataLoadedListener(OnDataLoadedListener> onDataLoadedListener) {
35 | this.onDataLoadedListener = onDataLoadedListener;
36 | }
37 |
38 | @Override
39 | public void onStop() {
40 | super.onStop();
41 | subscriptions.clear();
42 | }
43 |
44 | @OnLifecycleEvent(Lifecycle.Event.ON_START)
45 | public void start() {
46 | getFavoriteRecipes();
47 | }
48 |
49 | @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
50 | public void stop() {
51 | }
52 |
53 | public void getFavoriteRecipes() {
54 | Disposable disposable = repository.getFavoriteRecipes()
55 | .observeOn(AndroidSchedulers.mainThread())
56 | .subscribeOn(Schedulers.io())
57 | .subscribe(new Consumer>() {
58 | @Override
59 | public void accept(@NonNull List recipes) throws Exception {
60 | emptyViewVisibility.set(recipes.isEmpty() ? View.VISIBLE : View.INVISIBLE);
61 | onDataLoadedListener.onDataLoaded(recipes);
62 | }
63 | });
64 |
65 | subscriptions.add(disposable);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/fragment/BaseFragment.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.fragment;
2 |
3 | import android.arch.lifecycle.LifecycleFragment;
4 | import android.support.annotation.StringRes;
5 | import android.view.View;
6 |
7 | import com.mlsdev.recipefinder.view.ActionListener;
8 | import com.mlsdev.recipefinder.view.BaseActivity;
9 |
10 | public class BaseFragment extends LifecycleFragment implements ActionListener {
11 |
12 | @Override
13 | public void onStartFilter() {
14 |
15 | }
16 |
17 | @Override
18 | public void showProgressDialog(boolean show, String message) {
19 | ((BaseActivity) getActivity()).showProgressDialog(show, message);
20 | }
21 |
22 | @Override
23 | public void showSnackbar(@StringRes int message) {
24 | ((BaseActivity) getActivity()).showSnackbar(message);
25 | }
26 |
27 | @Override
28 | public void showSnackbar(String message) {
29 | ((BaseActivity) getActivity()).showSnackbar(message);
30 | }
31 |
32 | @Override
33 | public void showSnackbar(String message, String action, View.OnClickListener listener) {
34 | ((BaseActivity) getActivity()).showSnackbar(message, action, listener);
35 | }
36 |
37 | @Override
38 | public void showSnackbar(@StringRes int message, @StringRes int action, View.OnClickListener listener) {
39 | ((BaseActivity) getActivity()).showSnackbar(message, action, listener);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/fragment/RecipeListFragment.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.fragment;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.drawable.BitmapDrawable;
5 | import android.os.Build;
6 | import android.os.Bundle;
7 | import android.support.v4.app.Fragment;
8 | import android.support.v4.view.ViewCompat;
9 | import android.support.v4.widget.SwipeRefreshLayout;
10 | import android.support.v7.widget.GridLayoutManager;
11 | import android.support.v7.widget.RecyclerView;
12 | import android.transition.Fade;
13 | import android.transition.TransitionInflater;
14 |
15 | import com.bumptech.glide.load.resource.bitmap.GlideBitmapDrawable;
16 | import com.mlsdev.recipefinder.R;
17 | import com.mlsdev.recipefinder.data.entity.recipe.Recipe;
18 | import com.mlsdev.recipefinder.databinding.RecipeListItemBinding;
19 | import com.mlsdev.recipefinder.view.Extras;
20 | import com.mlsdev.recipefinder.view.fragments.TabFragment;
21 | import com.mlsdev.recipefinder.view.listener.OnDataLoadedListener;
22 | import com.mlsdev.recipefinder.view.recipedetails.RecipeDetailsFragment;
23 | import com.mlsdev.recipefinder.view.searchrecipes.RecipeListAdapter;
24 | import com.mlsdev.recipefinder.view.utils.UtilsUI;
25 |
26 | import java.util.List;
27 |
28 | import javax.inject.Inject;
29 |
30 | public class RecipeListFragment extends TabFragment implements RecipeListAdapter.OnItemClickListener,
31 | RecipeListAdapter.OnLastItemShownListener, OnDataLoadedListener> {
32 | protected RecipeListAdapter recipeListAdapter;
33 | protected RecyclerView recipeRecyclerView;
34 | protected SwipeRefreshLayout swipeRefreshLayout;
35 |
36 | @Inject
37 | UtilsUI utilsUI;
38 |
39 | @Override
40 | public void onItemClicked(Recipe recipe, RecipeListItemBinding itemBinding) {
41 | Bundle recipeData = new Bundle();
42 | Fragment fragment = new RecipeDetailsFragment();
43 |
44 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
45 | setSharedElementReturnTransition(TransitionInflater.from(getActivity())
46 | .inflateTransition(R.transition.change_image_transform));
47 | setExitTransition(new Fade());
48 |
49 | fragment.setSharedElementEnterTransition(TransitionInflater.from(getActivity())
50 | .inflateTransition(R.transition.change_image_transform));
51 | fragment.setEnterTransition(new Fade());
52 | }
53 |
54 | recipeData.putSerializable(Extras.DATA, recipe);
55 |
56 | if (itemBinding.ivRecipeImage.getDrawable() != null) {
57 | Bitmap bitmapImage = itemBinding.ivRecipeImage.getDrawable() instanceof GlideBitmapDrawable ?
58 | ((GlideBitmapDrawable) itemBinding.ivRecipeImage.getDrawable()).getBitmap() :
59 | ((BitmapDrawable) itemBinding.ivRecipeImage.getDrawable()).getBitmap();
60 | recipeData.putParcelable(Extras.IMAGE_DATA, bitmapImage);
61 | }
62 |
63 | recipeData.putString(Extras.IMAGE_TRANSITION_NAME, ViewCompat.getTransitionName(itemBinding.ivRecipeImage));
64 |
65 | fragment.setArguments(recipeData);
66 |
67 | getFragmentManager()
68 | .beginTransaction()
69 | .addToBackStack("RecipeDetails")
70 | .replace(R.id.fl_content, fragment)
71 | .addSharedElement(itemBinding.ivRecipeImage, ViewCompat.getTransitionName(itemBinding.ivRecipeImage))
72 | .commit();
73 | }
74 |
75 | @Override
76 | public void onLastItemShown() {
77 |
78 | }
79 |
80 | protected void initRecyclerView(RecyclerView recyclerView) {
81 | int columns = getActivity().getResources().getConfiguration().orientation;
82 |
83 | if (recipeListAdapter == null)
84 | recipeListAdapter = new RecipeListAdapter(this, this);
85 |
86 | recipeRecyclerView = recyclerView;
87 | recipeRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(), columns, GridLayoutManager.VERTICAL, false));
88 | recipeRecyclerView.setHasFixedSize(true);
89 | recipeRecyclerView.setAdapter(recipeListAdapter);
90 | }
91 |
92 | protected void initSwipeRefreshLayout(SwipeRefreshLayout refreshLayout, SwipeRefreshLayout.OnRefreshListener listener) {
93 | swipeRefreshLayout = refreshLayout;
94 | swipeRefreshLayout.setOnRefreshListener(listener);
95 | swipeRefreshLayout.setColorSchemeColors(
96 | utilsUI.getColor(R.color.colorPrimaryDark),
97 | utilsUI.getColor(R.color.colorPrimary),
98 | utilsUI.getColor(R.color.colorAccent)
99 | );
100 | }
101 |
102 | @Override
103 | public void onDataLoaded(List recipes) {
104 | recipeListAdapter.setData(recipes);
105 | stopRefreshing();
106 | }
107 |
108 | @Override
109 | public void onMoreDataLoaded(List moreRecipes) {
110 | recipeListAdapter.setMoreData(moreRecipes);
111 | stopRefreshing();
112 | }
113 |
114 | protected void stopRefreshing() {
115 | if (swipeRefreshLayout != null)
116 | swipeRefreshLayout.setRefreshing(false);
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/fragments/TabFragment.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.fragments;
2 |
3 | import android.support.annotation.Nullable;
4 |
5 | import com.mlsdev.recipefinder.view.analysenutrition.AnalyseNutritionFragment;
6 | import com.mlsdev.recipefinder.view.enums.TabItemType;
7 | import com.mlsdev.recipefinder.view.favoriterecipes.FavoriteRecipesFragment;
8 | import com.mlsdev.recipefinder.view.fragment.BaseFragment;
9 | import com.mlsdev.recipefinder.view.searchrecipes.SearchRecipeFragment;
10 |
11 | public abstract class TabFragment extends BaseFragment {
12 |
13 | @Nullable
14 | public static TabFragment getNewInstance(TabItemType tabItemType) {
15 |
16 | switch (tabItemType) {
17 | case ANALYSE:
18 | return new AnalyseNutritionFragment();
19 | case SEARCH:
20 | return new SearchRecipeFragment();
21 | case FAVORITES:
22 | return new FavoriteRecipesFragment();
23 | default:
24 | return null;
25 | }
26 |
27 | }
28 |
29 | /**
30 | * Scrolls the root view of the fragment to top by clicking on a current tab in the navigation view.
31 | */
32 | public void scrollToTop() {
33 |
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/listener/OnDataLoadedListener.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.listener;
2 |
3 | public interface OnDataLoadedListener {
4 | void onDataLoaded(T recipes);
5 |
6 | void onMoreDataLoaded(T moreRecipes);
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/listener/OnIngredientAnalyzedListener.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.listener;
2 |
3 | import com.github.mikephil.charting.data.PieData;
4 |
5 | public interface OnIngredientAnalyzedListener {
6 | void onIngredientAnalyzed(PieData diagramData);
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/message/Message.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.message;
2 |
3 | import com.mlsdev.recipefinder.view.BaseActivity;
4 |
5 | public class Message {
6 |
7 | protected BaseActivity activity;
8 |
9 | public Message(BaseActivity activity) {
10 | this.activity = activity;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/message/ProgressDialogMessage.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.message;
2 |
3 | import android.app.ProgressDialog;
4 | import android.support.annotation.Nullable;
5 |
6 | import com.mlsdev.recipefinder.R;
7 | import com.mlsdev.recipefinder.view.BaseActivity;
8 |
9 | public class ProgressDialogMessage extends Message {
10 | private ProgressDialog progressDialog;
11 |
12 | public ProgressDialogMessage(BaseActivity activity) {
13 | super(activity);
14 | }
15 |
16 | public void showProgressDialog(boolean isShow, @Nullable String message) {
17 | if (progressDialog == null) {
18 | progressDialog = new ProgressDialog(activity, R.style.AlertDialogAppCompat);
19 | progressDialog.setIndeterminate(true);
20 | progressDialog.setMessage(message);
21 | }
22 |
23 | if (isShow)
24 | progressDialog.show();
25 | else
26 | progressDialog.dismiss();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/message/SnackbarMessage.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.message;
2 |
3 | import android.support.annotation.StringRes;
4 | import android.support.design.widget.Snackbar;
5 | import android.view.View;
6 |
7 | import com.mlsdev.recipefinder.R;
8 | import com.mlsdev.recipefinder.view.BaseActivity;
9 |
10 | public class SnackbarMessage extends Message {
11 |
12 | public SnackbarMessage(BaseActivity activity) {
13 | super(activity);
14 | }
15 |
16 | public void showSnackbar(@StringRes int message) {
17 | if (activity != null)
18 | showSnackbar(activity.getString(message));
19 | }
20 |
21 | public void showSnackbar(String message) {
22 | showSnackbar(message, null, null);
23 | }
24 |
25 | public void showSnackbar(@StringRes int message, @StringRes int action, View.OnClickListener listener) {
26 | if (activity != null)
27 | showSnackbar(activity.getString(message), activity.getString(action), listener);
28 | }
29 |
30 | public void showSnackbar(String message, String action, View.OnClickListener listener) {
31 | if (activity != null) {
32 | String tag = activity.getString(R.string.content_tag);
33 | View view = activity.getWindow().getDecorView().findViewWithTag(tag);
34 | if (view != null) {
35 | Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_LONG);
36 |
37 | if (action != null && listener != null)
38 | snackbar.setAction(action, listener);
39 |
40 | snackbar.show();
41 | }
42 |
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/recipedetails/RecipeDetailsFragment.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.recipedetails;
2 |
3 | import android.arch.lifecycle.ViewModelProvider;
4 | import android.arch.lifecycle.ViewModelProviders;
5 | import android.databinding.DataBindingUtil;
6 | import android.graphics.Bitmap;
7 | import android.os.Bundle;
8 | import android.support.annotation.Nullable;
9 | import android.support.v4.view.ViewCompat;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 |
14 | import com.mlsdev.recipefinder.R;
15 | import com.mlsdev.recipefinder.databinding.FragmentRecipeDetailsBinding;
16 | import com.mlsdev.recipefinder.di.Injectable;
17 | import com.mlsdev.recipefinder.view.Extras;
18 | import com.mlsdev.recipefinder.view.MainActivity;
19 | import com.mlsdev.recipefinder.view.fragment.BaseFragment;
20 |
21 | import javax.inject.Inject;
22 |
23 | public class RecipeDetailsFragment extends BaseFragment implements Injectable {
24 | private FragmentRecipeDetailsBinding binding;
25 | private RecipeViewModel viewModel;
26 |
27 | @Inject
28 | ViewModelProvider.Factory viewModelFactory;
29 |
30 | @Override
31 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
32 | viewModel = ViewModelProviders.of(this, viewModelFactory).get(RecipeViewModel.class);
33 | viewModel.setRecipeData(getArguments());
34 | viewModel.setActionListener(this);
35 | binding = DataBindingUtil.inflate(inflater, R.layout.fragment_recipe_details, container, false);
36 | binding.setViewModel(viewModel);
37 |
38 | ((MainActivity) getActivity()).setSupportActionBar(binding.toolbar);
39 | if (((MainActivity) getActivity()).getSupportActionBar() != null) {
40 | ((MainActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
41 | }
42 |
43 | String imageTransitionName = getArguments().getString(Extras.IMAGE_TRANSITION_NAME);
44 |
45 | if (imageTransitionName != null)
46 | ViewCompat.setTransitionName(binding.ivRecipeImage, imageTransitionName);
47 |
48 | Bitmap bitmap = getArguments().getParcelable(Extras.IMAGE_DATA);
49 | if (bitmap != null)
50 | binding.ivRecipeImage.setImageBitmap(bitmap);
51 |
52 | return binding.getRoot();
53 | }
54 |
55 | @Override
56 | public void onStart() {
57 | super.onStart();
58 | viewModel.onStart();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/searchrecipes/FilterDialogFragment.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.searchrecipes;
2 |
3 | import android.app.Activity;
4 | import android.app.Dialog;
5 | import android.content.DialogInterface;
6 | import android.content.Intent;
7 | import android.databinding.DataBindingUtil;
8 | import android.os.Bundle;
9 | import android.support.annotation.NonNull;
10 | import android.support.v4.app.DialogFragment;
11 | import android.support.v7.app.AlertDialog;
12 | import android.view.LayoutInflater;
13 |
14 | import com.mlsdev.recipefinder.R;
15 | import com.mlsdev.recipefinder.databinding.DialogFragmentSearchFilterBinding;
16 |
17 | public class FilterDialogFragment extends DialogFragment {
18 | private DialogFragmentSearchFilterBinding binding;
19 | public static final String HEALTH_LABEL_KEY = "health_label_key";
20 | public static final String DIET_LABEL_KEY = "diet_label_key";
21 | private int healthSelectedIndex;
22 | private int dietSelectedIndex;
23 |
24 | @Override
25 | public void onStart() {
26 | super.onStart();
27 | binding.spHealthLabels.setSelection(healthSelectedIndex);
28 | binding.spDietLabels.setSelection(dietSelectedIndex);
29 | }
30 |
31 | @NonNull
32 | @Override
33 | public Dialog onCreateDialog(Bundle savedInstanceState) {
34 | LayoutInflater inflater = getActivity().getLayoutInflater();
35 | binding = DataBindingUtil.inflate(inflater, R.layout.dialog_fragment_search_filter, null, false);
36 |
37 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AlertDialogAppCompat);
38 | builder.setView(binding.getRoot())
39 | .setTitle(R.string.dialog_title_filter)
40 | .setPositiveButton(R.string.btn_apply_filter, new DialogInterface.OnClickListener() {
41 | @Override
42 | public void onClick(DialogInterface dialogInterface, int i) {
43 | Intent data = new Intent();
44 | healthSelectedIndex = binding.spHealthLabels.getSelectedItemPosition();
45 | dietSelectedIndex = binding.spDietLabels.getSelectedItemPosition();
46 | data.putExtra(HEALTH_LABEL_KEY, (String) binding.spHealthLabels.getSelectedItem());
47 | data.putExtra(DIET_LABEL_KEY, (String) binding.spDietLabels.getSelectedItem());
48 |
49 | if (getTargetFragment() != null) {
50 | getTargetFragment().onActivityResult(SearchRecipeFragment.FILTER_REQUEST_CODE,
51 | Activity.RESULT_OK, data);
52 | }
53 |
54 | dismiss();
55 | }
56 | });
57 |
58 |
59 | return builder.create();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/searchrecipes/RecipeListItemViewModel.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.searchrecipes;
2 |
3 | import android.databinding.ObservableField;
4 |
5 | import com.mlsdev.recipefinder.data.entity.recipe.Recipe;
6 |
7 | public class RecipeListItemViewModel {
8 | private Recipe recipe;
9 | public final ObservableField recipeTitle;
10 | public final ObservableField recipeImageUrl;
11 |
12 | public RecipeListItemViewModel(Recipe recipe) {
13 | this.recipe = recipe;
14 | recipeTitle = new ObservableField<>(recipe.getLabel());
15 | recipeImageUrl = new ObservableField<>(recipe.getImage());
16 | }
17 |
18 | public void setRecipe(Recipe recipe) {
19 | this.recipe = recipe;
20 | recipeTitle.set(recipe.getLabel());
21 | recipeImageUrl.set(recipe.getImage());
22 | }
23 |
24 | public Recipe getRecipe() {
25 | return recipe;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/utils/DiagramUtils.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.utils;
2 |
3 | import android.support.annotation.Nullable;
4 |
5 | import com.github.mikephil.charting.animation.Easing;
6 | import com.github.mikephil.charting.charts.PieChart;
7 | import com.github.mikephil.charting.components.Legend;
8 | import com.github.mikephil.charting.data.PieData;
9 | import com.github.mikephil.charting.data.PieDataSet;
10 | import com.github.mikephil.charting.data.PieEntry;
11 | import com.github.mikephil.charting.formatter.PercentFormatter;
12 | import com.mlsdev.recipefinder.R;
13 | import com.mlsdev.recipefinder.data.entity.nutrition.TotalNutrients;
14 |
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | public class DiagramUtils {
19 | private UtilsUI utilsUI;
20 |
21 | public DiagramUtils(UtilsUI utilsUI) {
22 | this.utilsUI = utilsUI;
23 | }
24 |
25 | public ArrayList preparePieEntries(TotalNutrients nutrients) {
26 | ArrayList entries = new ArrayList<>(3);
27 | if (nutrients.getProtein() != null)
28 | entries.add(new PieEntry((float) nutrients.getProtein().getQuantity(), nutrients.getProtein().getLabel()));
29 | if (nutrients.getFat() != null)
30 | entries.add(new PieEntry((float) nutrients.getFat().getQuantity(), nutrients.getFat().getLabel()));
31 | if (nutrients.getCarbs() != null)
32 | entries.add(new PieEntry((float) nutrients.getCarbs().getQuantity(), nutrients.getCarbs().getLabel()));
33 |
34 | return entries;
35 | }
36 |
37 | public PieChart preparePieChart(PieChart pieChart) {
38 | pieChart.setUsePercentValues(true);
39 | pieChart.getDescription().setEnabled(false);
40 | pieChart.setExtraOffsets(5, 10, 5, 5);
41 | pieChart.setDragDecelerationFrictionCoef(0.96f);
42 |
43 | pieChart.setDrawHoleEnabled(true);
44 | pieChart.setHoleColor(android.R.color.transparent);
45 |
46 | pieChart.setTransparentCircleColor(utilsUI.getColor(android.R.color.white));
47 | pieChart.setTransparentCircleAlpha(50);
48 |
49 | pieChart.setHoleRadius(40f);
50 | pieChart.setTransparentCircleRadius(45f);
51 |
52 | pieChart.setDrawCenterText(true);
53 | pieChart.setCenterText("Balance");
54 |
55 | pieChart.setRotationAngle(0);
56 | // enable rotation of the chart by touch
57 | pieChart.setRotationEnabled(false);
58 | pieChart.setHighlightPerTapEnabled(true);
59 | pieChart.setDrawEntryLabels(true);
60 | pieChart.setEntryLabelColor(utilsUI.getColor(android.R.color.white));
61 | pieChart.setEntryLabelTextSize(15f);
62 |
63 | Legend l = pieChart.getLegend();
64 | l.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
65 | l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER);
66 | l.setOrientation(Legend.LegendOrientation.HORIZONTAL);
67 | l.setDrawInside(false);
68 |
69 | return pieChart;
70 | }
71 |
72 | public PieDataSet createPieDataSet(List pieEntryList,
73 | @Nullable String label,
74 | @Nullable List colors) {
75 | PieDataSet pieDataSet = new PieDataSet(pieEntryList, label);
76 | pieDataSet.setSliceSpace(1.5f);
77 | pieDataSet.setSelectionShift(2f);
78 |
79 | pieDataSet.setDrawValues(true);
80 |
81 | if (colors == null) {
82 | colors = new ArrayList<>(3);
83 | colors.add(utilsUI.getColor(R.color.colorPrimaryDark));
84 | colors.add(utilsUI.getColor(R.color.colorPrimary));
85 | colors.add(utilsUI.getColor(R.color.colorAccent));
86 | }
87 |
88 | pieDataSet.setColors(colors);
89 | return pieDataSet;
90 | }
91 |
92 | public PieData createPieData(PieDataSet pieDataSet) {
93 | PieData pieData = new PieData(pieDataSet);
94 | pieData.setValueFormatter(new PercentFormatter());
95 | pieData.setValueTextSize(15f);
96 | pieData.setValueTextColor(utilsUI.getColor(android.R.color.white));
97 | return pieData;
98 | }
99 |
100 | public void setData(PieChart pieChart, PieData pieData) {
101 | pieChart.setData(pieData);
102 | pieChart.highlightValue(null);
103 | pieChart.invalidate();
104 | pieChart.animateY(1400, Easing.EasingOption.EaseInOutQuad);
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/utils/ParamsHelper.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.utils;
2 |
3 | public class ParamsHelper {
4 |
5 | public static String formatLabel(String label) {
6 | if (label == null)
7 | throw new IllegalArgumentException("'label' can't be 'null'");
8 |
9 | String formattedLabel = label.toLowerCase();
10 | formattedLabel = formattedLabel.replaceAll(" ", "-");
11 | return formattedLabel;
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/utils/UtilsUI.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.utils;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.ColorInt;
5 | import android.support.annotation.ColorRes;
6 |
7 | import com.mlsdev.recipefinder.RecipeApplication;
8 |
9 | import java.text.DecimalFormat;
10 |
11 | public class UtilsUI {
12 | private Context context;
13 |
14 | public UtilsUI() {
15 | this.context = RecipeApplication.getInstance();
16 | }
17 |
18 | @ColorInt
19 | public int getColor(@ColorRes int colorResId) {
20 | @ColorInt int color = 0;
21 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
22 | color = context.getResources().getColor(colorResId, context.getTheme());
23 | } else {
24 | color = context.getResources().getColor(colorResId);
25 | }
26 | return color;
27 | }
28 |
29 | public static String formatDecimalToString(double value) {
30 | return new DecimalFormat("#0.00").format(value);
31 | }
32 |
33 | public static int getPersents(double fullValue, double partValue) {
34 | return (int) ((partValue / fullValue) * 100);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/viewmodel/BaseViewModel.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.viewmodel;
2 |
3 | import android.arch.lifecycle.ViewModel;
4 | import android.content.Context;
5 | import android.support.annotation.NonNull;
6 |
7 | import com.mlsdev.recipefinder.R;
8 | import com.mlsdev.recipefinder.RecipeApplication;
9 | import com.mlsdev.recipefinder.data.source.BaseObserver;
10 | import com.mlsdev.recipefinder.data.source.repository.DataRepository;
11 | import com.mlsdev.recipefinder.view.ActionListener;
12 |
13 | import java.io.IOException;
14 |
15 | import io.reactivex.disposables.CompositeDisposable;
16 | import retrofit2.HttpException;
17 |
18 | public class BaseViewModel extends ViewModel {
19 | protected Context context = RecipeApplication.getInstance();
20 | protected DataRepository repository;
21 | protected CompositeDisposable subscriptions;
22 | protected ActionListener actionListener;
23 |
24 | public BaseViewModel() {
25 | subscriptions = new CompositeDisposable();
26 | }
27 |
28 | public void onDestroy() {
29 | subscriptions.clear();
30 | }
31 |
32 | public void onStop() {
33 |
34 | }
35 |
36 | public void onStart() {
37 |
38 | }
39 |
40 | public void setActionListener(@NonNull ActionListener actionListener) {
41 | this.actionListener = actionListener;
42 | }
43 |
44 | protected void showError(Throwable throwable) {
45 | actionListener.showProgressDialog(false, null);
46 | String errorMessage = context.getString(R.string.error_message_common);
47 |
48 | if (throwable instanceof HttpException) {
49 | HttpException httpException = (HttpException) throwable;
50 |
51 | if (httpException.code() >= BaseObserver.SERVER_ERROR)
52 | errorMessage = context.getString(R.string.error_message_technical);
53 | } else if (throwable instanceof IOException) {
54 | errorMessage = context.getString(R.string.error_message_connection);
55 | }
56 |
57 | actionListener.showSnackbar(errorMessage);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mlsdev/recipefinder/view/viewmodel/ViewModelFactory.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder.view.viewmodel;
2 |
3 | import android.arch.lifecycle.ViewModel;
4 | import android.arch.lifecycle.ViewModelProvider;
5 |
6 | import java.util.Map;
7 |
8 | import javax.inject.Inject;
9 | import javax.inject.Provider;
10 | import javax.inject.Singleton;
11 |
12 | @Singleton
13 | public class ViewModelFactory implements ViewModelProvider.Factory {
14 | private Map, Provider> creators;
15 |
16 | @Inject
17 | public ViewModelFactory(Map, Provider> creators) {
18 | this.creators = creators;
19 | }
20 |
21 | @Override
22 | public T create(Class modelClass) {
23 | Provider extends ViewModel> creator = creators.get(modelClass);
24 |
25 | if (creator == null) {
26 | for (Map.Entry, Provider> entry : creators.entrySet()) {
27 | if (modelClass.isAssignableFrom(entry.getKey())) {
28 | creator = entry.getValue();
29 | break;
30 | }
31 | }
32 | }
33 |
34 | if (creator == null)
35 | throw new IllegalArgumentException("unknown model class " + modelClass);
36 |
37 | try {
38 | return (T) creator.get();
39 | } catch (Exception e) {
40 | throw new RuntimeException();
41 | }
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/fade_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/fade_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/color/tab_item_text_color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/recipe_list_item_foreground.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/tab_item_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/toolbar_item_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | -
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/btn_cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/drawable-xxhdpi/btn_cancel.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_favorite_checked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/drawable-xxhdpi/ic_favorite_checked.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_favorite_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/drawable-xxhdpi/ic_favorite_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_navigation_analyse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/drawable-xxhdpi/ic_navigation_analyse.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_navigation_favorites.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/drawable-xxhdpi/ic_navigation_favorites.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_navigation_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/drawable-xxhdpi/ic_navigation_search.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_nothing_found.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/drawable-xxhdpi/ic_nothing_found.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/drawable-xxxhdpi/ic_close.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_empty_view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/drawable-xxxhdpi/ic_empty_view.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/drawable-xxxhdpi/ic_filter.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/drawable-xxxhdpi/ic_search.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/primary_color_shape.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/primary_dark_color_shape.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/progress_bar_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/progress_drawable.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
9 |
10 |
11 | -
12 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/recipe_item_title_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/recipe_list_item_foreground.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tab_item_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/toolbar_item_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/top_shadow.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
21 |
22 |
27 |
28 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_recipe_analysis_details.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
16 |
17 |
22 |
23 |
31 |
32 |
33 |
34 |
38 |
39 |
45 |
46 |
51 |
52 |
59 |
60 |
64 |
65 |
70 |
71 |
75 |
76 |
77 |
78 |
79 |
85 |
86 |
93 |
94 |
99 |
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/add_ingredient_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_fragment_add_ingredient.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
13 |
14 |
19 |
20 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_fragment_search_filter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
14 |
15 |
21 |
22 |
28 |
29 |
36 |
37 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_analyse_nutrition.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
14 |
15 |
19 |
20 |
30 |
31 |
32 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_favorite_recipes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
15 |
16 |
20 |
21 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_recipe_analysis.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
15 |
16 |
20 |
21 |
27 |
28 |
29 |
34 |
35 |
41 |
42 |
43 |
48 |
49 |
55 |
56 |
57 |
66 |
67 |
72 |
73 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_search_recipes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
19 |
20 |
24 |
25 |
32 |
33 |
34 |
35 |
40 |
41 |
46 |
47 |
51 |
52 |
53 |
54 |
55 |
62 |
63 |
70 |
71 |
76 |
77 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/ingredient_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
17 |
18 |
25 |
26 |
38 |
39 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/progress_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recipe_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
20 |
21 |
27 |
28 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/options_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/transition/change_image_transform.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #C5CAE9
5 | #303F9F
6 | #FF4081
7 | #55ffffff
8 | #BDBDBD
9 | #46ffffff
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 56dp
6 | 56dp
7 | 6dp
8 | 8dp
9 | 8dp
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RecipeFinder
3 | 75347af5
4 | c12154e41f974c51a56fad5a256c27f2
5 | d07b5508
6 | b45686d25ac88da90a36f286122ee3de
7 |
8 |
9 | Analyze
10 | Search
11 | Favorites
12 |
13 | Recipe analysing details
14 |
15 | Nutrition
16 | Recipe
17 |
18 | Search…
19 | Ingredient for analysis
20 | Health labels
21 | Diet labels
22 | Ingredients
23 | Find your recipe!
24 | Nothing. Try again.
25 |
26 | apply
27 | Filter Nutrition
28 | Diet label
29 | Health label
30 | You have no favorites yet
31 | Analyze
32 | add
33 | add ingredient
34 | No Ingredients
35 | Add at least one ingredient
36 |
37 | Calories: %1$d
38 | Total weight: %1$s
39 | Yields: %1$s
40 |
41 | sharedImage%1$s
42 | %1$s; Weight: %2$s
43 | %1$d)
44 | Balance
45 | protein
46 | carbs
47 | fat
48 | Technical error
49 | Server error. Try again later.
50 | Something went wrong.
51 | Seems to be a problem with your internet connection.
52 | Error
53 | Fill in the ingredient field
54 | content
55 | Fill in
56 |
57 |
58 | - Balanced
59 | - High-Fiber
60 | - High-Protein
61 | - Low-Carb
62 | - Low-Fat
63 | - Low-Sodium
64 |
65 |
66 |
67 | - Alcohol-free
68 | - Vegan
69 | - Vegetarian
70 | - paleo
71 | - Peanut-free
72 | - Tree-nut-free
73 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
17 |
18 |
23 |
24 |
29 |
30 |
37 |
38 |
44 |
45 |
51 |
52 |
55 |
56 |
63 |
64 |
65 |
71 |
72 |
79 |
80 |
81 |
85 |
86 |
96 |
97 |
98 |
99 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/app/src/test/java/com/mlsdev/recipefinder/NutrientTest.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder;
2 |
3 | import com.mlsdev.recipefinder.data.entity.nutrition.Nutrient;
4 |
5 | import org.junit.Assert;
6 | import org.junit.Before;
7 | import org.junit.Test;
8 |
9 | public class NutrientTest {
10 | private double quantity = 100.081;
11 | private String label = "Protein";
12 | private String unit = "g";
13 | private String expectedResult;
14 | private Nutrient nutrient;
15 |
16 | @Before
17 | public void setUp() {
18 | expectedResult = label + " 100.08 " + unit;
19 | nutrient = new Nutrient(label, quantity, unit);
20 | }
21 |
22 | @Test
23 | public void testGetFormattedFullText() {
24 | String actualResult = nutrient.getFormattedFullText();
25 | Assert.assertEquals(expectedResult, actualResult);
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/test/java/com/mlsdev/recipefinder/ParamsHelperTest.java:
--------------------------------------------------------------------------------
1 | package com.mlsdev.recipefinder;
2 |
3 | import com.mlsdev.recipefinder.view.utils.ParamsHelper;
4 |
5 | import org.junit.Assert;
6 | import org.junit.Test;
7 |
8 | public class ParamsHelperTest {
9 | private final String expectedFormatLabelResult = "alcohol-free";
10 | private final String testableFormatLabelValue = "Alcohol Free";
11 |
12 | @Test
13 | public void testFilterLabelFormatting() {
14 | String actualResult = ParamsHelper.formatLabel(testableFormatLabelValue);
15 | Assert.assertEquals(expectedFormatLabelResult, actualResult);
16 | }
17 |
18 | @Test(expected = IllegalArgumentException.class)
19 | public void testFilterLabelFormatting_WithNullAsArgument() {
20 | ParamsHelper.formatLabel(null);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | mavenCentral()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:2.3.3'
10 | classpath 'com.stanfy.spoon:spoon-gradle-plugin:1.2.2'
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | jcenter()
20 | maven { url "https://jitpack.io" }
21 | maven { url 'https://maven.google.com' }
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MLSDev/RecipeFinderJavaVersion/7e87c0c029186c66fb6f23259f9a06b63a4c21ca/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Mar 03 09:28:50 EET 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-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------