├── .gitignore ├── LICENSE ├── README.md ├── app ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── cat │ │ └── ppicas │ │ └── cleanarch │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── cat │ │ └── ppicas │ │ ├── cleanarch │ │ ├── app │ │ │ ├── App.java │ │ │ ├── DefaultServiceContainer.java │ │ │ ├── ServiceContainer.java │ │ │ ├── ServiceContainerProvider.java │ │ │ └── ServiceContainers.java │ │ ├── text │ │ │ └── NumberFormat.java │ │ ├── ui │ │ │ ├── activity │ │ │ │ ├── ActivityNavigator.java │ │ │ │ ├── ActivityNavigatorImpl.java │ │ │ │ ├── CityDetailsActivity.java │ │ │ │ └── SearchCitiesActivity.java │ │ │ ├── adapter │ │ │ │ ├── AdapterViewUnBinder.java │ │ │ │ └── CityAdapter.java │ │ │ ├── fragment │ │ │ │ ├── CityCurrentWeatherFragment.java │ │ │ │ ├── CityDailyForecastFragment.java │ │ │ │ ├── CityDetailFragment.java │ │ │ │ ├── PresenterHolderFragment.java │ │ │ │ └── SearchCitiesFragment.java │ │ │ ├── presenter │ │ │ │ ├── CityCurrentWeatherPresenter.java │ │ │ │ ├── CityDailyForecastPresenter.java │ │ │ │ ├── CityDetailPresenter.java │ │ │ │ ├── CityListItemPresenter.java │ │ │ │ └── SearchCitiesPresenter.java │ │ │ ├── view │ │ │ │ └── CityListItemView.java │ │ │ └── vista │ │ │ │ ├── CityCurrentWeatherVista.java │ │ │ │ ├── CityDailyForecastVista.java │ │ │ │ ├── CityDetailVista.java │ │ │ │ ├── CityListItemVista.java │ │ │ │ ├── SearchCitiesVista.java │ │ │ │ └── TaskResultVista.java │ │ └── util │ │ │ ├── AsyncTaskExecutor.java │ │ │ └── DisplayErrorTaskCallback.java │ │ └── framework │ │ └── ui │ │ ├── Presenter.java │ │ ├── PresenterFactory.java │ │ ├── PresenterHolder.java │ │ └── Vista.java │ └── res │ ├── layout │ ├── fragment_city_current_weather.xml │ ├── fragment_city_daily_forecast.xml │ ├── fragment_city_detail.xml │ ├── fragment_search_cities.xml │ ├── include_loading_layer.xml │ └── view_city_list_item.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 │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── core ├── build.gradle └── src │ └── main │ └── java │ └── cat │ └── ppicas │ ├── cleanarch │ ├── model │ │ ├── City.java │ │ ├── CurrentWeather.java │ │ ├── CurrentWeatherPreview.java │ │ └── DailyForecast.java │ ├── owm │ │ ├── OWMCityRepository.java │ │ ├── OWMCurrentWeatherRepository.java │ │ ├── OWMDailyForecastRepository.java │ │ ├── OWMService.java │ │ └── model │ │ │ ├── OWMCurrentWeather.java │ │ │ ├── OWMCurrentWeatherList.java │ │ │ ├── OWMDailyForecast.java │ │ │ └── OWMDailyForecastList.java │ ├── repository │ │ ├── CityRepository.java │ │ ├── CurrentWeatherRepository.java │ │ └── DailyForecastRepository.java │ └── task │ │ ├── FindCityTask.java │ │ ├── GetCityTask.java │ │ ├── GetCurrentWeatherTask.java │ │ ├── GetDailyForecastsTask.java │ │ └── GetElevationTask.java │ └── framework │ └── task │ ├── NoException.java │ ├── SuccessTaskCallback.java │ ├── Task.java │ ├── TaskCallback.java │ ├── TaskExecutor.java │ └── TaskResult.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | /.gradle/ 2 | /.idea/ 3 | /local.properties 4 | build/ 5 | .DS_Store 6 | *.iml 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, and 11 | distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 14 | owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all other entities 17 | that control, are controlled by, or are under common control with that entity. 18 | For the purposes of this definition, "control" means (i) the power, direct or 19 | indirect, to cause the direction or management of such entity, whether by 20 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity exercising 24 | permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, including 27 | but not limited to software source code, documentation source, and configuration 28 | files. 29 | 30 | "Object" form shall mean any form resulting from mechanical transformation or 31 | translation of a Source form, including but not limited to compiled object code, 32 | generated documentation, and conversions to other media types. 33 | 34 | "Work" shall mean the work of authorship, whether in Source or Object form, made 35 | available under the License, as indicated by a copyright notice that is included 36 | in or attached to the work (an example is provided in the Appendix below). 37 | 38 | "Derivative Works" shall mean any work, whether in Source or Object form, that 39 | is based on (or derived from) the Work and for which the editorial revisions, 40 | annotations, elaborations, or other modifications represent, as a whole, an 41 | original work of authorship. For the purposes of this License, Derivative Works 42 | shall not include works that remain separable from, or merely link (or bind by 43 | name) to the interfaces of, the Work and Derivative Works thereof. 44 | 45 | "Contribution" shall mean any work of authorship, including the original version 46 | of the Work and any modifications or additions to that Work or Derivative Works 47 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 48 | by the copyright owner or by an individual or Legal Entity authorized to submit 49 | on behalf of the copyright owner. For the purposes of this definition, 50 | "submitted" means any form of electronic, verbal, or written communication sent 51 | to the Licensor or its representatives, including but not limited to 52 | communication on electronic mailing lists, source code control systems, and 53 | issue tracking systems that are managed by, or on behalf of, the Licensor for 54 | the purpose of discussing and improving the Work, but excluding communication 55 | that is conspicuously marked or otherwise designated in writing by the copyright 56 | owner as "Not a Contribution." 57 | 58 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 59 | of whom a Contribution has been received by Licensor and subsequently 60 | incorporated within the Work. 61 | 62 | 2. Grant of Copyright License. 63 | 64 | Subject to the terms and conditions of this License, each Contributor hereby 65 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 66 | irrevocable copyright license to reproduce, prepare Derivative Works of, 67 | publicly display, publicly perform, sublicense, and distribute the Work and such 68 | Derivative Works in Source or Object form. 69 | 70 | 3. Grant of Patent License. 71 | 72 | Subject to the terms and conditions of this License, each Contributor hereby 73 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 74 | irrevocable (except as stated in this section) patent license to make, have 75 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 76 | such license applies only to those patent claims licensable by such Contributor 77 | that are necessarily infringed by their Contribution(s) alone or by combination 78 | of their Contribution(s) with the Work to which such Contribution(s) was 79 | submitted. If You institute patent litigation against any entity (including a 80 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 81 | Contribution incorporated within the Work constitutes direct or contributory 82 | patent infringement, then any patent licenses granted to You under this License 83 | for that Work shall terminate as of the date such litigation is filed. 84 | 85 | 4. Redistribution. 86 | 87 | You may reproduce and distribute copies of the Work or Derivative Works thereof 88 | in any medium, with or without modifications, and in Source or Object form, 89 | provided that You meet the following conditions: 90 | 91 | You must give any other recipients of the Work or Derivative Works a copy of 92 | this License; and 93 | You must cause any modified files to carry prominent notices stating that You 94 | changed the files; and 95 | You must retain, in the Source form of any Derivative Works that You distribute, 96 | all copyright, patent, trademark, and attribution notices from the Source form 97 | of the Work, excluding those notices that do not pertain to any part of the 98 | Derivative Works; and 99 | If the Work includes a "NOTICE" text file as part of its distribution, then any 100 | Derivative Works that You distribute must include a readable copy of the 101 | attribution notices contained within such NOTICE file, excluding those notices 102 | that do not pertain to any part of the Derivative Works, in at least one of the 103 | following places: within a NOTICE text file distributed as part of the 104 | Derivative Works; within the Source form or documentation, if provided along 105 | with the Derivative Works; or, within a display generated by the Derivative 106 | Works, if and wherever such third-party notices normally appear. The contents of 107 | the NOTICE file are for informational purposes only and do not modify the 108 | License. You may add Your own attribution notices within Derivative Works that 109 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 110 | provided that such additional attribution notices cannot be construed as 111 | modifying the License. 112 | You may add Your own copyright statement to Your modifications and may provide 113 | additional or different license terms and conditions for use, reproduction, or 114 | distribution of Your modifications, or for any such Derivative Works as a whole, 115 | provided Your use, reproduction, and distribution of the Work otherwise complies 116 | with the conditions stated in this License. 117 | 118 | 5. Submission of Contributions. 119 | 120 | Unless You explicitly state otherwise, any Contribution intentionally submitted 121 | for inclusion in the Work by You to the Licensor shall be under the terms and 122 | conditions of this License, without any additional terms or conditions. 123 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 124 | any separate license agreement you may have executed with Licensor regarding 125 | such Contributions. 126 | 127 | 6. Trademarks. 128 | 129 | This License does not grant permission to use the trade names, trademarks, 130 | service marks, or product names of the Licensor, except as required for 131 | reasonable and customary use in describing the origin of the Work and 132 | reproducing the content of the NOTICE file. 133 | 134 | 7. Disclaimer of Warranty. 135 | 136 | Unless required by applicable law or agreed to in writing, Licensor provides the 137 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 138 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 139 | including, without limitation, any warranties or conditions of TITLE, 140 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 141 | solely responsible for determining the appropriateness of using or 142 | redistributing the Work and assume any risks associated with Your exercise of 143 | permissions under this License. 144 | 145 | 8. Limitation of Liability. 146 | 147 | In no event and under no legal theory, whether in tort (including negligence), 148 | contract, or otherwise, unless required by applicable law (such as deliberate 149 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 150 | liable to You for damages, including any direct, indirect, special, incidental, 151 | or consequential damages of any character arising as a result of this License or 152 | out of the use or inability to use the Work (including but not limited to 153 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 154 | any and all other commercial damages or losses), even if such Contributor has 155 | been advised of the possibility of such damages. 156 | 157 | 9. Accepting Warranty or Additional Liability. 158 | 159 | While redistributing the Work or Derivative Works thereof, You may choose to 160 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 161 | other liability obligations and/or rights consistent with this License. However, 162 | in accepting such obligations, You may act only on Your own behalf and on Your 163 | sole responsibility, not on behalf of any other Contributor, and only if You 164 | agree to indemnify, defend, and hold each Contributor harmless for any liability 165 | incurred by, or claims asserted against, such Contributor by reason of your 166 | accepting any such warranty or additional liability. 167 | 168 | END OF TERMS AND CONDITIONS 169 | 170 | APPENDIX: How to apply the Apache License to your work 171 | 172 | To apply the Apache License to your work, attach the following boilerplate 173 | notice, with the fields enclosed by brackets "{}" replaced with your own 174 | identifying information. (Don't include the brackets!) The text should be 175 | enclosed in the appropriate comment syntax for the file format. We also 176 | recommend that a file or class name and description of purpose be included on 177 | the same "printed page" as the copyright notice for easier identification within 178 | third-party archives. 179 | 180 | Copyright {yyyy} {name of copyright owner} 181 | 182 | Licensed under the Apache License, Version 2.0 (the "License"); 183 | you may not use this file except in compliance with the License. 184 | You may obtain a copy of the License at 185 | 186 | http://www.apache.org/licenses/LICENSE-2.0 187 | 188 | Unless required by applicable law or agreed to in writing, software 189 | distributed under the License is distributed on an "AS IS" BASIS, 190 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 191 | See the License for the specific language governing permissions and 192 | limitations under the License. 193 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android Clean Architecture and MVP 2 | 3 | This sample project shows how to implement [Clean Architecture](http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html) (Or any other similar architecture) to an Android project. In short with a clean architecture your code is split across various layers, with the objective to separate the business logic code from the code of the UI, database, etc. 4 | 5 | The core of the app (Entities and use cases layers of clean architecture) are implemented with a pure java project. This is good because it forces your core code to not have any dependency with Android system. And if your core code is not dependant from Android SDK, it will be following the dependency rule. In addition that will be easier to unit test your code since to run the test will not require any Android instrumentation framework. 6 | 7 | The UI is implemented using [MVP](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter) (Model View Presenter). The *Presenter* is implemented using a normal Java class that doesn't extend any Android framework class (*Activity*, *Fragment*, *View*, etc). The only special thing that have these *Presenter* classes, are that they implement an interface called [Presenter](app/src/main/java/cat/ppicas/cleanarch/ui/presenter/Presenter.java). The *View* are simply a typical Android UI class (*Activity*, *Fragment* or *View*) that implements an interface called [Vista](app/src/main/java/cat/ppicas/cleanarch/ui/vista/Vista.java). Here we chose *Vista* instead of *View* to avoid name clashing with Android view classes (Thanks @gergokajtar for the tip! ;). 8 | 9 | The best part comes on how this implementation supports configuration changes. This project introduces the [PresenterHolder](app/src/main/java/cat/ppicas/cleanarch/ui/presenter/PresenterHolder.java), that it will be in charge of manage all the *Presenter* instances used inside an Activity context. The trick is to implement this *PresenterHolder* with a [Fragment](app/src/main/java/cat/ppicas/cleanarch/ui/fragment/PresenterHolderFragment.java) that have the retain instance flag set to true ([setRetainInstance](http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance%28boolean%29)). With this flag set to *true*, the *PresenterHolder Fragment* will survive to any configuration change, and by extension all the presenters that are managed by this holder. 10 | 11 | ## Features of this sample 12 | 13 | * Allows the user to search for the current weather of any city of the world. 14 | * Shows the weather forecast of a city for the next 3 days. 15 | * Uses [OpenWeatherMap](http://openweathermap.org/) APIs to query the data. 16 | * Implements [Clean Architecture](http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html). 17 | * Separated pure Java project for core business logic. 18 | * [MVP](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter) implementation that is configuration changes friendly (Supports orientation changes). 19 | * Use of [Repository](http://martinfowler.com/eaaCatalog/repository.html) pattern to access server APIs. 20 | 21 | ## More about Clean Architecture 22 | 23 | TODO... 24 | 25 | ## More about PresenterHolder 26 | 27 | TODO... 28 | 29 | ## More about Repository pattern 30 | 31 | TODO... 32 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | apply plugin: 'com.android.application' 18 | 19 | android { 20 | compileSdkVersion 22 21 | buildToolsVersion '21.1.2' 22 | 23 | compileOptions { 24 | sourceCompatibility JavaVersion.VERSION_1_7 25 | targetCompatibility JavaVersion.VERSION_1_7 26 | } 27 | 28 | defaultConfig { 29 | applicationId "cat.ppicas.cleanarch" 30 | minSdkVersion 16 31 | targetSdkVersion 22 32 | versionCode 1 33 | versionName "1.0" 34 | } 35 | 36 | buildTypes { 37 | release { 38 | minifyEnabled false 39 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 40 | } 41 | } 42 | } 43 | 44 | dependencies { 45 | compile fileTree(dir: 'libs', include: ['*.jar']) 46 | compile project(':core') 47 | compile 'com.android.support:support-v13:23.0.0' 48 | } 49 | -------------------------------------------------------------------------------- /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 /home/pau/Apps/android-studio/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/java/cat/ppicas/cleanarch/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch; 18 | 19 | import android.app.Application; 20 | import android.test.ApplicationTestCase; 21 | 22 | /** 23 | * Testing Fundamentals 24 | */ 25 | public class ApplicationTest extends ApplicationTestCase { 26 | public ApplicationTest() { 27 | super(Application.class); 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 21 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/app/App.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.app; 18 | 19 | import android.app.Application; 20 | 21 | public class App extends Application implements ServiceContainerProvider { 22 | 23 | private ServiceContainer mServiceContainer; 24 | 25 | @Override 26 | public void onCreate() { 27 | super.onCreate(); 28 | 29 | // Initialize the default implementation of the ServiceContainer interface 30 | mServiceContainer = new DefaultServiceContainer(this); 31 | } 32 | 33 | @Override 34 | public ServiceContainer getServiceContainer() { 35 | return mServiceContainer; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/app/DefaultServiceContainer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.app; 18 | 19 | import com.squareup.okhttp.Cache; 20 | import com.squareup.okhttp.OkHttpClient; 21 | 22 | import android.content.Context; 23 | 24 | import java.io.File; 25 | import java.io.IOException; 26 | import java.util.concurrent.TimeUnit; 27 | 28 | import cat.ppicas.cleanarch.owm.OWMCurrentWeatherRepository; 29 | import cat.ppicas.cleanarch.owm.OWMDailyForecastRepository; 30 | import cat.ppicas.cleanarch.repository.CityRepository; 31 | import cat.ppicas.cleanarch.owm.OWMCityRepository; 32 | import cat.ppicas.cleanarch.owm.OWMService; 33 | import cat.ppicas.cleanarch.repository.CurrentWeatherRepository; 34 | import cat.ppicas.cleanarch.repository.DailyForecastRepository; 35 | import cat.ppicas.cleanarch.util.AsyncTaskExecutor; 36 | import cat.ppicas.framework.task.TaskExecutor; 37 | import retrofit.RestAdapter; 38 | import retrofit.client.OkClient; 39 | 40 | /** 41 | * Implementation of {@link ServiceContainer} interface exposing a default configuration 42 | * for the app. 43 | */ 44 | class DefaultServiceContainer implements ServiceContainer { 45 | 46 | private Context mContext; 47 | 48 | private OWMService mOWMService; 49 | private RestAdapter mRestAdapter; 50 | private OkHttpClient mOkClient; 51 | private AsyncTaskExecutor mTaskExecutor; 52 | 53 | public DefaultServiceContainer(Context context) { 54 | mContext = context.getApplicationContext(); 55 | } 56 | 57 | @Override 58 | public CityRepository getCityRepository() { 59 | return new OWMCityRepository(getOWMService()); 60 | } 61 | 62 | @Override 63 | public CurrentWeatherRepository getCurrentWeatherRepository() { 64 | return new OWMCurrentWeatherRepository(getOWMService()); 65 | } 66 | 67 | @Override 68 | public DailyForecastRepository getDailyForecastRepository() { 69 | return new OWMDailyForecastRepository(getOWMService()); 70 | } 71 | 72 | @Override 73 | public TaskExecutor getTaskExecutor() { 74 | if (mTaskExecutor == null) { 75 | mTaskExecutor = new AsyncTaskExecutor(); 76 | } 77 | return mTaskExecutor; 78 | } 79 | 80 | private OWMService getOWMService() { 81 | if (mOWMService == null) { 82 | mOWMService = getRestAdapter().create(OWMService.class); 83 | } 84 | return mOWMService; 85 | } 86 | 87 | private RestAdapter getRestAdapter() { 88 | if (mRestAdapter == null) { 89 | mRestAdapter = new RestAdapter.Builder() 90 | .setEndpoint("http://api.openweathermap.org") 91 | .setClient(new OkClient(getOkHttpClient())) 92 | .setLogLevel(RestAdapter.LogLevel.NONE) 93 | .build(); 94 | } 95 | 96 | return mRestAdapter; 97 | } 98 | 99 | private OkHttpClient getOkHttpClient() { 100 | if (mOkClient == null) { 101 | mOkClient = new OkHttpClient(); 102 | mOkClient.setConnectTimeout(10, TimeUnit.SECONDS); 103 | mOkClient.setReadTimeout(5, TimeUnit.SECONDS); 104 | mOkClient.setWriteTimeout(5, TimeUnit.SECONDS); 105 | mOkClient.setCache(createOkHttpCache()); 106 | } 107 | 108 | return mOkClient; 109 | } 110 | 111 | private Cache createOkHttpCache() { 112 | try { 113 | File directory = new File(mContext.getCacheDir(), "ok-http"); 114 | return new Cache(directory, 3000000); 115 | } catch (IOException e) { 116 | return null; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/app/ServiceContainer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.app; 18 | 19 | import cat.ppicas.cleanarch.repository.CityRepository; 20 | import cat.ppicas.cleanarch.repository.CurrentWeatherRepository; 21 | import cat.ppicas.cleanarch.repository.DailyForecastRepository; 22 | import cat.ppicas.framework.task.TaskExecutor; 23 | 24 | /** 25 | * Interface to be used as a repository of dependency or services required across the app. 26 | * The services provided by this container can be used to fulfill the dependencies from 27 | * other classes implementing the inversion of control principle. 28 | */ 29 | public interface ServiceContainer { 30 | 31 | CityRepository getCityRepository(); 32 | 33 | CurrentWeatherRepository getCurrentWeatherRepository(); 34 | 35 | DailyForecastRepository getDailyForecastRepository(); 36 | 37 | TaskExecutor getTaskExecutor(); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/app/ServiceContainerProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.app; 18 | 19 | public interface ServiceContainerProvider { 20 | 21 | ServiceContainer getServiceContainer(); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/app/ServiceContainers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.app; 18 | 19 | import android.content.Context; 20 | 21 | public final class ServiceContainers { 22 | 23 | private ServiceContainers() { 24 | throw new RuntimeException("Instances are not allowed for this class"); 25 | } 26 | 27 | public static ServiceContainer getFromApp(Context context) { 28 | Context app = context.getApplicationContext(); 29 | ServiceContainerProvider provider = (ServiceContainerProvider) app; 30 | return provider.getServiceContainer(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/text/NumberFormat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.text; 18 | 19 | public final class NumberFormat { 20 | 21 | private static final java.text.NumberFormat DECIMAL_FORMATTER 22 | = java.text.NumberFormat.getInstance(); 23 | 24 | static { 25 | DECIMAL_FORMATTER.setMaximumFractionDigits(2); 26 | } 27 | 28 | private NumberFormat() { 29 | throw new RuntimeException("Instances are not allowed for this class"); 30 | } 31 | 32 | public static String formatDecimal(double num) { 33 | return DECIMAL_FORMATTER.format(num); 34 | } 35 | 36 | public static String formatTemperature(double temp) { 37 | return DECIMAL_FORMATTER.format(temp) + "º"; 38 | } 39 | 40 | public static String formatHumidity(double humidity) { 41 | return Math.round(humidity) + "%"; 42 | } 43 | 44 | public static String formatWindSpeed(double windSpeed) { 45 | return DECIMAL_FORMATTER.format(windSpeed) + " m/s"; 46 | } 47 | 48 | public static String formatElevation(int elevation) { 49 | return elevation + "m"; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/activity/ActivityNavigator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.activity; 18 | 19 | import cat.ppicas.cleanarch.model.City; 20 | 21 | /** 22 | * Interface that can be used to open (launch) different activities of the app without 23 | * relying on a concrete implementation. This interface helps to decouple the presenters 24 | * from the activities. 25 | */ 26 | public interface ActivityNavigator { 27 | 28 | /** 29 | * Opens the details activity for the specified {@link City}. 30 | * 31 | * @param cityId an ID of the desired {@code City} to open 32 | */ 33 | void openCityDetails(String cityId); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/activity/ActivityNavigatorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.activity; 18 | 19 | import android.app.Activity; 20 | 21 | public class ActivityNavigatorImpl implements ActivityNavigator { 22 | 23 | private Activity mActivity; 24 | 25 | public ActivityNavigatorImpl(Activity activity) { 26 | mActivity = activity; 27 | } 28 | 29 | @Override 30 | public void openCityDetails(String cityId) { 31 | mActivity.startActivity(new CityDetailsActivity.Intent(mActivity, cityId)); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/activity/CityDetailsActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.activity; 18 | 19 | import android.app.Activity; 20 | import android.app.Fragment; 21 | import android.content.Context; 22 | import android.os.Bundle; 23 | import android.view.Window; 24 | 25 | import cat.ppicas.cleanarch.ui.fragment.CityDetailFragment; 26 | import cat.ppicas.cleanarch.ui.fragment.PresenterHolderFragment; 27 | import cat.ppicas.framework.ui.Presenter; 28 | import cat.ppicas.framework.ui.PresenterFactory; 29 | import cat.ppicas.framework.ui.PresenterHolder; 30 | 31 | public class CityDetailsActivity extends Activity implements PresenterHolder { 32 | 33 | private PresenterHolder mPresenterHolder; 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | 39 | requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); 40 | 41 | if (savedInstanceState == null) { 42 | Intent intent = new Intent(getIntent()); 43 | getFragmentManager().beginTransaction() 44 | .add(new PresenterHolderFragment(), null) 45 | .add(android.R.id.content, CityDetailFragment.newInstance(intent.getCityId())) 46 | .commit(); 47 | } 48 | } 49 | 50 | @Override 51 | public void onAttachFragment(Fragment fragment) { 52 | super.onAttachFragment(fragment); 53 | if (fragment instanceof PresenterHolder) { 54 | mPresenterHolder = (PresenterHolder) fragment; 55 | } 56 | } 57 | 58 | @Override 59 | public > T getOrCreatePresenter(PresenterFactory presenterFactory) { 60 | return mPresenterHolder.getOrCreatePresenter(presenterFactory); 61 | } 62 | 63 | @Override 64 | public void destroyPresenter(PresenterFactory presenterFactory) { 65 | mPresenterHolder.destroyPresenter(presenterFactory); 66 | } 67 | 68 | public static class Intent extends android.content.Intent { 69 | 70 | private static final String EXTRA_CITY_ID = "cityId"; 71 | 72 | public Intent(Context packageContext, String cityId) { 73 | super(packageContext, CityDetailsActivity.class); 74 | putExtra(EXTRA_CITY_ID, cityId); 75 | } 76 | 77 | public Intent(android.content.Intent intent) { 78 | super(intent); 79 | } 80 | 81 | public String getCityId() { 82 | return getStringExtra(EXTRA_CITY_ID); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/activity/SearchCitiesActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.activity; 18 | 19 | import android.app.Activity; 20 | import android.app.Fragment; 21 | import android.os.Bundle; 22 | 23 | import cat.ppicas.cleanarch.ui.fragment.PresenterHolderFragment; 24 | import cat.ppicas.cleanarch.ui.fragment.SearchCitiesFragment; 25 | import cat.ppicas.framework.ui.Presenter; 26 | import cat.ppicas.framework.ui.PresenterFactory; 27 | import cat.ppicas.framework.ui.PresenterHolder; 28 | 29 | public class SearchCitiesActivity extends Activity implements PresenterHolder { 30 | 31 | private PresenterHolder mPresenterHolder; 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | 37 | if (savedInstanceState == null) { 38 | getFragmentManager().beginTransaction() 39 | .add(new PresenterHolderFragment(), null) 40 | .add(android.R.id.content, new SearchCitiesFragment()) 41 | .commit(); 42 | } 43 | } 44 | 45 | @Override 46 | public void onAttachFragment(Fragment fragment) { 47 | super.onAttachFragment(fragment); 48 | if (fragment instanceof PresenterHolder) { 49 | mPresenterHolder = (PresenterHolder) fragment; 50 | } 51 | } 52 | 53 | @Override 54 | public > T getOrCreatePresenter(PresenterFactory presenterFactory) { 55 | return mPresenterHolder.getOrCreatePresenter(presenterFactory); 56 | } 57 | 58 | @Override 59 | public void destroyPresenter(PresenterFactory presenterFactory) { 60 | mPresenterHolder.destroyPresenter(presenterFactory); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/adapter/AdapterViewUnBinder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.adapter; 18 | 19 | import android.view.View; 20 | 21 | import cat.ppicas.framework.ui.Presenter; 22 | 23 | public class AdapterViewUnBinder implements View.OnAttachStateChangeListener { 24 | 25 | private Presenter mPresenter; 26 | 27 | public AdapterViewUnBinder(Presenter presenter) { 28 | mPresenter = presenter; 29 | } 30 | 31 | @Override 32 | public void onViewAttachedToWindow(View v) { 33 | } 34 | 35 | @Override 36 | public void onViewDetachedFromWindow(View v) { 37 | mPresenter.stop(); 38 | mPresenter.onDestroy(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/adapter/CityAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.adapter; 18 | 19 | import android.content.Context; 20 | import android.view.LayoutInflater; 21 | import android.view.View; 22 | import android.view.ViewGroup; 23 | import android.widget.ArrayAdapter; 24 | 25 | import cat.ppicas.cleanarch.R; 26 | import cat.ppicas.cleanarch.app.ServiceContainers; 27 | import cat.ppicas.cleanarch.model.City; 28 | import cat.ppicas.cleanarch.ui.vista.CityListItemVista; 29 | import cat.ppicas.cleanarch.ui.presenter.CityListItemPresenter; 30 | import cat.ppicas.framework.task.TaskExecutor; 31 | 32 | public class CityAdapter extends ArrayAdapter { 33 | 34 | private final LayoutInflater mInflater; 35 | private final TaskExecutor mTaskExecutor; 36 | 37 | public CityAdapter(Context context) { 38 | super(context, android.R.layout.simple_list_item_1); 39 | mInflater = LayoutInflater.from(context); 40 | 41 | mTaskExecutor = ServiceContainers.getFromApp(context).getTaskExecutor(); 42 | } 43 | 44 | @Override 45 | public View getView(int position, View view, ViewGroup parent) { 46 | if (view == null) { 47 | view = mInflater.inflate(R.layout.view_city_list_item, parent, false); 48 | } 49 | CityListItemVista vista = (CityListItemVista) view; 50 | 51 | City city = getItem(position); 52 | 53 | // Initialize or reconfigures a Presenter for CityListItemView 54 | CityListItemPresenter presenter = (CityListItemPresenter) view.getTag(); 55 | if (presenter == null) { 56 | presenter = new CityListItemPresenter(mTaskExecutor, city); 57 | presenter.start(vista); 58 | view.setTag(presenter); 59 | view.addOnAttachStateChangeListener(new AdapterViewUnBinder(presenter)); 60 | } else { 61 | presenter.setCity(city); 62 | } 63 | 64 | return view; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/fragment/CityCurrentWeatherFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.fragment; 18 | 19 | import android.app.Fragment; 20 | import android.os.Bundle; 21 | import android.support.annotation.Nullable; 22 | import android.view.LayoutInflater; 23 | import android.view.View; 24 | import android.view.ViewGroup; 25 | import android.widget.TextView; 26 | import android.widget.Toast; 27 | 28 | import cat.ppicas.cleanarch.R; 29 | import cat.ppicas.cleanarch.app.ServiceContainer; 30 | import cat.ppicas.cleanarch.app.ServiceContainers; 31 | import cat.ppicas.cleanarch.ui.presenter.CityCurrentWeatherPresenter; 32 | import cat.ppicas.framework.ui.PresenterFactory; 33 | import cat.ppicas.framework.ui.PresenterHolder; 34 | import cat.ppicas.cleanarch.ui.vista.CityCurrentWeatherVista; 35 | 36 | public class CityCurrentWeatherFragment extends Fragment implements CityCurrentWeatherVista, 37 | PresenterFactory { 38 | 39 | private static final String ARG_CITY_ID = "cityId"; 40 | 41 | private String mCityId; 42 | private CityCurrentWeatherPresenter mPresenter; 43 | 44 | private TextView mCurrent; 45 | private TextView mHumidity; 46 | private TextView mWindSpeed; 47 | private View mLoading; 48 | 49 | public static CityCurrentWeatherFragment newInstance(String cityId) { 50 | Bundle args = new Bundle(); 51 | args.putString(ARG_CITY_ID, cityId); 52 | CityCurrentWeatherFragment fragment = new CityCurrentWeatherFragment(); 53 | fragment.setArguments(args); 54 | return fragment; 55 | } 56 | 57 | @Override 58 | public void onCreate(Bundle savedInstanceState) { 59 | super.onCreate(savedInstanceState); 60 | 61 | Bundle args = getArguments(); 62 | if (args == null || !args.containsKey(ARG_CITY_ID)) { 63 | throw new IllegalArgumentException("Invalid Fragment arguments"); 64 | } 65 | 66 | mCityId = args.getString(ARG_CITY_ID); 67 | 68 | mPresenter = ((PresenterHolder) getActivity()).getOrCreatePresenter(this); 69 | } 70 | 71 | @Nullable 72 | @Override 73 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { 74 | View view = inflater.inflate(R.layout.fragment_city_current_weather, container, false); 75 | 76 | mCurrent = (TextView) view.findViewById(R.id.city_weather__current); 77 | mHumidity = (TextView) view.findViewById(R.id.city_weather__humidity); 78 | mWindSpeed = (TextView) view.findViewById(R.id.city_weather__wind_speed); 79 | mLoading = view.findViewById(R.id.city_weather__loading); 80 | 81 | return view; 82 | } 83 | 84 | @Override 85 | public void onStart() { 86 | super.onStart(); 87 | mPresenter.start(this); 88 | } 89 | 90 | @Override 91 | public void onStop() { 92 | super.onStop(); 93 | mPresenter.stop(); 94 | } 95 | 96 | @Override 97 | public void setCurrentTemp(String temp) { 98 | mCurrent.setText(temp); 99 | } 100 | 101 | @Override 102 | public void setHumidity(String humidity) { 103 | mHumidity.setText(humidity); 104 | } 105 | 106 | @Override 107 | public void setWindSpeed(String windSpeed) { 108 | mWindSpeed.setText(windSpeed); 109 | } 110 | 111 | @Override 112 | public void displayLoading(boolean display) { 113 | mLoading.setVisibility(display ? View.VISIBLE : View.GONE); 114 | } 115 | 116 | @Override 117 | public void displayError(int stringResId, Object... args) { 118 | Toast.makeText(getActivity().getApplicationContext(), stringResId, Toast.LENGTH_LONG).show(); 119 | } 120 | 121 | @Override 122 | public CityCurrentWeatherPresenter createPresenter() { 123 | ServiceContainer sc = ServiceContainers.getFromApp(getActivity()); 124 | return new CityCurrentWeatherPresenter(sc.getTaskExecutor(), 125 | sc.getCurrentWeatherRepository(), mCityId); 126 | } 127 | 128 | @Override 129 | public String getPresenterTag() { 130 | return CityCurrentWeatherFragment.class.getName(); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/fragment/CityDailyForecastFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.fragment; 18 | 19 | import android.app.Fragment; 20 | import android.os.Bundle; 21 | import android.support.annotation.Nullable; 22 | import android.view.LayoutInflater; 23 | import android.view.View; 24 | import android.view.ViewGroup; 25 | import android.widget.TextView; 26 | import android.widget.Toast; 27 | 28 | import cat.ppicas.cleanarch.R; 29 | import cat.ppicas.cleanarch.app.ServiceContainer; 30 | import cat.ppicas.cleanarch.app.ServiceContainers; 31 | import cat.ppicas.cleanarch.ui.presenter.CityDailyForecastPresenter; 32 | import cat.ppicas.framework.ui.PresenterFactory; 33 | import cat.ppicas.framework.ui.PresenterHolder; 34 | import cat.ppicas.cleanarch.ui.vista.CityDailyForecastVista; 35 | 36 | public class CityDailyForecastFragment extends Fragment implements CityDailyForecastVista, 37 | PresenterFactory { 38 | 39 | private static final String ARG_CITY_ID = "cityId"; 40 | private static final String ARG_DAYS_FROM_TODAY = "daysFromToday"; 41 | 42 | private String mCityId; 43 | private int mDaysFromToday; 44 | private CityDailyForecastPresenter mPresenter; 45 | 46 | private TextView mDescription; 47 | private TextView mDayTemp; 48 | private TextView mMinTemp; 49 | private TextView mMaxTemp; 50 | private TextView mHumidity; 51 | private TextView mWindSpeed; 52 | private View mLoading; 53 | 54 | public static CityDailyForecastFragment newInstance(String cityId, int daysFromToday) { 55 | Bundle args = new Bundle(); 56 | args.putString(ARG_CITY_ID, cityId); 57 | args.putInt(ARG_DAYS_FROM_TODAY, daysFromToday); 58 | CityDailyForecastFragment fragment = new CityDailyForecastFragment(); 59 | fragment.setArguments(args); 60 | return fragment; 61 | } 62 | 63 | @Override 64 | public void onCreate(Bundle savedInstanceState) { 65 | super.onCreate(savedInstanceState); 66 | 67 | Bundle args = getArguments(); 68 | mCityId = args.getString(ARG_CITY_ID); 69 | mDaysFromToday = args.getInt(ARG_DAYS_FROM_TODAY); 70 | 71 | mPresenter = ((PresenterHolder) getActivity()).getOrCreatePresenter(this); 72 | } 73 | 74 | @Nullable 75 | @Override 76 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { 77 | View view = inflater.inflate(R.layout.fragment_city_daily_forecast, container, false); 78 | 79 | mDescription = (TextView) view.findViewById(R.id.daily_forecast__description); 80 | mDayTemp = (TextView) view.findViewById(R.id.daily_forecast__day_temp); 81 | mMinTemp = (TextView) view.findViewById(R.id.daily_forecast__min_temp); 82 | mMaxTemp = (TextView) view.findViewById(R.id.daily_forecast__max_temp); 83 | mHumidity = (TextView) view.findViewById(R.id.daily_forecast__humidity); 84 | mWindSpeed = (TextView) view.findViewById(R.id.daily_forecast__wind_speed); 85 | mLoading = view.findViewById(R.id.daily_forecast__loading); 86 | 87 | return view; 88 | } 89 | 90 | @Override 91 | public void onStart() { 92 | super.onStart(); 93 | mPresenter.start(this); 94 | } 95 | 96 | @Override 97 | public void onStop() { 98 | super.onStop(); 99 | mPresenter.stop(); 100 | } 101 | 102 | @Override 103 | public void setForecastDescription(String description) { 104 | mDescription.setText(description); 105 | } 106 | 107 | @Override 108 | public void setDayTemp(String temp) { 109 | mDayTemp.setText(temp); 110 | } 111 | 112 | @Override 113 | public void setMinTemp(String temp) { 114 | mMinTemp.setText(temp); 115 | } 116 | 117 | @Override 118 | public void setMaxTemp(String temp) { 119 | mMaxTemp.setText(temp); 120 | } 121 | 122 | @Override 123 | public void setHumidity(String humidity) { 124 | mHumidity.setText(humidity); 125 | } 126 | 127 | @Override 128 | public void setWindSpeed(String windSpeed) { 129 | mWindSpeed.setText(windSpeed); 130 | } 131 | 132 | @Override 133 | public void displayLoading(boolean display) { 134 | mLoading.setVisibility(display ? View.VISIBLE : View.GONE); 135 | } 136 | 137 | @Override 138 | public void displayError(int stringResId, Object... args) { 139 | Toast.makeText(getActivity().getApplicationContext(), stringResId, Toast.LENGTH_LONG).show(); 140 | } 141 | 142 | @Override 143 | public CityDailyForecastPresenter createPresenter() { 144 | ServiceContainer sc = ServiceContainers.getFromApp(getActivity()); 145 | return new CityDailyForecastPresenter(sc.getTaskExecutor(), sc.getDailyForecastRepository(), 146 | mCityId, mDaysFromToday); 147 | } 148 | 149 | @Override 150 | public String getPresenterTag() { 151 | return CityDailyForecastFragment.class.getName() + "." + mDaysFromToday; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/fragment/CityDetailFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.fragment; 18 | 19 | import android.app.Fragment; 20 | import android.app.FragmentManager; 21 | import android.os.Bundle; 22 | import android.support.v13.app.FragmentStatePagerAdapter; 23 | import android.support.v4.view.ViewPager; 24 | import android.view.LayoutInflater; 25 | import android.view.View; 26 | import android.view.ViewGroup; 27 | import android.widget.Toast; 28 | 29 | import cat.ppicas.cleanarch.R; 30 | import cat.ppicas.cleanarch.app.ServiceContainer; 31 | import cat.ppicas.cleanarch.app.ServiceContainers; 32 | import cat.ppicas.cleanarch.ui.presenter.CityDetailPresenter; 33 | import cat.ppicas.framework.ui.PresenterFactory; 34 | import cat.ppicas.framework.ui.PresenterHolder; 35 | import cat.ppicas.cleanarch.ui.vista.CityDetailVista; 36 | 37 | public class CityDetailFragment extends Fragment implements CityDetailVista, 38 | PresenterFactory { 39 | 40 | private static final String ARG_CITY_ID = "cityId"; 41 | 42 | private String mCityId; 43 | 44 | private CityDetailPresenter mPresenter; 45 | 46 | public static CityDetailFragment newInstance(String cityId) { 47 | Bundle args = new Bundle(); 48 | args.putString(ARG_CITY_ID, cityId); 49 | CityDetailFragment fragment = new CityDetailFragment(); 50 | fragment.setArguments(args); 51 | return fragment; 52 | } 53 | 54 | @Override 55 | public void onCreate(Bundle savedInstanceState) { 56 | super.onCreate(savedInstanceState); 57 | 58 | Bundle args = getArguments(); 59 | if (args == null || !args.containsKey(ARG_CITY_ID)) { 60 | throw new IllegalArgumentException("Invalid Fragment arguments"); 61 | } 62 | 63 | mCityId = args.getString(ARG_CITY_ID); 64 | 65 | mPresenter = ((PresenterHolder) getActivity()).getOrCreatePresenter(this); 66 | } 67 | 68 | @Override 69 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 70 | View view = inflater.inflate(R.layout.fragment_city_detail, container, false); 71 | 72 | ViewPager viewPager = (ViewPager) view.findViewById(R.id.city_detail__view_pager); 73 | viewPager.setAdapter(new LocalPageAdapter(getFragmentManager())); 74 | 75 | return view; 76 | } 77 | 78 | @Override 79 | public void onStart() { 80 | super.onStart(); 81 | mPresenter.start(this); 82 | } 83 | 84 | @Override 85 | public void onStop() { 86 | super.onStop(); 87 | mPresenter.stop(); 88 | } 89 | 90 | @Override 91 | public void setTitle(int stringResId, Object... args) { 92 | getActivity().setTitle(getString(stringResId, args)); 93 | } 94 | 95 | @Override 96 | public void displayLoading(boolean display) { 97 | getActivity().setProgressBarIndeterminate(true); 98 | getActivity().setProgressBarIndeterminateVisibility(display); 99 | } 100 | 101 | @Override 102 | public void displayError(int stringResId, Object... args) { 103 | Toast.makeText(getActivity().getApplicationContext(), stringResId, Toast.LENGTH_LONG).show(); 104 | } 105 | 106 | @Override 107 | public CityDetailPresenter createPresenter() { 108 | ServiceContainer sc = ServiceContainers.getFromApp(getActivity()); 109 | return new CityDetailPresenter(sc.getTaskExecutor(), sc.getCityRepository(), 110 | getResources(), mCityId); 111 | } 112 | 113 | @Override 114 | public String getPresenterTag() { 115 | return CityDetailFragment.class.getName(); 116 | } 117 | 118 | private class LocalPageAdapter extends FragmentStatePagerAdapter { 119 | 120 | public LocalPageAdapter(FragmentManager fm) { 121 | super(fm); 122 | } 123 | 124 | @Override 125 | public Fragment getItem(int position) { 126 | if (position == 0) { 127 | return CityCurrentWeatherFragment.newInstance(mCityId); 128 | } else { 129 | return CityDailyForecastFragment.newInstance(mCityId, position - 1); 130 | } 131 | } 132 | 133 | @Override 134 | public CharSequence getPageTitle(int position) { 135 | if (position == 0) { 136 | return getString(R.string.city_details__tab_current); 137 | } else { 138 | return mPresenter.getForecastPageTitle(position - 1); 139 | } 140 | } 141 | 142 | @Override 143 | public int getCount() { 144 | return 1 + 3; 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/fragment/PresenterHolderFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.fragment; 18 | 19 | import android.app.Fragment; 20 | import android.os.Bundle; 21 | 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | 25 | import cat.ppicas.framework.ui.Presenter; 26 | import cat.ppicas.framework.ui.PresenterFactory; 27 | import cat.ppicas.framework.ui.PresenterHolder; 28 | 29 | public class PresenterHolderFragment extends Fragment implements PresenterHolder { 30 | 31 | private static final String STATE_PRESENTERS = "presenters"; 32 | 33 | private final Map> mPresenterMap = new HashMap>(); 34 | 35 | private Bundle mPresentersStates; 36 | 37 | @Override 38 | public void onCreate(Bundle state) { 39 | super.onCreate(state); 40 | setRetainInstance(true); 41 | 42 | if (state != null) { 43 | mPresentersStates = state.getBundle(STATE_PRESENTERS); 44 | } 45 | } 46 | 47 | @Override 48 | public void onSaveInstanceState(Bundle state) { 49 | super.onSaveInstanceState(state); 50 | Bundle presentersStates = new Bundle(); 51 | for (Map.Entry> entry : mPresenterMap.entrySet()) { 52 | Bundle presenterState = new Bundle(); 53 | entry.getValue().saveState(presenterState); 54 | presentersStates.putBundle(entry.getKey(), presenterState); 55 | } 56 | state.putBundle(STATE_PRESENTERS, presentersStates); 57 | } 58 | 59 | @Override 60 | public void onDestroy() { 61 | super.onDestroy(); 62 | for (Presenter presenter : mPresenterMap.values()) { 63 | presenter.onDestroy(); 64 | } 65 | } 66 | 67 | @Override 68 | public > T getOrCreatePresenter(PresenterFactory presenterFactory) { 69 | String tag = presenterFactory.getPresenterTag(); 70 | 71 | @SuppressWarnings("unchecked") 72 | T presenter = (T) mPresenterMap.get(tag); 73 | 74 | if (presenter == null) { 75 | presenter = presenterFactory.createPresenter(); 76 | if (mPresentersStates != null && mPresentersStates.containsKey(tag)) { 77 | presenter.restoreState(mPresentersStates.getBundle(tag)); 78 | } 79 | mPresenterMap.put(tag, presenter); 80 | } 81 | 82 | return presenter; 83 | } 84 | 85 | @Override 86 | public void destroyPresenter(PresenterFactory presenterFactory) { 87 | String tag = presenterFactory.getPresenterTag(); 88 | Presenter presenter = mPresenterMap.get(tag); 89 | if (presenter != null) { 90 | presenter.onDestroy(); 91 | } 92 | mPresenterMap.remove(tag); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/fragment/SearchCitiesFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.fragment; 18 | 19 | import android.app.Fragment; 20 | import android.content.Context; 21 | import android.os.Bundle; 22 | import android.view.LayoutInflater; 23 | import android.view.View; 24 | import android.view.ViewGroup; 25 | import android.view.inputmethod.InputMethodManager; 26 | import android.widget.AdapterView; 27 | import android.widget.ListView; 28 | import android.widget.ProgressBar; 29 | import android.widget.SearchView; 30 | import android.widget.TextView; 31 | import android.widget.Toast; 32 | 33 | import java.util.List; 34 | 35 | import cat.ppicas.cleanarch.R; 36 | import cat.ppicas.cleanarch.app.ServiceContainer; 37 | import cat.ppicas.cleanarch.app.ServiceContainers; 38 | import cat.ppicas.cleanarch.model.City; 39 | import cat.ppicas.cleanarch.ui.activity.ActivityNavigator; 40 | import cat.ppicas.cleanarch.ui.activity.ActivityNavigatorImpl; 41 | import cat.ppicas.cleanarch.ui.adapter.CityAdapter; 42 | import cat.ppicas.cleanarch.ui.vista.SearchCitiesVista; 43 | import cat.ppicas.framework.ui.PresenterFactory; 44 | import cat.ppicas.framework.ui.PresenterHolder; 45 | import cat.ppicas.cleanarch.ui.presenter.SearchCitiesPresenter; 46 | 47 | public class SearchCitiesFragment extends Fragment implements SearchCitiesVista, 48 | PresenterFactory { 49 | 50 | private static final String STATE_LIST_GROUP_VISIBILITY = "listGroupVisibility"; 51 | private static final String STATE_LIST_VISIBILITY = "listVisibility"; 52 | private static final String STATE_EMPTY_VISIBILITY = "emptyVisibility"; 53 | private static final String STATE_PROGRESS_VISIBILITY = "progressVisibility"; 54 | 55 | private SearchCitiesPresenter mPresenter; 56 | 57 | private CityAdapter mAdapter; 58 | 59 | private SearchView mSearch; 60 | private View mListGroup; 61 | private ListView mList; 62 | private TextView mEmpty; 63 | private ProgressBar mProgress; 64 | 65 | @Override 66 | public void onCreate(Bundle savedInstanceState) { 67 | super.onCreate(savedInstanceState); 68 | mPresenter = ((PresenterHolder) getActivity()).getOrCreatePresenter(this); 69 | } 70 | 71 | @Override 72 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { 73 | final View view = inflater.inflate(R.layout.fragment_search_cities, container, false); 74 | 75 | bindViews(view); 76 | 77 | mSearch.setOnQueryTextListener(new SearchView.OnQueryTextListener() { 78 | @Override 79 | public boolean onQueryTextSubmit(String query) { 80 | ((InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE)) 81 | .hideSoftInputFromWindow(view.getWindowToken(), 0); 82 | mPresenter.onCitySearch(query); 83 | return false; 84 | } 85 | 86 | @Override 87 | public boolean onQueryTextChange(String newText) { 88 | return false; 89 | } 90 | }); 91 | 92 | mAdapter = new CityAdapter(getActivity()); 93 | mList.setAdapter(mAdapter); 94 | mList.setOnItemClickListener(new AdapterView.OnItemClickListener() { 95 | @Override 96 | public void onItemClick(AdapterView parent, View view, int position, long id) { 97 | City city = mAdapter.getItem(position); 98 | mPresenter.onCitySelected(city.getId()); 99 | } 100 | }); 101 | 102 | mProgress.setVisibility(View.GONE); 103 | mEmpty.setVisibility(View.GONE); 104 | 105 | if (state != null) { 106 | restoreViewsState(state); 107 | } 108 | 109 | return view; 110 | } 111 | 112 | @Override 113 | public void onStart() { 114 | super.onStart(); 115 | mPresenter.start(this); 116 | } 117 | 118 | @Override 119 | public void onStop() { 120 | super.onStop(); 121 | mPresenter.stop(); 122 | } 123 | 124 | @Override 125 | public void onSaveInstanceState(Bundle state) { 126 | super.onSaveInstanceState(state); 127 | state.putInt(STATE_LIST_GROUP_VISIBILITY, mListGroup.getVisibility()); 128 | state.putInt(STATE_LIST_VISIBILITY, mList.getVisibility()); 129 | state.putInt(STATE_EMPTY_VISIBILITY, mEmpty.getVisibility()); 130 | state.putInt(STATE_PROGRESS_VISIBILITY, mProgress.getVisibility()); 131 | } 132 | 133 | @SuppressWarnings("ResourceType") 134 | public void restoreViewsState(Bundle state) { 135 | mListGroup.setVisibility(state.getInt(STATE_LIST_GROUP_VISIBILITY)); 136 | mList.setVisibility(state.getInt(STATE_LIST_VISIBILITY)); 137 | mEmpty.setVisibility(state.getInt(STATE_EMPTY_VISIBILITY)); 138 | mProgress.setVisibility(state.getInt(STATE_PROGRESS_VISIBILITY)); 139 | } 140 | 141 | @Override 142 | public void setTitle(int stringResId, Object... args) { 143 | getActivity().setTitle(getString(stringResId, args)); 144 | } 145 | 146 | @Override 147 | public void setCities(List cities) { 148 | mList.setVisibility(View.VISIBLE); 149 | mEmpty.setVisibility(View.GONE); 150 | mAdapter.clear(); 151 | mAdapter.addAll(cities); 152 | } 153 | 154 | @Override 155 | public void displayCitiesNotFound() { 156 | mList.setVisibility(View.GONE); 157 | mEmpty.setVisibility(View.VISIBLE); 158 | } 159 | 160 | @Override 161 | public void displayLoading(boolean show) { 162 | mListGroup.setVisibility(show ? View.GONE : View.VISIBLE); 163 | mProgress.setVisibility(show ? View.VISIBLE : View.GONE); 164 | } 165 | 166 | @Override 167 | public void displayError(int stringResId, Object... args) { 168 | Toast.makeText(getActivity().getApplicationContext(), stringResId, Toast.LENGTH_LONG).show(); 169 | } 170 | 171 | @Override 172 | public SearchCitiesPresenter createPresenter() { 173 | ServiceContainer sc = ServiceContainers.getFromApp(getActivity()); 174 | ActivityNavigator activityNavigator = new ActivityNavigatorImpl(getActivity()); 175 | return new SearchCitiesPresenter(sc.getTaskExecutor(), activityNavigator, 176 | sc.getCityRepository()); 177 | } 178 | 179 | @Override 180 | public String getPresenterTag() { 181 | return SearchCitiesFragment.class.getName(); 182 | } 183 | 184 | private void bindViews(View view) { 185 | mSearch = (SearchView) view.findViewById(R.id.search_cities__search); 186 | mListGroup = view.findViewById(R.id.search_cities__list_group); 187 | mList = (ListView) view.findViewById(R.id.search_cities__list); 188 | mEmpty = (TextView) view.findViewById(R.id.search_cities__empty); 189 | mProgress = (ProgressBar) view.findViewById(R.id.search_cities__progress); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/presenter/CityCurrentWeatherPresenter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.presenter; 18 | 19 | import cat.ppicas.cleanarch.model.CurrentWeather; 20 | import cat.ppicas.cleanarch.repository.CurrentWeatherRepository; 21 | import cat.ppicas.cleanarch.task.GetCurrentWeatherTask; 22 | import cat.ppicas.cleanarch.text.NumberFormat; 23 | import cat.ppicas.cleanarch.ui.vista.CityCurrentWeatherVista; 24 | import cat.ppicas.cleanarch.util.DisplayErrorTaskCallback; 25 | import cat.ppicas.framework.task.TaskExecutor; 26 | import cat.ppicas.framework.ui.Presenter; 27 | 28 | public class CityCurrentWeatherPresenter extends Presenter { 29 | 30 | private final TaskExecutor mTaskExecutor; 31 | private final CurrentWeatherRepository mRepository; 32 | private final String mCityId; 33 | 34 | private GetCurrentWeatherTask mGetCurrentWeatherTask; 35 | private CurrentWeather mLastCurrentWeather; 36 | 37 | public CityCurrentWeatherPresenter(TaskExecutor taskExecutor, 38 | CurrentWeatherRepository repository, String cityId) { 39 | mTaskExecutor = taskExecutor; 40 | mRepository = repository; 41 | mCityId = cityId; 42 | } 43 | 44 | @Override 45 | public void onStart(CityCurrentWeatherVista vista) { 46 | if (mLastCurrentWeather != null) { 47 | updateVista(vista, mLastCurrentWeather); 48 | } else { 49 | vista.displayLoading(true); 50 | if (!mTaskExecutor.isRunning(mGetCurrentWeatherTask)) { 51 | mGetCurrentWeatherTask = new GetCurrentWeatherTask(mRepository, mCityId); 52 | mTaskExecutor.execute(mGetCurrentWeatherTask, new GetCurrentWeatherTaskCallback()); 53 | } 54 | } 55 | } 56 | 57 | private void updateVista(CityCurrentWeatherVista vista, CurrentWeather cw) { 58 | vista.setCurrentTemp(NumberFormat.formatTemperature(cw.getCurrentTemp())); 59 | vista.setHumidity(NumberFormat.formatHumidity(cw.getHumidity())); 60 | vista.setWindSpeed(NumberFormat.formatWindSpeed(cw.getWindSpeed())); 61 | } 62 | 63 | private class GetCurrentWeatherTaskCallback extends DisplayErrorTaskCallback { 64 | public GetCurrentWeatherTaskCallback() { 65 | super(CityCurrentWeatherPresenter.this); 66 | } 67 | 68 | @Override 69 | public void onSuccess(CurrentWeather cw) { 70 | mLastCurrentWeather = cw; 71 | CityCurrentWeatherVista vista = getVista(); 72 | if (vista != null) { 73 | vista.displayLoading(false); 74 | updateVista(vista, cw); 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/presenter/CityDailyForecastPresenter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.presenter; 18 | 19 | import java.util.List; 20 | 21 | import cat.ppicas.cleanarch.R; 22 | import cat.ppicas.cleanarch.model.DailyForecast; 23 | import cat.ppicas.cleanarch.repository.DailyForecastRepository; 24 | import cat.ppicas.cleanarch.task.GetDailyForecastsTask; 25 | import cat.ppicas.cleanarch.text.NumberFormat; 26 | import cat.ppicas.cleanarch.ui.vista.CityDailyForecastVista; 27 | import cat.ppicas.cleanarch.util.DisplayErrorTaskCallback; 28 | import cat.ppicas.framework.task.TaskExecutor; 29 | import cat.ppicas.framework.ui.Presenter; 30 | 31 | public class CityDailyForecastPresenter extends Presenter { 32 | 33 | private final TaskExecutor mTaskExecutor; 34 | private final DailyForecastRepository mRepository; 35 | private final String mCityId; 36 | private final int mDaysFromToday; 37 | 38 | private GetDailyForecastsTask mGetDailyForecastsTask; 39 | private DailyForecast mLastDailyForecast; 40 | 41 | public CityDailyForecastPresenter(TaskExecutor taskExecutor, DailyForecastRepository repository, 42 | String cityId, int daysFromToday) { 43 | mTaskExecutor = taskExecutor; 44 | mRepository = repository; 45 | mCityId = cityId; 46 | mDaysFromToday = daysFromToday; 47 | } 48 | 49 | @Override 50 | public void onStart(CityDailyForecastVista vista) { 51 | if (mLastDailyForecast != null) { 52 | updateVista(vista, mLastDailyForecast); 53 | } else { 54 | vista.displayLoading(true); 55 | if (!mTaskExecutor.isRunning(mGetDailyForecastsTask)) { 56 | mGetDailyForecastsTask = new GetDailyForecastsTask(mRepository, mCityId); 57 | mTaskExecutor.execute(mGetDailyForecastsTask, new GetDailyForecastTaskCallback()); 58 | } 59 | } 60 | } 61 | 62 | private void updateVista(CityDailyForecastVista vista, DailyForecast df) { 63 | vista.setForecastDescription(capitalizeFirstLetter( 64 | df.getDescription())); 65 | vista.setDayTemp(NumberFormat.formatTemperature(df.getDayTemp())); 66 | vista.setMinTemp(NumberFormat.formatTemperature(df.getMinTemp())); 67 | vista.setMaxTemp(NumberFormat.formatTemperature(df.getMaxTemp())); 68 | vista.setHumidity(NumberFormat.formatHumidity(df.getHumidity())); 69 | vista.setWindSpeed(NumberFormat.formatWindSpeed(df.getWindSpeed())); 70 | } 71 | 72 | private String capitalizeFirstLetter(String text) { 73 | return text.substring(0, 1).toUpperCase() + text.substring(1); 74 | } 75 | 76 | private class GetDailyForecastTaskCallback extends DisplayErrorTaskCallback> { 77 | public GetDailyForecastTaskCallback() { 78 | super(CityDailyForecastPresenter.this); 79 | } 80 | 81 | @Override 82 | public void onSuccess(List list) { 83 | DailyForecast dailyForecast = null; 84 | if (list.size() >= mDaysFromToday + 1) { 85 | dailyForecast = list.get(mDaysFromToday); 86 | } 87 | 88 | mLastDailyForecast = dailyForecast; 89 | 90 | CityDailyForecastVista vista = getVista(); 91 | if (vista != null) { 92 | vista.displayLoading(false); 93 | if (dailyForecast != null) { 94 | updateVista(vista, dailyForecast); 95 | } else { 96 | vista.displayError(R.string.error__connection); 97 | } 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/presenter/CityDetailPresenter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.presenter; 18 | 19 | import android.content.res.Resources; 20 | import android.text.format.DateFormat; 21 | 22 | import java.util.Calendar; 23 | 24 | import cat.ppicas.cleanarch.R; 25 | import cat.ppicas.cleanarch.model.City; 26 | import cat.ppicas.cleanarch.repository.CityRepository; 27 | import cat.ppicas.cleanarch.task.GetCityTask; 28 | import cat.ppicas.cleanarch.ui.vista.CityDetailVista; 29 | import cat.ppicas.cleanarch.util.DisplayErrorTaskCallback; 30 | import cat.ppicas.framework.task.TaskExecutor; 31 | import cat.ppicas.framework.ui.Presenter; 32 | 33 | public class CityDetailPresenter extends Presenter { 34 | 35 | private static final String DAY_OF_WEEK_DATE_FORMAT_PATTERN = "cccc"; 36 | 37 | private final TaskExecutor mTaskExecutor; 38 | private final CityRepository mCityRepository; 39 | private final Resources mResources; 40 | private final String mCityId; 41 | 42 | private GetCityTask mGetCityTask; 43 | private City mCity; 44 | 45 | public CityDetailPresenter(TaskExecutor taskExecutor, CityRepository cityRepository, 46 | Resources resources, String cityId) { 47 | mTaskExecutor = taskExecutor; 48 | mCityRepository = cityRepository; 49 | mResources = resources; 50 | mCityId = cityId; 51 | } 52 | 53 | @Override 54 | public void onStart(CityDetailVista vista) { 55 | vista.setTitle(R.string.city_details__title_loading); 56 | 57 | if (mCity != null) { 58 | vista.setTitle(R.string.city_details__title, mCity.getName()); 59 | } else { 60 | vista.displayLoading(true); 61 | if (!mTaskExecutor.isRunning(mGetCityTask)) { 62 | mGetCityTask = new GetCityTask(mCityRepository, mCityId); 63 | mTaskExecutor.execute(mGetCityTask, new GetCityTaskCallback()); 64 | } 65 | } 66 | } 67 | 68 | public String getForecastPageTitle(int daysFromToday) { 69 | if (daysFromToday == 0) { 70 | return mResources.getString(R.string.city_details__tab_forecast, 71 | mResources.getString(R.string.global__today)); 72 | } else if (daysFromToday == 1) { 73 | return mResources.getString(R.string.city_details__tab_forecast, 74 | mResources.getString(R.string.global__tomorrow)); 75 | } else { 76 | Calendar cal = Calendar.getInstance(); 77 | cal.add(Calendar.DAY_OF_MONTH, daysFromToday); 78 | return mResources.getString(R.string.city_details__tab_forecast, 79 | DateFormat.format(DAY_OF_WEEK_DATE_FORMAT_PATTERN, cal)); 80 | } 81 | } 82 | 83 | private class GetCityTaskCallback extends DisplayErrorTaskCallback { 84 | 85 | public GetCityTaskCallback() { 86 | super(CityDetailPresenter.this); 87 | } 88 | 89 | @Override 90 | public void onSuccess(City city) { 91 | mCity = city; 92 | CityDetailVista vista = getVista(); 93 | if (vista != null) { 94 | vista.displayLoading(false); 95 | vista.setTitle(R.string.city_details__title, city.getName()); 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/presenter/CityListItemPresenter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.presenter; 18 | 19 | import cat.ppicas.cleanarch.model.City; 20 | import cat.ppicas.cleanarch.task.GetElevationTask; 21 | import cat.ppicas.cleanarch.text.NumberFormat; 22 | import cat.ppicas.cleanarch.ui.vista.CityListItemVista; 23 | import cat.ppicas.framework.task.SuccessTaskCallback; 24 | import cat.ppicas.framework.task.TaskExecutor; 25 | import cat.ppicas.framework.ui.Presenter; 26 | 27 | public class CityListItemPresenter extends Presenter { 28 | 29 | private TaskExecutor mTaskExecutor; 30 | private City mCity; 31 | 32 | private int mElevation = -1; 33 | private GetElevationTask mGetElevationTask; 34 | 35 | public CityListItemPresenter(TaskExecutor taskExecutor, City city) { 36 | mTaskExecutor = taskExecutor; 37 | mCity = city; 38 | } 39 | 40 | @Override 41 | public void onStart(CityListItemVista vista) { 42 | updateVista(); 43 | 44 | if (mElevation > -1) { 45 | vista.setLoadingElevation(false); 46 | vista.setElevation(mElevation); 47 | } else { 48 | vista.setLoadingElevation(true); 49 | if (!mTaskExecutor.isRunning(mGetElevationTask)) { 50 | mGetElevationTask = new GetElevationTask(mCity); 51 | mTaskExecutor.execute(mGetElevationTask, new GetElevationTaskCallback()); 52 | } 53 | } 54 | } 55 | 56 | @Override 57 | public void onDestroy() { 58 | if (mTaskExecutor.isRunning(mGetElevationTask)) { 59 | mGetElevationTask.cancel(); 60 | } 61 | } 62 | 63 | public void setCity(City city) { 64 | if (mCity.getId().equals(city.getId()) && mCity.getName().equals(city.getName())) { 65 | return; 66 | } 67 | 68 | mCity = city; 69 | updateVista(); 70 | 71 | if (mTaskExecutor.isRunning(mGetElevationTask)) { 72 | mGetElevationTask.cancel(); 73 | } 74 | if (getVista() != null) { 75 | getVista().setLoadingElevation(true); 76 | } 77 | mElevation = -1; 78 | mGetElevationTask = new GetElevationTask(city); 79 | mTaskExecutor.execute(mGetElevationTask, new GetElevationTaskCallback()); 80 | } 81 | 82 | private void updateVista() { 83 | CityListItemVista vista = getVista(); 84 | if (vista == null) { 85 | return; 86 | } 87 | 88 | vista.setCityName(mCity.getName()); 89 | vista.setCountry(mCity.getCountry()); 90 | double temp = mCity.getCurrentWeatherPreview().getCurrentTemp(); 91 | vista.setCurrentTemp(NumberFormat.formatTemperature(temp)); 92 | } 93 | 94 | private class GetElevationTaskCallback extends SuccessTaskCallback { 95 | @Override 96 | public void onSuccess(Integer elevation) { 97 | mElevation = elevation; 98 | if (getVista() != null) { 99 | getVista().setElevation(elevation); 100 | getVista().setLoadingElevation(false); 101 | } 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/presenter/SearchCitiesPresenter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.presenter; 18 | 19 | import android.os.Bundle; 20 | import android.text.TextUtils; 21 | 22 | import java.io.IOException; 23 | import java.util.List; 24 | 25 | import cat.ppicas.cleanarch.R; 26 | import cat.ppicas.cleanarch.model.City; 27 | import cat.ppicas.cleanarch.repository.CityRepository; 28 | import cat.ppicas.cleanarch.task.FindCityTask; 29 | import cat.ppicas.cleanarch.ui.activity.ActivityNavigator; 30 | import cat.ppicas.cleanarch.ui.vista.SearchCitiesVista; 31 | import cat.ppicas.cleanarch.util.DisplayErrorTaskCallback; 32 | import cat.ppicas.framework.task.TaskExecutor; 33 | import cat.ppicas.framework.ui.Presenter; 34 | 35 | public class SearchCitiesPresenter extends Presenter { 36 | 37 | private static final String STATE_LAST_SEARCH = "lastSearch"; 38 | 39 | private TaskExecutor mTaskExecutor; 40 | private ActivityNavigator mActivityNavigator; 41 | private CityRepository mCityRepository; 42 | 43 | private FindCityTask mFindCityTask; 44 | private String mLastSearch; 45 | private List mLastResults; 46 | 47 | public SearchCitiesPresenter(TaskExecutor taskExecutor, ActivityNavigator activityNavigator, 48 | CityRepository cityRepository) { 49 | mTaskExecutor = taskExecutor; 50 | mActivityNavigator = activityNavigator; 51 | mCityRepository = cityRepository; 52 | } 53 | 54 | @Override 55 | public void onStart(SearchCitiesVista vista) { 56 | vista.setTitle(R.string.search_cities__title); 57 | 58 | if (mTaskExecutor.isRunning(mFindCityTask)) { 59 | vista.displayLoading(true); 60 | } 61 | 62 | if (mLastResults != null) { 63 | vista.setCities(mLastResults); 64 | } else if (!TextUtils.isEmpty(mLastSearch) && !mTaskExecutor.isRunning(mFindCityTask)) { 65 | onCitySearch(mLastSearch); 66 | } 67 | } 68 | 69 | public void onCitySearch(String cityName) { 70 | if (getVista() == null) { 71 | return; 72 | } 73 | 74 | cityName = cityName.trim().toLowerCase(); 75 | mLastSearch = cityName; 76 | 77 | getVista().displayLoading(true); 78 | 79 | if (mTaskExecutor.isRunning(mFindCityTask)) { 80 | mFindCityTask.cancel(); 81 | } 82 | mFindCityTask = new FindCityTask(cityName, mCityRepository); 83 | mTaskExecutor.execute(mFindCityTask, new DisplayErrorTaskCallback>(this) { 84 | @Override 85 | public void onSuccess(List result) { 86 | mLastResults = result; 87 | SearchCitiesVista vista = getVista(); 88 | if (vista != null) { 89 | vista.displayLoading(false); 90 | if (result.isEmpty()) { 91 | vista.displayCitiesNotFound(); 92 | } else { 93 | vista.setCities(result); 94 | } 95 | } 96 | } 97 | 98 | 99 | @Override 100 | public void onError(IOException error) { 101 | super.onError(error); 102 | mLastSearch = null; 103 | } 104 | }); 105 | } 106 | 107 | public void onCitySelected(String cityId) { 108 | mActivityNavigator.openCityDetails(cityId); 109 | } 110 | 111 | @Override 112 | public void saveState(Bundle state) { 113 | state.putString(STATE_LAST_SEARCH, mLastSearch); 114 | } 115 | 116 | @Override 117 | public void restoreState(Bundle state) { 118 | mLastSearch = state.getString(STATE_LAST_SEARCH); 119 | } 120 | 121 | @Override 122 | public void onDestroy() { 123 | if (mTaskExecutor.isRunning(mFindCityTask)) { 124 | mFindCityTask.cancel(); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/view/CityListItemView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.view; 18 | 19 | import android.content.Context; 20 | import android.util.AttributeSet; 21 | import android.widget.LinearLayout; 22 | import android.widget.TextView; 23 | 24 | import cat.ppicas.cleanarch.R; 25 | import cat.ppicas.cleanarch.text.NumberFormat; 26 | import cat.ppicas.cleanarch.ui.vista.CityListItemVista; 27 | 28 | /** 29 | * A {@link LinearLayout} extension that implements {@link CityListItemVista}. 30 | */ 31 | public class CityListItemView extends LinearLayout implements CityListItemVista { 32 | 33 | private String mName; 34 | private String mCountry; 35 | 36 | private TextView mNameView; 37 | private TextView mTempView; 38 | private TextView mElevationView; 39 | 40 | public CityListItemView(Context context) { 41 | super(context); 42 | } 43 | 44 | public CityListItemView(Context context, AttributeSet attrs) { 45 | super(context, attrs); 46 | } 47 | 48 | public CityListItemView(Context context, AttributeSet attrs, int defStyle) { 49 | super(context, attrs, defStyle); 50 | } 51 | 52 | @Override 53 | protected void onFinishInflate() { 54 | super.onFinishInflate(); 55 | mNameView = (TextView) findViewById(R.id.city_list_item__name); 56 | mTempView = (TextView) findViewById(R.id.city_list_item__temp); 57 | mElevationView = (TextView) findViewById(R.id.city_list_item__elevation); 58 | } 59 | 60 | @Override 61 | public void setCityName(String name) { 62 | mName = name; 63 | updateNameView(); 64 | } 65 | 66 | @Override 67 | public void setCountry(String country) { 68 | mCountry = country; 69 | updateNameView(); 70 | } 71 | 72 | @Override 73 | public void setCurrentTemp(String temp) { 74 | mTempView.setText(temp); 75 | } 76 | 77 | @Override 78 | public void setLoadingElevation(boolean loading) { 79 | if (loading) { 80 | mElevationView.setText(getContext().getString(R.string.city_list_item__elevation)); 81 | } 82 | } 83 | 84 | @Override 85 | public void setElevation(int elevation) { 86 | mElevationView.setText(NumberFormat.formatElevation(elevation)); 87 | } 88 | 89 | private void updateNameView() { 90 | String text = mName + ", " + mCountry; 91 | mNameView.setText(text); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/vista/CityCurrentWeatherVista.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.vista; 18 | 19 | public interface CityCurrentWeatherVista extends TaskResultVista { 20 | 21 | void setCurrentTemp(String temp); 22 | 23 | void setHumidity(String humidity); 24 | 25 | void setWindSpeed(String windSpeed); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/vista/CityDailyForecastVista.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.vista; 18 | 19 | public interface CityDailyForecastVista extends TaskResultVista { 20 | 21 | void setForecastDescription(String description); 22 | 23 | void setDayTemp(String temp); 24 | 25 | void setMinTemp(String temp); 26 | 27 | void setMaxTemp(String temp); 28 | 29 | void setHumidity(String humidity); 30 | 31 | void setWindSpeed(String windSpeed); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/vista/CityDetailVista.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.vista; 18 | 19 | public interface CityDetailVista extends TaskResultVista { 20 | 21 | void setTitle(int stringResId, Object... args); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/vista/CityListItemVista.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.vista; 18 | 19 | import cat.ppicas.framework.ui.Vista; 20 | 21 | public interface CityListItemVista extends Vista { 22 | 23 | void setCityName(String name); 24 | 25 | void setCountry(String country); 26 | 27 | void setCurrentTemp(String temp); 28 | 29 | void setLoadingElevation(boolean loading); 30 | 31 | void setElevation(int elevation); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/vista/SearchCitiesVista.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.vista; 18 | 19 | import java.util.List; 20 | 21 | import cat.ppicas.cleanarch.model.City; 22 | 23 | public interface SearchCitiesVista extends TaskResultVista { 24 | 25 | void setTitle(int stringResId, Object... args); 26 | 27 | void setCities(List cities); 28 | 29 | void displayCitiesNotFound(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/ui/vista/TaskResultVista.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.ui.vista; 18 | 19 | import cat.ppicas.framework.ui.Vista; 20 | 21 | public interface TaskResultVista extends Vista { 22 | 23 | void displayLoading(boolean display); 24 | 25 | void displayError(int stringResId, Object... args); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/util/AsyncTaskExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.util; 18 | 19 | import android.os.Handler; 20 | 21 | import java.lang.ref.WeakReference; 22 | import java.util.ArrayList; 23 | import java.util.Iterator; 24 | import java.util.List; 25 | import java.util.concurrent.Executor; 26 | import java.util.concurrent.Executors; 27 | 28 | import cat.ppicas.framework.task.Task; 29 | import cat.ppicas.framework.task.TaskCallback; 30 | import cat.ppicas.framework.task.TaskExecutor; 31 | import cat.ppicas.framework.task.TaskResult; 32 | 33 | /** 34 | * A {@link TaskExecutor} implementation that executes tasks on another thread. This class 35 | * will not execute various {@link Task} concurrently. Instead the tasks will be added to the 36 | * queue and execute one by one respecting the execution order. 37 | */ 38 | public class AsyncTaskExecutor implements TaskExecutor { 39 | 40 | private final Executor mExecutor = Executors.newSingleThreadExecutor(); 41 | 42 | private final Handler mHandler = new Handler(); 43 | 44 | private final List> mRunningTasks = new ArrayList<>(); 45 | 46 | @Override 47 | public void execute( 48 | final Task task, final TaskCallback callback) { 49 | 50 | addRunningTask(task); 51 | mExecutor.execute(new Runnable() { 52 | @Override 53 | public void run() { 54 | final TaskResult result = task.execute(); 55 | removeRunningTask(task); 56 | 57 | if (!result.isCanceled()) { 58 | if (result.isSuccess()) { 59 | mHandler.post(new Runnable() { 60 | @Override 61 | public void run() { 62 | callback.onSuccess(result.getResult()); 63 | } 64 | }); 65 | } else { 66 | mHandler.post(new Runnable() { 67 | @Override 68 | public void run() { 69 | callback.onError(result.getError()); 70 | } 71 | }); 72 | } 73 | } 74 | } 75 | }); 76 | } 77 | 78 | @Override 79 | public synchronized boolean isRunning(Task task) { 80 | for (WeakReference rt : mRunningTasks) { 81 | if (rt.get() == task) { 82 | return true; 83 | } 84 | } 85 | 86 | return false; 87 | } 88 | 89 | private synchronized void addRunningTask(Task task) { 90 | mRunningTasks.add(new WeakReference<>(task)); 91 | } 92 | 93 | private synchronized void removeRunningTask(Task task) { 94 | Iterator> iterator = mRunningTasks.iterator(); 95 | while (iterator.hasNext()) { 96 | WeakReference reference = iterator.next(); 97 | if (reference.get() == task || reference.get() == null) { 98 | iterator.remove(); 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/cleanarch/util/DisplayErrorTaskCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.util; 18 | 19 | import java.io.IOException; 20 | 21 | import cat.ppicas.cleanarch.R; 22 | import cat.ppicas.framework.ui.Presenter; 23 | import cat.ppicas.cleanarch.ui.vista.TaskResultVista; 24 | import cat.ppicas.framework.task.TaskCallback; 25 | 26 | /** 27 | * A {@link TaskCallback} implementation that handles {@link IOException} errors automatically. This 28 | * class will stop the loading animation and call {@link TaskResultVista#displayError} when an error 29 | * is thrown during {@code Task} execution. 30 | */ 31 | public abstract class DisplayErrorTaskCallback implements TaskCallback { 32 | 33 | private final Presenter mPresenter; 34 | 35 | /** 36 | * Constructs an instance of {@link DisplayErrorTaskCallback} that will use 37 | * the specified {@link Presenter} to display the errors. To display the errors 38 | * this class expects a {@link Presenter} with a parameter extending {@link 39 | * TaskResultVista}. 40 | * 41 | * @param presenter a {@link Presenter} with a parameter extending {@link 42 | * TaskResultVista} 43 | */ 44 | public DisplayErrorTaskCallback(Presenter presenter) { 45 | mPresenter = presenter; 46 | } 47 | 48 | public void onError(IOException error) { 49 | TaskResultVista vista = mPresenter.getVista(); 50 | if (vista != null) { 51 | vista.displayLoading(false); 52 | error.printStackTrace(); 53 | vista.displayError(R.string.error__connection); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/framework/ui/Presenter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.framework.ui; 18 | 19 | import android.app.Activity; 20 | import android.app.Fragment; 21 | import android.os.Bundle; 22 | import android.support.annotation.Nullable; 23 | 24 | public abstract class Presenter { 25 | 26 | private T mVista; 27 | 28 | /** 29 | * Returns the current bound {@link Vista} if any. 30 | * 31 | * @return The bound {@code Vista} or {@code null}. 32 | */ 33 | @Nullable 34 | public T getVista() { 35 | return mVista; 36 | } 37 | 38 | /** 39 | * Must be called to bind the {@link Vista} and let the {@link Presenter} know that can start 40 | * {@code Vista} updates. Normally this method will be called from {@link Activity#onStart()} 41 | * or from {@link Fragment#onStart()}. 42 | * 43 | * @param vista A {@code Vista} instance to bind. 44 | */ 45 | public final void start(T vista) { 46 | mVista = vista; 47 | onStart(vista); 48 | } 49 | 50 | /** 51 | * Must be called un unbind the {@link Vista} and let the {@link Presenter} know that must 52 | * stop updating the {@code Vista}. Normally this method will be called from 53 | * {@link Activity#onStop()} or from {@link Fragment#onStop()}. 54 | */ 55 | public final void stop() { 56 | mVista = null; 57 | onStop(); 58 | } 59 | 60 | /** 61 | * Called when the {@link Presenter} can start {@link Vista} updates. 62 | * 63 | * @param vista The bound {@code Vista}. 64 | */ 65 | public abstract void onStart(T vista); 66 | 67 | /** 68 | * Called when the {@link Presenter} must stop {@link Vista} updates. The extending 69 | * {@code Presenter} can override this method to provide some custom logic. 70 | */ 71 | public void onStop() { 72 | } 73 | 74 | /** 75 | * Called to ask the {@link Presenter} to save its current dynamic state, so it 76 | * can later be reconstructed in a new instance of its process is 77 | * restarted. 78 | * 79 | * @param state Bundle in which to place your saved state. 80 | * @see Activity#onSaveInstanceState(Bundle) 81 | */ 82 | public void saveState(Bundle state) { 83 | } 84 | 85 | /** 86 | * Called to ask the {@link Presenter} to restore the previous saved state. 87 | * 88 | * @param state The data most recently supplied in {@link #saveState}. 89 | * @see Activity#onRestoreInstanceState(Bundle) 90 | */ 91 | public void restoreState(Bundle state) { 92 | } 93 | 94 | /** 95 | * Called when this {@link Presenter} is going to be destroyed, so it has a chance to 96 | * release resources. The extending {@code Presenter} can override this method to provide some 97 | * custom logic. 98 | */ 99 | public void onDestroy() { 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/framework/ui/PresenterFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.framework.ui; 18 | 19 | public interface PresenterFactory> { 20 | 21 | T createPresenter(); 22 | 23 | String getPresenterTag(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/framework/ui/PresenterHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.framework.ui; 18 | 19 | public interface PresenterHolder { 20 | 21 | > T getOrCreatePresenter(PresenterFactory presenterFactory); 22 | 23 | void destroyPresenter(PresenterFactory presenterFactory); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/cat/ppicas/framework/ui/Vista.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.framework.ui; 18 | 19 | public interface Vista { 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_city_current_weather.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 22 | 23 | 28 | 29 | 34 | 35 | 41 | 42 | 47 | 48 | 54 | 55 | 60 | 61 | 64 | 65 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_city_daily_forecast.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 22 | 23 | 26 | 27 | 32 | 33 | 37 | 38 | 43 | 44 | 49 | 50 | 55 | 56 | 61 | 62 | 67 | 68 | 73 | 74 | 79 | 80 | 85 | 86 | 91 | 92 | 97 | 98 | 103 | 104 | 105 | 106 | 109 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_city_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 22 | 23 | 28 | 29 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_search_cities.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 22 | 23 | 29 | 30 | 35 | 36 | 41 | 42 | 46 | 47 | 54 | 55 | 56 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/src/main/res/layout/include_loading_layer.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 26 | 27 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_city_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 24 | 25 | 32 | 33 | 38 | 39 | 45 | 46 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ppicas/android-clean-architecture-mvp/3173fdaab7edef0ee824200642a25751a3c3b56a/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ppicas/android-clean-architecture-mvp/3173fdaab7edef0ee824200642a25751a3c3b56a/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ppicas/android-clean-architecture-mvp/3173fdaab7edef0ee824200642a25751a3c3b56a/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ppicas/android-clean-architecture-mvp/3173fdaab7edef0ee824200642a25751a3c3b56a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ppicas/android-clean-architecture-mvp/3173fdaab7edef0ee824200642a25751a3c3b56a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 21 | 64dp 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 16dp 20 | 16dp 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | Clean Architecture 21 | Today 22 | Tomorrow 23 | 24 | Connection problem 25 | 26 | Search city 27 | City name 28 | No cities found 29 | 30 | %s weather 31 | Loading weather 32 | Current weather 33 | %s\'s forecast 34 | 35 | Temperature 36 | Humidity 37 | Wind speed 38 | 39 | Forecast: 40 | Temperature: 41 | Max temperature: 42 | Min temperature: 43 | Humidity: 44 | Wind speed: 45 | 46 | elevation... 47 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 32 | 33 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 18 | 19 | buildscript { 20 | repositories { 21 | jcenter() 22 | } 23 | dependencies { 24 | classpath 'com.android.tools.build:gradle:1.3.0' 25 | 26 | // NOTE: Do not place your application dependencies here; they belong 27 | // in the individual module build.gradle files 28 | } 29 | } 30 | 31 | allprojects { 32 | repositories { 33 | jcenter() 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | apply plugin: 'java' 18 | 19 | sourceCompatibility = JavaVersion.VERSION_1_7 20 | targetCompatibility = JavaVersion.VERSION_1_7 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile 'com.squareup.retrofit:retrofit:1.6.1' 25 | compile 'com.squareup.okhttp:okhttp:2.0.0' 26 | compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0' 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/model/City.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.model; 18 | 19 | public class City { 20 | 21 | private String mId; 22 | private String mName; 23 | private String mCountry; 24 | private CurrentWeatherPreview mCurrentWeatherPreview; 25 | 26 | public City(String id, String name, String country) { 27 | mId = id; 28 | mName = name; 29 | mCountry = country; 30 | } 31 | 32 | public City(String id, String name, String country, 33 | CurrentWeatherPreview currentWeatherPreview) { 34 | mId = id; 35 | mName = name; 36 | mCountry = country; 37 | mCurrentWeatherPreview = currentWeatherPreview; 38 | } 39 | 40 | public String getId() { 41 | return mId; 42 | } 43 | 44 | public String getName() { 45 | return mName; 46 | } 47 | 48 | public String getCountry() { 49 | return mCountry; 50 | } 51 | 52 | public CurrentWeatherPreview getCurrentWeatherPreview() { 53 | return mCurrentWeatherPreview; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/model/CurrentWeather.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.model; 18 | 19 | public class CurrentWeather extends CurrentWeatherPreview { 20 | 21 | private int mHumidity; 22 | private double mWindSpeed; 23 | 24 | public CurrentWeather(String cityId, double currentTemp, int humidity, double windSpeed) { 25 | super(cityId, currentTemp); 26 | mHumidity = humidity; 27 | mWindSpeed = windSpeed; 28 | } 29 | 30 | public int getHumidity() { 31 | return mHumidity; 32 | } 33 | 34 | public double getWindSpeed() { 35 | return mWindSpeed; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/model/CurrentWeatherPreview.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.model; 18 | 19 | public class CurrentWeatherPreview { 20 | 21 | private String mCityId; 22 | private double mCurrentTemp; 23 | 24 | public CurrentWeatherPreview(String cityId, double currentTemp) { 25 | mCityId = cityId; 26 | mCurrentTemp = currentTemp; 27 | } 28 | 29 | public String getCityId() { 30 | return mCityId; 31 | } 32 | 33 | public double getCurrentTemp() { 34 | return mCurrentTemp; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/model/DailyForecast.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.model; 18 | 19 | import java.util.Date; 20 | 21 | public class DailyForecast { 22 | 23 | private String mCityId; 24 | private Date mDate; 25 | private String mDescription; 26 | private double mDayTemp; 27 | private double mMinTemp; 28 | private double mMaxTemp; 29 | private double mHumidity; 30 | private double mWindSpeed; 31 | 32 | public DailyForecast(String cityId, Date date, String description, double dayTemp, 33 | double minTemp, double maxTemp, double humidity, double windSpeed) { 34 | mCityId = cityId; 35 | mDate = date; 36 | mDescription = description; 37 | mDayTemp = dayTemp; 38 | mMinTemp = minTemp; 39 | mMaxTemp = maxTemp; 40 | mHumidity = humidity; 41 | mWindSpeed = windSpeed; 42 | } 43 | 44 | public String getCityId() { 45 | return mCityId; 46 | } 47 | 48 | public Date getDate() { 49 | return mDate; 50 | } 51 | 52 | public String getDescription() { 53 | return mDescription; 54 | } 55 | 56 | public double getDayTemp() { 57 | return mDayTemp; 58 | } 59 | 60 | public double getMinTemp() { 61 | return mMinTemp; 62 | } 63 | 64 | public double getMaxTemp() { 65 | return mMaxTemp; 66 | } 67 | 68 | public double getHumidity() { 69 | return mHumidity; 70 | } 71 | 72 | public double getWindSpeed() { 73 | return mWindSpeed; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/owm/OWMCityRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.owm; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | import cat.ppicas.cleanarch.model.City; 23 | import cat.ppicas.cleanarch.model.CurrentWeatherPreview; 24 | import cat.ppicas.cleanarch.owm.model.OWMCurrentWeather; 25 | import cat.ppicas.cleanarch.owm.model.OWMCurrentWeatherList; 26 | import cat.ppicas.cleanarch.repository.CityRepository; 27 | 28 | public class OWMCityRepository implements CityRepository { 29 | 30 | private final OWMService mService; 31 | 32 | public OWMCityRepository(OWMService service) { 33 | mService = service; 34 | } 35 | 36 | @Override 37 | public City getCity(String cityId) { 38 | OWMCurrentWeather cw = mService.getCurrentWeatherByCityId(cityId); 39 | return createCityFromCityWeather(cw); 40 | } 41 | 42 | @Override 43 | public List findCity(String name) { 44 | List cities = new ArrayList(); 45 | OWMCurrentWeatherList citiesWeather = mService.getCurrentWeatherByCityName(name); 46 | for (OWMCurrentWeather cw : citiesWeather.getList()) { 47 | cities.add(createCityFromCityWeather(cw)); 48 | } 49 | return cities; 50 | } 51 | 52 | private City createCityFromCityWeather(OWMCurrentWeather cw) { 53 | CurrentWeatherPreview weatherPreview = new CurrentWeatherPreview( 54 | cw.getCityId(), cw.getMain().getTemp()); 55 | City city = new City(cw.getCityId(), cw.getCityName(), 56 | cw.getSystem().getCountry(), weatherPreview); 57 | return city; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/owm/OWMCurrentWeatherRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.owm; 18 | 19 | import cat.ppicas.cleanarch.model.CurrentWeather; 20 | import cat.ppicas.cleanarch.owm.model.OWMCurrentWeather; 21 | import cat.ppicas.cleanarch.repository.CurrentWeatherRepository; 22 | 23 | public class OWMCurrentWeatherRepository implements CurrentWeatherRepository { 24 | 25 | private OWMService mService; 26 | 27 | public OWMCurrentWeatherRepository(OWMService service) { 28 | mService = service; 29 | } 30 | 31 | @Override 32 | public CurrentWeather getCityCurrentWeather(String cityId) { 33 | OWMCurrentWeather cw = mService.getCurrentWeatherByCityId(cityId); 34 | return new CurrentWeather(cw.getCityId(), cw.getMain().getTemp(), 35 | cw.getMain().getHumidity(), cw.getWind().getSpeed()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/owm/OWMDailyForecastRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.owm; 18 | 19 | import java.util.ArrayList; 20 | import java.util.Date; 21 | import java.util.List; 22 | 23 | import cat.ppicas.cleanarch.model.DailyForecast; 24 | import cat.ppicas.cleanarch.owm.model.OWMDailyForecast; 25 | import cat.ppicas.cleanarch.owm.model.OWMDailyForecastList; 26 | import cat.ppicas.cleanarch.repository.DailyForecastRepository; 27 | 28 | public class OWMDailyForecastRepository implements DailyForecastRepository { 29 | 30 | private static final int FORECAST_DAYS = 3; 31 | 32 | private OWMService mService; 33 | 34 | public OWMDailyForecastRepository(OWMService service) { 35 | mService = service; 36 | } 37 | 38 | @Override 39 | public List getDailyForecasts(String cityId) { 40 | List list = new ArrayList(); 41 | OWMDailyForecastList owmDFList = mService.getDailyForecastByCityId(cityId, FORECAST_DAYS); 42 | for (OWMDailyForecast owmDF : owmDFList.getList()) { 43 | list.add(createDailyForecast(cityId, owmDF)); 44 | } 45 | return list; 46 | } 47 | 48 | private DailyForecast createDailyForecast(String cityId, OWMDailyForecast owmDF) { 49 | Date data = new Date(owmDF.getTimestamp() * 1000L); 50 | String description = (owmDF.getWeatherList().length >= 1) 51 | ? owmDF.getWeatherList()[0].getDescription() : "Not available"; 52 | OWMDailyForecast.Temp temp = owmDF.getTemp(); 53 | return new DailyForecast(cityId, data, description, temp.getDay(), temp.getMin(), 54 | temp.getMax(), owmDF.getHumidity(), owmDF.getWindSpeed()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/owm/OWMService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.owm; 18 | 19 | import cat.ppicas.cleanarch.owm.model.OWMCurrentWeather; 20 | import cat.ppicas.cleanarch.owm.model.OWMCurrentWeatherList; 21 | import cat.ppicas.cleanarch.owm.model.OWMDailyForecastList; 22 | import retrofit.http.GET; 23 | import retrofit.http.Headers; 24 | import retrofit.http.Query; 25 | 26 | public interface OWMService { 27 | 28 | @GET("/data/2.5/find?units=metric") 29 | @Headers("Cache-Control: max-age=300, max-stale=900") 30 | OWMCurrentWeatherList getCurrentWeatherByCityName(@Query("q") String query); 31 | 32 | @GET("/data/2.5/weather?units=metric") 33 | @Headers("Cache-Control: max-age=300, max-stale=900") 34 | OWMCurrentWeather getCurrentWeatherByCityId(@Query("id") String id); 35 | 36 | @GET("/data/2.5/forecast/daily?units=metric") 37 | @Headers("Cache-Control: max-age=300, max-stale=900") 38 | OWMDailyForecastList getDailyForecastByCityId(@Query("id") String id, 39 | @Query("cnt") int days); 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/owm/model/OWMCurrentWeather.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.owm.model; 18 | 19 | import com.google.gson.annotations.SerializedName; 20 | 21 | @SuppressWarnings("UnusedDeclaration") 22 | public class OWMCurrentWeather { 23 | 24 | @SerializedName("id") 25 | private String mCityId; 26 | @SerializedName("name") 27 | private String mCityName; 28 | @SerializedName("main") 29 | private Main mMain; 30 | @SerializedName("wind") 31 | private Wind mWind; 32 | @SerializedName("sys") 33 | private System mSystem; 34 | 35 | public String getCityId() { 36 | return mCityId; 37 | } 38 | 39 | public String getCityName() { 40 | return mCityName; 41 | } 42 | 43 | public Main getMain() { 44 | return mMain; 45 | } 46 | 47 | public Wind getWind() { 48 | return mWind; 49 | } 50 | 51 | public System getSystem() { 52 | return mSystem; 53 | } 54 | 55 | public class Main { 56 | @SerializedName("temp") 57 | private double mTemp; 58 | @SerializedName("humidity") 59 | private int mHumidity; 60 | 61 | public double getTemp() { 62 | return mTemp; 63 | } 64 | 65 | public int getHumidity() { 66 | return mHumidity; 67 | } 68 | } 69 | 70 | public class Wind { 71 | @SerializedName("speed") 72 | private double mSpeed; 73 | 74 | public double getSpeed() { 75 | return mSpeed; 76 | } 77 | } 78 | 79 | public class System { 80 | @SerializedName("country") 81 | private String mCountry; 82 | 83 | public String getCountry() { 84 | return mCountry; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/owm/model/OWMCurrentWeatherList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.owm.model; 18 | 19 | import com.google.gson.annotations.SerializedName; 20 | 21 | import java.util.List; 22 | 23 | @SuppressWarnings("UnusedDeclaration") 24 | public class OWMCurrentWeatherList { 25 | 26 | @SerializedName("count") 27 | private int mCount; 28 | @SerializedName("list") 29 | private List mCurrentWeatherList; 30 | 31 | public int getCount() { 32 | return mCount; 33 | } 34 | 35 | public List getList() { 36 | return mCurrentWeatherList; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/owm/model/OWMDailyForecast.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.owm.model; 18 | 19 | import com.google.gson.annotations.SerializedName; 20 | 21 | @SuppressWarnings("UnusedDeclaration") 22 | public class OWMDailyForecast { 23 | 24 | @SerializedName("dt") 25 | private int mTimestamp; 26 | @SerializedName("temp") 27 | private Temp mTemp; 28 | @SerializedName("humidity") 29 | private int mHumidity; 30 | @SerializedName("speed") 31 | private double mWindSpeed; 32 | @SerializedName("weather") 33 | private Weather[] mWeatherList; 34 | 35 | public int getTimestamp() { 36 | return mTimestamp; 37 | } 38 | 39 | public Temp getTemp() { 40 | return mTemp; 41 | } 42 | 43 | public int getHumidity() { 44 | return mHumidity; 45 | } 46 | 47 | public double getWindSpeed() { 48 | return mWindSpeed; 49 | } 50 | 51 | public Weather[] getWeatherList() { 52 | return mWeatherList; 53 | } 54 | 55 | public class Temp { 56 | @SerializedName("day") 57 | private double mDay; 58 | @SerializedName("min") 59 | private double mMin; 60 | @SerializedName("max") 61 | private double mMax; 62 | 63 | public double getDay() { 64 | return mDay; 65 | } 66 | 67 | public double getMin() { 68 | return mMin; 69 | } 70 | 71 | public double getMax() { 72 | return mMax; 73 | } 74 | } 75 | 76 | public class Weather { 77 | @SerializedName("description") 78 | private String mDescription; 79 | 80 | public String getDescription() { 81 | return mDescription; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/owm/model/OWMDailyForecastList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.owm.model; 18 | 19 | import com.google.gson.annotations.SerializedName; 20 | 21 | import java.util.List; 22 | 23 | @SuppressWarnings("UnusedDeclaration") 24 | public class OWMDailyForecastList { 25 | 26 | @SerializedName("cnt") 27 | private int mCount; 28 | @SerializedName("city") 29 | private City mCity; 30 | @SerializedName("list") 31 | private List mDailyForecasts; 32 | 33 | public int getCount() { 34 | return mCount; 35 | } 36 | 37 | public City getCity() { 38 | return mCity; 39 | } 40 | 41 | public List getList() { 42 | return mDailyForecasts; 43 | } 44 | 45 | public class City { 46 | @SerializedName("id") 47 | private String mId; 48 | 49 | public String getId() { 50 | return mId; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/repository/CityRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.repository; 18 | 19 | import java.util.List; 20 | 21 | import cat.ppicas.cleanarch.model.City; 22 | 23 | public interface CityRepository { 24 | 25 | City getCity(String cityId); 26 | 27 | List findCity(String name); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/repository/CurrentWeatherRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.repository; 18 | 19 | import cat.ppicas.cleanarch.model.CurrentWeather; 20 | 21 | public interface CurrentWeatherRepository { 22 | 23 | CurrentWeather getCityCurrentWeather(String cityId); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/repository/DailyForecastRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.repository; 18 | 19 | import java.util.List; 20 | 21 | import cat.ppicas.cleanarch.model.DailyForecast; 22 | 23 | public interface DailyForecastRepository { 24 | 25 | List getDailyForecasts(String cityId); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/task/FindCityTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.task; 18 | 19 | import java.io.IOException; 20 | import java.util.List; 21 | 22 | import cat.ppicas.cleanarch.model.City; 23 | import cat.ppicas.cleanarch.repository.CityRepository; 24 | import cat.ppicas.framework.task.Task; 25 | import cat.ppicas.framework.task.TaskResult; 26 | import retrofit.RetrofitError; 27 | 28 | public class FindCityTask implements Task, IOException> { 29 | 30 | private String mCityName; 31 | private CityRepository mRepository; 32 | 33 | private boolean mCanceled; 34 | 35 | public FindCityTask(String cityName, CityRepository repository) { 36 | mCityName = cityName; 37 | mRepository = repository; 38 | } 39 | 40 | @Override 41 | public TaskResult, IOException> execute() { 42 | try { 43 | List city = mRepository.findCity(mCityName); 44 | if (mCanceled) { 45 | return TaskResult.newCanceledResult(); 46 | } else { 47 | return TaskResult.newSuccessResult(city); 48 | } 49 | } catch (RetrofitError e) { 50 | return TaskResult.newErrorResult(new IOException(e)); 51 | } 52 | } 53 | 54 | public void cancel() { 55 | mCanceled = true; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/task/GetCityTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.task; 18 | 19 | import java.io.IOException; 20 | 21 | import cat.ppicas.cleanarch.model.City; 22 | import cat.ppicas.cleanarch.repository.CityRepository; 23 | import cat.ppicas.framework.task.Task; 24 | import cat.ppicas.framework.task.TaskResult; 25 | import retrofit.RetrofitError; 26 | 27 | public class GetCityTask implements Task { 28 | 29 | private String mId; 30 | 31 | private CityRepository mRepository; 32 | 33 | public GetCityTask(CityRepository repository, String id) { 34 | mId = id; 35 | mRepository = repository; 36 | } 37 | 38 | @Override 39 | public TaskResult execute() { 40 | try { 41 | return TaskResult.newSuccessResult(mRepository.getCity(mId)); 42 | } catch (RetrofitError e) { 43 | return TaskResult.newErrorResult(new IOException(e)); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/task/GetCurrentWeatherTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.task; 18 | 19 | import java.io.IOException; 20 | 21 | import cat.ppicas.cleanarch.model.CurrentWeather; 22 | import cat.ppicas.cleanarch.repository.CurrentWeatherRepository; 23 | import cat.ppicas.framework.task.Task; 24 | import cat.ppicas.framework.task.TaskResult; 25 | import retrofit.RetrofitError; 26 | 27 | public class GetCurrentWeatherTask implements Task { 28 | 29 | private CurrentWeatherRepository mRepository; 30 | 31 | private String mCityId; 32 | 33 | public GetCurrentWeatherTask(CurrentWeatherRepository repository, String cityId) { 34 | mRepository = repository; 35 | mCityId = cityId; 36 | } 37 | 38 | @Override 39 | public TaskResult execute() { 40 | try { 41 | return TaskResult.newSuccessResult(mRepository.getCityCurrentWeather(mCityId)); 42 | } catch (RetrofitError e) { 43 | return TaskResult.newErrorResult(new IOException(e)); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/task/GetDailyForecastsTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.task; 18 | 19 | import java.io.IOException; 20 | import java.util.List; 21 | 22 | import cat.ppicas.cleanarch.model.DailyForecast; 23 | import cat.ppicas.cleanarch.repository.DailyForecastRepository; 24 | import cat.ppicas.framework.task.Task; 25 | import cat.ppicas.framework.task.TaskResult; 26 | import retrofit.RetrofitError; 27 | 28 | public class GetDailyForecastsTask implements Task, IOException> { 29 | 30 | private DailyForecastRepository mRepository; 31 | 32 | private String mCityId; 33 | 34 | public GetDailyForecastsTask(DailyForecastRepository repository, String cityId) { 35 | mRepository = repository; 36 | mCityId = cityId; 37 | } 38 | 39 | @Override 40 | public TaskResult, IOException> execute() { 41 | try { 42 | return TaskResult.newSuccessResult(mRepository.getDailyForecasts(mCityId)); 43 | } catch (RetrofitError e) { 44 | return TaskResult.newErrorResult(new IOException(e)); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/cleanarch/task/GetElevationTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.cleanarch.task; 18 | 19 | import cat.ppicas.cleanarch.model.City; 20 | import cat.ppicas.framework.task.NoException; 21 | import cat.ppicas.framework.task.Task; 22 | import cat.ppicas.framework.task.TaskResult; 23 | 24 | public class GetElevationTask implements Task { 25 | 26 | @SuppressWarnings("FieldCanBeLocal") 27 | private City mCity; 28 | 29 | private volatile boolean mCanceled; 30 | 31 | public GetElevationTask(City city) { 32 | mCity = city; 33 | } 34 | 35 | @Override 36 | public TaskResult execute() { 37 | try { 38 | // Here we simulate an external call to some service 39 | for (int i = 0; i < 15 && !mCanceled; i++) { 40 | Thread.sleep(100); 41 | } 42 | } catch (InterruptedException ignored) {} 43 | 44 | if (!mCanceled) { 45 | int result = (int) (Math.random() * 1500); 46 | return TaskResult.newSuccessResult(result); 47 | } else { 48 | return TaskResult.newCanceledResult(); 49 | } 50 | } 51 | 52 | public void cancel() { 53 | mCanceled = true; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/framework/task/NoException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.framework.task; 18 | 19 | /** 20 | * Special {@link RuntimeException} that can be used to indicate that a {@link Task} doesn't 21 | * return any kind of error. 22 | * 23 | * @author Pau Picas 24 | */ 25 | public final class NoException extends RuntimeException { 26 | 27 | private NoException() { 28 | // Private constructor to ensure this class is never instantiated 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/framework/task/SuccessTaskCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.framework.task; 18 | 19 | /** 20 | * Specialized {@link TaskCallback} that can be used with {@link Task} implementations that are 21 | * always successful. An always successful {@code Task} is the one that declares that returns 22 | * {@link NoException} as error. 23 | * 24 | * @author Pau Picas 25 | */ 26 | public abstract class SuccessTaskCallback implements TaskCallback { 27 | 28 | @Override 29 | public void onError(NoException error) { 30 | throw error; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/framework/task/Task.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.framework.task; 18 | 19 | public interface Task { 20 | 21 | TaskResult execute(); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/framework/task/TaskCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.framework.task; 18 | 19 | public interface TaskCallback { 20 | 21 | void onSuccess(R result); 22 | 23 | void onError(E error); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/framework/task/TaskExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.framework.task; 18 | 19 | public interface TaskExecutor { 20 | 21 | void execute(Task task, TaskCallback callback); 22 | 23 | boolean isRunning(Task task); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/cat/ppicas/framework/task/TaskResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package cat.ppicas.framework.task; 18 | 19 | public class TaskResult { 20 | 21 | private final R mResult; 22 | 23 | private final E mError; 24 | 25 | private final boolean mCanceled; 26 | 27 | public static TaskResult newSuccessResult(R result) { 28 | return new TaskResult<>(result, null, false); 29 | } 30 | 31 | public static TaskResult newErrorResult(E error) { 32 | return new TaskResult<>(null, error, false); 33 | } 34 | 35 | public static TaskResult newCanceledResult() { 36 | return new TaskResult<>(null, null, true); 37 | } 38 | 39 | TaskResult(R result, E error, boolean canceled) { 40 | mResult = result; 41 | mError = error; 42 | mCanceled = canceled; 43 | } 44 | 45 | public R getResult() { 46 | return mResult; 47 | } 48 | 49 | public E getError() { 50 | return mError; 51 | } 52 | 53 | public boolean isSuccess() { 54 | return !mCanceled && mError == null; 55 | } 56 | 57 | public boolean isCanceled() { 58 | return mCanceled; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2015 Pau Picas Sans 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | # use this file except in compliance with the License. You may obtain a copy of 6 | # the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations under 14 | # the License. 15 | # 16 | 17 | # Project-wide Gradle settings. 18 | 19 | # IDE (e.g. Android Studio) users: 20 | # Settings specified in this file will override any Gradle settings 21 | # configured through the IDE. 22 | 23 | # For more details on how to configure your build environment visit 24 | # http://www.gradle.org/docs/current/userguide/build_environment.html 25 | 26 | # Specifies the JVM arguments used for the daemon process. 27 | # The setting is particularly useful for tweaking memory settings. 28 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 29 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 30 | 31 | # When configured, Gradle will run in incubating parallel mode. 32 | # This option should only be used with decoupled projects. More details, visit 33 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 34 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ppicas/android-clean-architecture-mvp/3173fdaab7edef0ee824200642a25751a3c3b56a/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2015 Pau Picas Sans 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | # use this file except in compliance with the License. You may obtain a copy of 6 | # the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations under 14 | # the License. 15 | # 16 | 17 | #Wed Dec 03 21:34:05 CET 2014 18 | distributionBase=GRADLE_USER_HOME 19 | distributionPath=wrapper/dists 20 | zipStoreBase=GRADLE_USER_HOME 21 | zipStorePath=wrapper/dists 22 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip 23 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /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 | /* 2 | * Copyright (C) 2015 Pau Picas Sans 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | include ':app', ':core' 18 | --------------------------------------------------------------------------------