├── .gitattributes ├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── License.txt ├── README.md ├── app ├── .gitignore ├── build.gradle ├── google-services.json ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── sampleapp │ │ └── ApplicationTest.java │ ├── debug │ └── res │ │ └── values │ │ └── google_maps_api.xml │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── sampleapp │ │ │ ├── api │ │ │ ├── NetModule.java │ │ │ └── RestService.java │ │ │ ├── base │ │ │ ├── AppComponent.java │ │ │ ├── BaseActivity.java │ │ │ ├── BaseFragment.java │ │ │ └── SampleApplication.java │ │ │ ├── constants │ │ │ ├── ApiConstants.java │ │ │ ├── PrefernceConstants.java │ │ │ └── ValueConstants.java │ │ │ ├── interfaces │ │ │ ├── LocationUpdateListener.java │ │ │ └── OnDialogButtonClickListener.java │ │ │ ├── model │ │ │ ├── UserData.java │ │ │ ├── request │ │ │ │ └── LoginRequest.java │ │ │ └── response │ │ │ │ └── LoginResponse.java │ │ │ ├── module │ │ │ ├── SplashActivity.java │ │ │ ├── fragmentsample │ │ │ │ ├── SampleFragment.java │ │ │ │ ├── SamplePresenter.java │ │ │ │ └── SampleView.java │ │ │ ├── login │ │ │ │ ├── LoginActivity.java │ │ │ │ ├── LoginComponent.java │ │ │ │ ├── LoginModule.java │ │ │ │ ├── LoginPresenter.java │ │ │ │ ├── LoginPresenterComponent.java │ │ │ │ └── LoginView.java │ │ │ └── register │ │ │ │ ├── RegisterActivity.java │ │ │ │ ├── RegisterMvpView.java │ │ │ │ └── RegisterPresenter.java │ │ │ ├── mvpbase │ │ │ ├── BasePresenter.java │ │ │ ├── MvpView.java │ │ │ └── Presenter.java │ │ │ ├── notification │ │ │ ├── PushMessagingService.java │ │ │ └── SampleAppFirebaseInstanceIDService.java │ │ │ ├── utils │ │ │ ├── AppUtils.java │ │ │ ├── DateTimeUtils.java │ │ │ ├── DialogsUtil.java │ │ │ ├── FragmentUtils.java │ │ │ ├── ImageUtility.java │ │ │ ├── LocationHelper.java │ │ │ ├── LocationTracker.java │ │ │ ├── PreferenceManager.java │ │ │ ├── ProgressBarHandler.java │ │ │ └── UtilsModule.java │ │ │ └── views │ │ │ └── RemoveErrorEditText.java │ └── res │ │ ├── drawable-v21 │ │ └── general_click_selector.xml │ │ ├── drawable │ │ └── general_click_selector.xml │ │ ├── layout │ │ ├── activity_login.xml │ │ ├── activity_register.xml │ │ ├── activity_splash.xml │ │ └── fragment_sample.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-hdpi │ │ └── dimens.xml │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ ├── values-xhdpi │ │ └── dimens.xml │ │ ├── values-xxhdpi │ │ └── dimens.xml │ │ ├── values-xxxhdpi │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ ├── release │ └── res │ │ └── values │ │ └── google_maps_api.xml │ └── test │ └── java │ └── com │ └── sampleapp │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | SampleApp -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | C:\Users\saveen_dhiman\AppData\Roaming\Subversion 48 | 49 | 50 | 51 | 52 | 53 | 1.8 54 | 55 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SampleApp 2 | # Android Project Structure 3 | 4 | 5 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/2a8eb532d98842f6966bc164a896419a)](https://www.codacy.com/app/saveendhiman/SampleApp?utm_source=github.com&utm_medium=referral&utm_content=saveendhiman/SampleApp&utm_campaign=badger) 6 | [![Twitter](https://img.shields.io/badge/Twitter-@saveendhiman-blue.svg?style=flat)](https://twitter.com/saveendhiman) 7 | 8 | [![API](https://img.shields.io/badge/API-14%2B-yellow.svg?style=flat)](https://android-arsenal.com/api?level=14) 9 | 10 | [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) 11 | 12 | 13 | Hi guys, I have made one Project Structure for Android. This is the open project for any contributer who want to improve something here. 14 | 15 | This a Sample Project Structure for Android which you can follow for a clean architecture. 16 | 17 | **NOTE:** It's quite old one. You can refer [ComplexRecycler] Sample project. It's in Kotlin too. 18 | 19 | It shows usage of following libraries: 20 | 21 | * [Retrofit2] for REST API. 22 | 23 | * [RX java] for background process and Retrofit integration. 24 | 25 | * [Dagger2] for dependency injection. 26 | 27 | * [Firebase] for push notifications. 28 | 29 | * [Calligraphy] for font. 30 | 31 | * [Picasso] for image loading. 32 | 33 | * [Komensky] validations for annotation based validations. 34 | 35 | * [Fabric] for crashlytics. 36 | 37 | * [Butterknife] for view binding. 38 | 39 | * [Timber] for logging. 40 | 41 | It uses MVP (Model View Presenter) pattern. MVP is a derivative from the well known MVC (Model View Controller), which for a while now is gaining importance in the development of Android applications.This project also contains basic utility classes required for day to day programming. 42 | 43 | 44 | Location Handling by fused api. 45 | 46 | Utils classes. 47 | 48 | 49 | # Here is what the app gradle look likes. 50 | 51 | buildscript { 52 | repositories { 53 | maven { url 'https://maven.fabric.io/public' } 54 | } 55 | 56 | dependencies { 57 | classpath 'io.fabric.tools:gradle:1.+' 58 | } 59 | } 60 | apply plugin: 'com.android.application' 61 | apply plugin: 'io.fabric' 62 | apply plugin: 'com.neenbedankt.android-apt' 63 | apply plugin: 'me.tatarka.retrolambda' 64 | 65 | android { 66 | compileSdkVersion rootProject.ext.compileSdkVersion 67 | buildToolsVersion rootProject.ext.buildToolsVersion 68 | 69 | //app versioning 70 | def versionMajor = 1 71 | def versionMinor = 0 72 | def versionPatch = 0 73 | def versionBuild = 0 74 | 75 | defaultConfig { 76 | applicationId "com.sampleapp" 77 | minSdkVersion rootProject.ext.minSdkVersion 78 | targetSdkVersion rootProject.ext.targetSdkVersion 79 | versionCode versionMajor * 10000 + versionMinor * 1000 + versionPatch * 100 + versionBuild 80 | versionName "${versionMajor}.${versionMinor}.${versionPatch}" 81 | } 82 | buildTypes { 83 | release { 84 | minifyEnabled false 85 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 86 | } 87 | } 88 | 89 | compileOptions { 90 | sourceCompatibility JavaVersion.VERSION_1_8 91 | targetCompatibility JavaVersion.VERSION_1_8 92 | } 93 | } 94 | 95 | repositories { 96 | maven { 97 | url "https://jitpack.io" 98 | } 99 | maven { url 'https://maven.fabric.io/public' } 100 | } 101 | 102 | dependencies { 103 | compile fileTree(include: ['*.jar'], dir: 'libs') 104 | compile "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion" 105 | compile "com.android.support:design:$rootProject.supportLibraryVersion" 106 | apt "com.google.dagger:dagger-compiler:$rootProject.daggerVersion" 107 | provided "org.glassfish:javax.annotation:$rootProject.ext.annotationVersion" 108 | compile "com.google.dagger:dagger:$rootProject.daggerVersion" 109 | compile "com.squareup.retrofit2:retrofit:$rootProject.ext.retrofitVersion" 110 | compile "com.squareup.retrofit2:converter-gson:$rootProject.ext.retrofitVersion" 111 | compile "com.squareup.retrofit2:adapter-rxjava:$rootProject.ext.retrofitVersion" 112 | compile "com.squareup.okhttp3:logging-interceptor:$rootProject.ext.loggerVersion" 113 | compile "io.reactivex:rxjava:$rootProject.ext.rxJavaVersion" 114 | compile "io.reactivex:rxandroid:$rootProject.ext.rxAndroidVersion" 115 | compile "com.jakewharton:butterknife:$rootProject.ext.butterknifeVersion" 116 | apt "com.jakewharton:butterknife-compiler:$rootProject.ext.butterknifeVersion" 117 | compile "com.jakewharton.timber:timber:$rootProject.ext.timberVersion" 118 | compile "com.google.android.gms:play-services-location:$rootProject.ext.playServiceVersion" 119 | compile "com.google.firebase:firebase-messaging:$rootProject.ext.playServiceVersion" 120 | compile "com.google.android.gms:play-services-maps:$rootProject.ext.playServiceVersion" 121 | compile "uk.co.chrisjenx:calligraphy:$rootProject.ext.calligraphyVersion" 122 | compile "com.squareup.picasso:picasso:$rootProject.ext.picassoVersion" 123 | compile "eu.inmite.android.lib:android-validation-komensky:$rootProject.ext.komenskyValidation@aar" 124 | compile("com.crashlytics.sdk.android:crashlytics:$rootProject.ext.crashVersion@aar") { 125 | transitive = true; 126 | } 127 | 128 | } 129 | apply plugin: 'com.google.gms.google-services' 130 | 131 | ##DONATIONS 132 | 133 | This project needs you! If you would like to support this project's further development, the creator of this project or the continuous maintenance of this project, feel free to donate. Your donation is highly appreciated (and I love food, coffee and beer). Thank you! 134 | 135 | **PayPal** 136 | 137 | * **[Donate $5]**: Thank's for creating this project, here's a coffee (or some beer) for you! 138 | 139 | * **[Donate $10]**: Wow, I am stunned. Let me take you to the movies!ù 140 | 141 | * **[Donate $15]**: I really appreciate your work, let's grab some lunch! 142 | 143 | * **[Donate $25]**: That's some awesome stuff you did right there, dinner is on me! 144 | 145 | * **[Donate $50]**: I really really want to support this project, great job! 146 | 147 | * **[Donate $100]**: You are the man! This project saved me hours (if not days) of struggle and hard work, simply awesome! 148 | 149 | * **[Donate $2799]**: Go buddy, buy Macbook Pro for yourself! 150 | 151 | Of course, you can also choose what you want to donate, all donations are awesome!! 152 | 153 | 154 | #Start from 155 | 156 | minSdkVersion 14 157 | 158 | #LICENSE 159 | 160 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 161 | 162 | http://www.apache.org/licenses/LICENSE-2.0 163 | 164 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 165 | 166 | #Authors 167 | 168 | [Saveen Dhiman] original Author 169 | 170 | 171 | [Donate $5]: https://www.paypal.me/saveendhiman/5 172 | [Donate $10]: https://www.paypal.me/saveendhiman/10 173 | [Donate $15]: https://www.paypal.me/saveendhiman/15 174 | [Donate $25]: https://www.paypal.me/saveendhiman/25 175 | [Donate $50]: https://www.paypal.me/saveendhiman/50 176 | [Donate $100]: https://www.paypal.me/saveendhiman/100 177 | [Donate $2799]: https://www.paypal.me/saveendhiman/2799 178 | 179 | [Saveen Dhiman]: https://github.com/saveendhiman 180 | 181 | [Retrofit2]: https://square.github.io/retrofit 182 | [RX java]: https://github.com/ReactiveX/RxJava 183 | [Dagger2]: https://google.github.io/dagger 184 | [Firebase]: https://firebase.google.com 185 | [Calligraphy]: https://github.com/chrisjenx/Calligraphy 186 | [Picasso]: http://square.github.io/picasso 187 | [Komensky]: https://github.com/inmite/android-validation-komensky 188 | [Fabric]: https://get.fabric.io/# 189 | [Butterknife]: http://jakewharton.github.io/butterknife 190 | [Timber]: https://github.com/JakeWharton/timber 191 | 192 | [ComplexRecycler]: https://github.com/saveendhiman/ComplexRecycler 193 | 194 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | maven { url 'https://maven.fabric.io/public' } 4 | } 5 | 6 | dependencies { 7 | classpath 'io.fabric.tools:gradle:1.+' 8 | } 9 | } 10 | apply plugin: 'com.android.application' 11 | apply plugin: 'io.fabric' 12 | apply plugin: 'com.neenbedankt.android-apt' 13 | apply plugin: 'me.tatarka.retrolambda' 14 | 15 | android { 16 | compileSdkVersion rootProject.ext.compileSdkVersion 17 | buildToolsVersion rootProject.ext.buildToolsVersion 18 | 19 | //app versioning 20 | def versionMajor = 1 21 | def versionMinor = 0 22 | def versionPatch = 0 23 | def versionBuild = 0 24 | 25 | defaultConfig { 26 | applicationId "com.sampleapp" 27 | minSdkVersion rootProject.ext.minSdkVersion 28 | targetSdkVersion rootProject.ext.targetSdkVersion 29 | versionCode versionMajor * 10000 + versionMinor * 1000 + versionPatch * 100 + versionBuild 30 | versionName "${versionMajor}.${versionMinor}.${versionPatch}" 31 | } 32 | buildTypes { 33 | release { 34 | minifyEnabled false 35 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 36 | } 37 | } 38 | 39 | compileOptions { 40 | sourceCompatibility JavaVersion.VERSION_1_8 41 | targetCompatibility JavaVersion.VERSION_1_8 42 | } 43 | } 44 | 45 | repositories { 46 | maven { 47 | url "https://jitpack.io" 48 | } 49 | maven { url 'https://maven.fabric.io/public' } 50 | } 51 | 52 | dependencies { 53 | compile fileTree(include: ['*.jar'], dir: 'libs') 54 | compile "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion" 55 | compile "com.android.support:design:$rootProject.supportLibraryVersion" 56 | apt "com.google.dagger:dagger-compiler:$rootProject.daggerVersion" 57 | provided "org.glassfish:javax.annotation:$rootProject.ext.annotationVersion" 58 | compile "com.google.dagger:dagger:$rootProject.daggerVersion" 59 | compile "com.squareup.retrofit2:retrofit:$rootProject.ext.retrofitVersion" 60 | compile "com.squareup.retrofit2:converter-gson:$rootProject.ext.retrofitVersion" 61 | compile "com.squareup.retrofit2:adapter-rxjava:$rootProject.ext.retrofitVersion" 62 | compile "com.squareup.okhttp3:logging-interceptor:$rootProject.ext.loggerVersion" 63 | compile "io.reactivex:rxjava:$rootProject.ext.rxJavaVersion" 64 | compile "io.reactivex:rxandroid:$rootProject.ext.rxAndroidVersion" 65 | compile "com.jakewharton:butterknife:$rootProject.ext.butterknifeVersion" 66 | apt "com.jakewharton:butterknife-compiler:$rootProject.ext.butterknifeVersion" 67 | compile "com.jakewharton.timber:timber:$rootProject.ext.timberVersion" 68 | compile "com.google.android.gms:play-services-location:$rootProject.ext.playServiceVersion" 69 | compile "com.google.firebase:firebase-messaging:$rootProject.ext.playServiceVersion" 70 | compile "com.google.android.gms:play-services-maps:$rootProject.ext.playServiceVersion" 71 | compile "uk.co.chrisjenx:calligraphy:$rootProject.ext.calligraphyVersion" 72 | compile "com.squareup.picasso:picasso:$rootProject.ext.picassoVersion" 73 | compile "eu.inmite.android.lib:android-validation-komensky:$rootProject.ext.komenskyValidation@aar" 74 | compile "com.facebook.android:facebook-android-sdk:$rootProject.ext.facebookVersion" 75 | compile("com.crashlytics.sdk.android:crashlytics:$rootProject.ext.crashVersion@aar") { 76 | transitive = true; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "196724664631", 4 | "firebase_url": "https://sampleapp-142606.firebaseio.com", 5 | "project_id": "sampleapp-142606", 6 | "storage_bucket": "sampleapp-142606.appspot.com" 7 | }, 8 | "client": [ 9 | { 10 | "client_info": { 11 | "mobilesdk_app_id": "1:196724664631:android:bfc12da51f75173a", 12 | "android_client_info": { 13 | "package_name": "com.sampleapp" 14 | } 15 | }, 16 | "oauth_client": [ 17 | { 18 | "client_id": "196724664631-58g4d8kr1dm6jnm0le9hu5fct9sguq8p.apps.googleusercontent.com", 19 | "client_type": 3 20 | }, 21 | { 22 | "client_id": "196724664631-o8jkrt2i43j9to35l0hnmpn0el4bt5h8.apps.googleusercontent.com", 23 | "client_type": 3 24 | } 25 | ], 26 | "api_key": [ 27 | { 28 | "current_key": "AIzaSyCQGcZEBeElSApIJdZ1IMNmg8_t1qc8J64" 29 | } 30 | ], 31 | "services": { 32 | "analytics_service": { 33 | "status": 1 34 | }, 35 | "appinvite_service": { 36 | "status": 1, 37 | "other_platform_oauth_client": [] 38 | }, 39 | "ads_service": { 40 | "status": 2 41 | } 42 | } 43 | } 44 | ], 45 | "configuration_version": "1" 46 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Android\Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | #Butterknife 20 | 21 | -keep class butterknife.** { *; } 22 | -keepnames class * { @butterknife.Bind *;} 23 | 24 | -dontwarn butterknife.internal.** 25 | -keep class **$$ViewBinder { *; } 26 | 27 | -keepclasseswithmembernames class * { 28 | @butterknife.* ; 29 | } 30 | 31 | -keepclasseswithmembernames class * { 32 | @butterknife.* ; 33 | } 34 | 35 | # Retain generated class which implement ViewBinder. 36 | -keep public class * implements butterknife.internal.ViewBinder { public (); } 37 | 38 | # Prevent obfuscation of types which use ButterKnife annotations since the simple name 39 | # is used to reflectively look up the generated ViewBinder. 40 | -keep class butterknife.* 41 | -keepclasseswithmembernames class * { @butterknife.* ; } 42 | -keepclasseswithmembernames class * { @butterknife.* ; } 43 | 44 | # rxjava 45 | -keep class rx.schedulers.Schedulers { 46 | public static ; 47 | } 48 | -keep class rx.schedulers.ImmediateScheduler { 49 | public ; 50 | } 51 | -keep class rx.schedulers.TestScheduler { 52 | public ; 53 | } 54 | -keep class rx.schedulers.Schedulers { 55 | public static ** test(); 56 | } 57 | -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { 58 | long producerIndex; 59 | long consumerIndex; 60 | } 61 | -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef { 62 | long producerNode; 63 | long consumerNode; 64 | } 65 | 66 | # Support library 67 | -dontwarn android.support.** 68 | -dontwarn android.support.v4.** 69 | -keep class android.support.v4.** { *; } 70 | -keep interface android.support.v4.** { *; } 71 | -dontwarn android.support.v7.** 72 | -keep class android.support.v7.** { *; } 73 | -keep interface android.support.v7.** { *; } 74 | 75 | # support design 76 | -dontwarn android.support.design.** 77 | -keep class android.support.design.** { *; } 78 | -keep interface android.support.design.** { *; } 79 | -keep public class android.support.design.R$* { *; } 80 | 81 | 82 | # Retrofit 2.X 83 | ## https://square.github.io/retrofit/ ## 84 | 85 | -dontwarn rx.** 86 | -dontwarn retrofit2.** 87 | -keep class retrofit2.** { *; } 88 | -keepattributes Signature 89 | -keepattributes Exceptions 90 | -keepattributes *Annotation* 91 | -keep class com.squareup.okhttp.** { *; } 92 | -keep interface com.squareup.okhttp.** { *; } 93 | -dontwarn com.squareup.okhttp.** 94 | 95 | -keepclasseswithmembers class * { 96 | @retrofit2.http.* ; 97 | } 98 | 99 | -keep class sun.misc.Unsafe { *; } 100 | #your package path where your gson models are stored 101 | -keep class com.xyz.model.** { *; } 102 | 103 | # Keep these for GSON and Jackson 104 | -keepattributes Signature 105 | -keepattributes *Annotation* 106 | -keepattributes EnclosingMethod 107 | -keep class sun.misc.Unsafe { *; } 108 | -keep class com.google.gson.** { *; } 109 | 110 | ## keep komensky validation 111 | -keepattributes *Annotation* 112 | -keep class eu.inmite.android.lib.validations.form.annotations.** { *; } 113 | -keep class * implements eu.inmite.android.lib.validations.form.iface.ICondition 114 | -keep class * implements eu.inmite.android.lib.validations.form.iface.IValidator 115 | -keep class * implements eu.inmite.android.lib.validations.form.iface.IFieldAdapter 116 | -keepclassmembers class ** { 117 | @eu.inmite.android.lib.validations.form.annotations.** *; 118 | } 119 | 120 | #facebook 121 | -keep class com.facebook.** { 122 | *; 123 | } 124 | -keepattributes Signature 125 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/sampleapp/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/debug/res/values/google_maps_api.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | AIzaSyDKYb1BxAP5DxdG1f9hFVegJkKsjSf9yH4 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 43 | 44 | 47 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/api/NetModule.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.api; 2 | 3 | 4 | import com.sampleapp.constants.ApiConstants; 5 | 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import javax.inject.Singleton; 9 | 10 | import dagger.Module; 11 | import dagger.Provides; 12 | import okhttp3.OkHttpClient; 13 | import okhttp3.logging.HttpLoggingInterceptor; 14 | import retrofit2.Retrofit; 15 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 16 | import retrofit2.converter.gson.GsonConverterFactory; 17 | 18 | /** 19 | * Created by saveen_dhiman on 05-November-16. 20 | * contains object related to network communication and API consumption 21 | */ 22 | @Module 23 | public class NetModule { 24 | 25 | //get retrofit instance 26 | @Singleton 27 | @Provides 28 | public RestService getRestService() { 29 | 30 | Retrofit retrofit = new Retrofit.Builder() 31 | .baseUrl(ApiConstants.BASE_URL) 32 | .addConverterFactory(GsonConverterFactory.create()) 33 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 34 | .client(getOkHttpClient()) 35 | .build(); 36 | 37 | return retrofit.create(RestService.class); 38 | } 39 | 40 | //get OkHttp instance 41 | @Singleton 42 | @Provides 43 | public OkHttpClient getOkHttpClient() { 44 | 45 | HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); 46 | httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 47 | 48 | OkHttpClient.Builder builder = new OkHttpClient.Builder(); 49 | builder.interceptors().add(httpLoggingInterceptor); 50 | builder.readTimeout(60, TimeUnit.SECONDS); 51 | builder.connectTimeout(60, TimeUnit.SECONDS); 52 | return builder.build(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/api/RestService.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.api; 2 | 3 | import com.sampleapp.constants.ApiConstants; 4 | import com.sampleapp.model.request.LoginRequest; 5 | import com.sampleapp.model.response.LoginResponse; 6 | 7 | import retrofit2.http.Body; 8 | import retrofit2.http.POST; 9 | import rx.Observable; 10 | 11 | /** 12 | * Created by saveen_dhiman on 05-November-16. 13 | * Contains API methods to be consumed 14 | */ 15 | public interface RestService { 16 | 17 | //LOGIN API 18 | @POST(ApiConstants.LOGIN) 19 | Observable login(@Body LoginRequest loginRequest); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/base/AppComponent.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.base; 2 | 3 | import com.sampleapp.module.fragmentsample.SampleFragment; 4 | import com.sampleapp.module.fragmentsample.SamplePresenter; 5 | import com.sampleapp.utils.LocationTracker; 6 | import com.sampleapp.utils.UtilsModule; 7 | 8 | import javax.inject.Singleton; 9 | 10 | import dagger.Component; 11 | 12 | /** 13 | * Created by saveen_dhiman on 05-November-16. 14 | * Injections for Application class 15 | */ 16 | 17 | @Singleton 18 | @Component(modules = {UtilsModule.class}) 19 | public interface AppComponent { 20 | void inject(LocationTracker locationTracker); 21 | 22 | void inject(SamplePresenter samplePresenter); 23 | 24 | void inject(SampleFragment sampleFragment); 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.base; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.LayoutRes; 5 | import android.support.v7.app.AppCompatActivity; 6 | 7 | import butterknife.ButterKnife; 8 | 9 | /** 10 | * Created by saveen_dhiman on 05-November-16. 11 | * To be extended by all Activities 12 | */ 13 | public abstract class BaseActivity extends AppCompatActivity { 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(getLayout()); 19 | //bind view here for all activities extending this Activity 20 | ButterKnife.bind(this); 21 | } 22 | 23 | /** 24 | * get layout to inflate 25 | */ 26 | public abstract 27 | @LayoutRes 28 | int getLayout(); 29 | 30 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/base/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.base; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.LayoutRes; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | 11 | import butterknife.ButterKnife; 12 | import butterknife.Unbinder; 13 | 14 | /** 15 | * Created by saveen_dhiman on 05-November-16. 16 | * To be extended by all fragments 17 | */ 18 | public abstract class BaseFragment extends Fragment { 19 | 20 | Unbinder mUnbinder; 21 | public boolean hasMore = false; 22 | public int pageNumber = 1; 23 | 24 | @Nullable 25 | @Override 26 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 27 | View view = inflater.inflate(getLayoutId(), container, false); 28 | mUnbinder = ButterKnife.bind(this, view); 29 | return view; 30 | } 31 | 32 | public abstract 33 | @LayoutRes 34 | int 35 | getLayoutId(); 36 | 37 | @Override 38 | public void onDestroyView() { 39 | super.onDestroyView(); 40 | mUnbinder.unbind(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/base/SampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.base; 2 | 3 | import android.app.Application; 4 | 5 | import com.crashlytics.android.Crashlytics; 6 | import com.sampleapp.BuildConfig; 7 | import com.sampleapp.utils.UtilsModule; 8 | 9 | import io.fabric.sdk.android.Fabric; 10 | import timber.log.Timber; 11 | 12 | 13 | /** 14 | * Created by saveen_dhiman on 05-November-16. 15 | * Initialization of required libraries 16 | */ 17 | public class SampleApplication extends Application { 18 | 19 | private AppComponent mAppComponent; 20 | 21 | @Override 22 | public void onCreate() { 23 | super.onCreate(); 24 | Fabric.with(this, new Crashlytics()); 25 | 26 | //create component 27 | mAppComponent = DaggerAppComponent.builder() 28 | .utilsModule(new UtilsModule(this)).build(); 29 | 30 | //configure timber for logging 31 | if (BuildConfig.DEBUG) { 32 | Timber.plant(new Timber.DebugTree()); 33 | } 34 | } 35 | 36 | public AppComponent getAppComponent() { 37 | return mAppComponent; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/constants/ApiConstants.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.constants; 2 | 3 | /** 4 | * Created by saveen_dhiman on 05-November-16. 5 | * contains all the constants related to API's 6 | */ 7 | public interface ApiConstants { 8 | int STATUS_SUCCESS = 200; 9 | String STATUS_SESSION_EXPIRE = "203"; 10 | String BASE_URL = "http://abc.com/"; 11 | String CONTROLLER = "/index.php/webController"; 12 | String LOGIN = CONTROLLER + "/apilogin"; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/constants/PrefernceConstants.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.constants; 2 | 3 | /** 4 | * Created by saveen_dhiman on 05-November-16. 5 | * Contains all the keys used in SharedPrefernce of application 6 | */ 7 | public interface PrefernceConstants { 8 | String PREFERENCE_NAME = "SAMPLE_APP_PREFERENCES"; 9 | String USER_DATA = "user_data"; 10 | String IS_LOGIN = "isLogin"; 11 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/constants/ValueConstants.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.constants; 2 | 3 | import android.support.annotation.IntDef; 4 | 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | 8 | /** 9 | * Created by saveen_dhiman on 05-November-16. 10 | * contains constant values used in application 11 | */ 12 | public interface ValueConstants { 13 | 14 | String LOCATION_PERMISSION = android.Manifest.permission.ACCESS_FINE_LOCATION; 15 | int REQUEST_CAMERA = 1001; 16 | int REQUEST_Gallery = 1002; 17 | int REQUEST_LOCATION = 1003; 18 | String DEVICE_TYPE = "android"; 19 | String NEW_THREAD = "newThread"; 20 | String MAIN_THREAD = "mainThread"; 21 | String DATE_INPUT_FORMAT = "yyyy-MM-dd HH:mm:ss"; 22 | String DATE_OUTPUT_FORMAT = "EEEE, h:mm a"; 23 | 24 | // type check for error during login 25 | @IntDef({ValidationType.VALID, ValidationType.USER_NAME_INVALID, ValidationType.PASSWORD_INVALID}) 26 | @Retention(RetentionPolicy.SOURCE) 27 | @interface ValidationType { 28 | int VALID = 0, USER_NAME_INVALID = 1, PASSWORD_INVALID = 2; 29 | } 30 | 31 | // type of dialog opened in MainActivity 32 | @IntDef({DialogType.DIALOG_DENY, DialogType.DIALOG_NEVER_ASK}) 33 | @Retention(RetentionPolicy.SOURCE) 34 | @interface DialogType { 35 | int DIALOG_DENY = 0, DIALOG_NEVER_ASK = 1; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/interfaces/LocationUpdateListener.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.interfaces; 2 | 3 | import android.location.Location; 4 | 5 | 6 | /** 7 | * Created by saveen_dhiman on 05-November-16. 8 | * 9 | * An interface to receive high-level updates on where your location is. 10 | * @author aalcock 11 | * 12 | */ 13 | public interface LocationUpdateListener { 14 | 15 | /** 16 | * Called immediately the service starts if the service can obtain location 17 | */ 18 | void canReceiveLocationUpdates(); 19 | 20 | /** 21 | * Called immediately the service tries to start if it cannot obtain location - eg the user has disabled wireless and 22 | */ 23 | void cannotReceiveLocationUpdates(); 24 | 25 | /** 26 | * Called whenever the location has changed (at least non-trivially) 27 | * @param location 28 | */ 29 | void updateLocation(Location location); 30 | 31 | /** 32 | * Called when GoogleLocationServices detects that the device has moved to a new location. 33 | * @param localityName The name of the locality (somewhere below street but above area). 34 | */ 35 | void updateLocationName(String localityName, Location location); 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/interfaces/OnDialogButtonClickListener.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.interfaces; 2 | 3 | /** 4 | * Created by saveen_dhiman on 05-November-16. 5 | *

6 | * Send click events to the class implementing this interface 7 | */ 8 | public interface OnDialogButtonClickListener { 9 | 10 | void onPositiveButtonClicked(); 11 | 12 | void onNegativeButtonClicked(); 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/model/UserData.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.model; 2 | 3 | /** 4 | * Created by saveen_dhiman on 05-November-16. 5 | * Pojo class for user data 6 | */ 7 | public class UserData { 8 | 9 | /** 10 | * code : 200 11 | * message : Success 12 | */ 13 | 14 | private StatusBean status; 15 | /** 16 | * auth : {"id":"2746","handle":"saveendhiman","email":"saveendhiman@gmail.com","firstname":"saveen","middlename":"0","lastname":"dhiman"} 17 | */ 18 | 19 | private ResponseBean response; 20 | 21 | public StatusBean getStatus() { 22 | return status; 23 | } 24 | 25 | public void setStatus(StatusBean status) { 26 | this.status = status; 27 | } 28 | 29 | public ResponseBean getResponse() { 30 | return response; 31 | } 32 | 33 | public void setResponse(ResponseBean response) { 34 | this.response = response; 35 | } 36 | 37 | public static class StatusBean { 38 | private String code; 39 | private String message; 40 | 41 | public String getCode() { 42 | return code; 43 | } 44 | 45 | public void setCode(String code) { 46 | this.code = code; 47 | } 48 | 49 | public String getMessage() { 50 | return message; 51 | } 52 | 53 | public void setMessage(String message) { 54 | this.message = message; 55 | } 56 | } 57 | 58 | public static class ResponseBean { 59 | /** 60 | * id : 2746 61 | * handle : saveendhiman 62 | * email : saveendhiman@gmail.com 63 | * firstname : saveen 64 | * middlename : 0 65 | * lastname : dhiman 66 | */ 67 | 68 | private AuthBean auth; 69 | 70 | public AuthBean getAuth() { 71 | return auth; 72 | } 73 | 74 | public void setAuth(AuthBean auth) { 75 | this.auth = auth; 76 | } 77 | 78 | public static class AuthBean { 79 | private String id; 80 | private String handle; 81 | private String email; 82 | private String firstname; 83 | private String middlename; 84 | private String lastname; 85 | private String session_id; 86 | 87 | public String getSession_id() { 88 | return session_id; 89 | } 90 | 91 | public void setSession_id(String session_id) { 92 | this.session_id = session_id; 93 | } 94 | 95 | public String getId() { 96 | return id; 97 | } 98 | 99 | public void setId(String id) { 100 | this.id = id; 101 | } 102 | 103 | public String getHandle() { 104 | return handle; 105 | } 106 | 107 | public void setHandle(String handle) { 108 | this.handle = handle; 109 | } 110 | 111 | public String getEmail() { 112 | return email; 113 | } 114 | 115 | public void setEmail(String email) { 116 | this.email = email; 117 | } 118 | 119 | public String getFirstname() { 120 | return firstname; 121 | } 122 | 123 | public void setFirstname(String firstname) { 124 | this.firstname = firstname; 125 | } 126 | 127 | public String getMiddlename() { 128 | return middlename; 129 | } 130 | 131 | public void setMiddlename(String middlename) { 132 | this.middlename = middlename; 133 | } 134 | 135 | public String getLastname() { 136 | return lastname; 137 | } 138 | 139 | public void setLastname(String lastname) { 140 | this.lastname = lastname; 141 | } 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/model/request/LoginRequest.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.model.request; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | /** 6 | * Created by saveen_dhiman on 05-November-16. 7 | * type of data to be sent in LoginApi 8 | */ 9 | public class LoginRequest { 10 | 11 | String username; 12 | String password; 13 | String platform; 14 | String deviceid; 15 | 16 | public LoginRequest(@NonNull String username, @NonNull String password, 17 | @NonNull String platform, @NonNull String deviceid) { 18 | this.username = username; 19 | this.password = password; 20 | this.platform = platform; 21 | this.deviceid = deviceid; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/model/response/LoginResponse.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.model.response; 2 | 3 | /** 4 | * Created by saveen_dhiman on 05-November-16. 5 | * response model for login api 6 | */ 7 | public class LoginResponse { 8 | /** 9 | * result : 1 10 | * resultText : Success 11 | * errorMSG : Success. 12 | * user_id : 20 13 | * phone : 1234567890 14 | * first_name : saveen 15 | * last_name : null 16 | * email : saveendhiman@gmail.com 17 | * role : 1 18 | * avatar : 19 | */ 20 | 21 | private ResponseBean Response; 22 | 23 | public ResponseBean getResponse() { 24 | return Response; 25 | } 26 | 27 | public void setResponse(ResponseBean Response) { 28 | this.Response = Response; 29 | } 30 | 31 | public static class ResponseBean { 32 | private int result; 33 | private String resultText; 34 | private String errorMSG; 35 | private int user_id; 36 | private String phone; 37 | private String first_name; 38 | private Object last_name; 39 | private String email; 40 | private int role; 41 | private String avatar; 42 | 43 | public int getResult() { 44 | return result; 45 | } 46 | 47 | public void setResult(int result) { 48 | this.result = result; 49 | } 50 | 51 | public String getResultText() { 52 | return resultText; 53 | } 54 | 55 | public void setResultText(String resultText) { 56 | this.resultText = resultText; 57 | } 58 | 59 | public String getErrorMSG() { 60 | return errorMSG; 61 | } 62 | 63 | public void setErrorMSG(String errorMSG) { 64 | this.errorMSG = errorMSG; 65 | } 66 | 67 | public int getUser_id() { 68 | return user_id; 69 | } 70 | 71 | public void setUser_id(int user_id) { 72 | this.user_id = user_id; 73 | } 74 | 75 | public String getPhone() { 76 | return phone; 77 | } 78 | 79 | public void setPhone(String phone) { 80 | this.phone = phone; 81 | } 82 | 83 | public String getFirst_name() { 84 | return first_name; 85 | } 86 | 87 | public void setFirst_name(String first_name) { 88 | this.first_name = first_name; 89 | } 90 | 91 | public Object getLast_name() { 92 | return last_name; 93 | } 94 | 95 | public void setLast_name(Object last_name) { 96 | this.last_name = last_name; 97 | } 98 | 99 | public String getEmail() { 100 | return email; 101 | } 102 | 103 | public void setEmail(String email) { 104 | this.email = email; 105 | } 106 | 107 | public int getRole() { 108 | return role; 109 | } 110 | 111 | public void setRole(int role) { 112 | this.role = role; 113 | } 114 | 115 | public String getAvatar() { 116 | return avatar; 117 | } 118 | 119 | public void setAvatar(String avatar) { 120 | this.avatar = avatar; 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/module/SplashActivity.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.module; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | 6 | import com.sampleapp.R; 7 | import com.sampleapp.module.login.LoginActivity; 8 | 9 | import java.util.concurrent.TimeUnit; 10 | 11 | import rx.Observable; 12 | import rx.Subscription; 13 | 14 | /** 15 | * Created by saveen_dhiman on 05-November-16. 16 | * initial screen for application to present app logo to users 17 | */ 18 | 19 | public class SplashActivity extends AppCompatActivity { 20 | 21 | private Subscription mSubscriber; 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.activity_splash); 27 | 28 | //start next activity after delay of 2 seconds 29 | mSubscriber = Observable.timer(2, TimeUnit.SECONDS).subscribe(aLong -> { 30 | startActivity(LoginActivity.createIntent(SplashActivity.this)); 31 | finish(); 32 | }); 33 | } 34 | 35 | @Override 36 | protected void onDestroy() { 37 | super.onDestroy(); 38 | mSubscriber.unsubscribe(); 39 | } 40 | 41 | @Override 42 | public void onBackPressed() { 43 | // super.onBackPressed(); 44 | } 45 | 46 | @Override 47 | protected void onPause() { 48 | super.onPause(); 49 | finish(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/module/fragmentsample/SampleFragment.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.module.fragmentsample; 2 | 3 | import android.graphics.Typeface; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.widget.SwipeRefreshLayout; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.View; 10 | import android.widget.TextView; 11 | 12 | import com.sampleapp.R; 13 | import com.sampleapp.base.BaseFragment; 14 | import com.sampleapp.base.SampleApplication; 15 | import com.sampleapp.utils.AppUtils; 16 | import com.sampleapp.utils.ProgressBarHandler; 17 | 18 | import javax.inject.Inject; 19 | 20 | import butterknife.BindView; 21 | 22 | /** 23 | * Created by saveen_dhiman on 05-August-17. 24 | * SHow user last login time and uploaded forms 25 | */ 26 | public class SampleFragment extends BaseFragment implements SampleView { 27 | 28 | // @BindView(R.id.txtUserName) 29 | // TextView mTxtUserName; 30 | 31 | LinearLayoutManager mLinearLayoutManager; 32 | @Inject 33 | ProgressBarHandler mProgressBarHandler; 34 | @Inject 35 | AppUtils mAppUtils; 36 | @Inject 37 | SamplePresenter mPresenter; 38 | 39 | 40 | @Override 41 | public int getLayoutId() { 42 | return R.layout.fragment_sample; 43 | } 44 | 45 | @Override 46 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 47 | super.onViewCreated(view, savedInstanceState); 48 | ((SampleApplication) getActivity().getApplication()).getAppComponent().inject(this); 49 | mPresenter.attachView(this); 50 | mPresenter.injectDependency(getActivity()); 51 | init(); 52 | } 53 | 54 | //noting much just initial work and API call 55 | private void init() { 56 | 57 | 58 | } 59 | 60 | 61 | @Override 62 | public void showProgress() { 63 | 64 | mProgressBarHandler.showProgress(); 65 | } 66 | 67 | @Override 68 | public void hideProgress() { 69 | mProgressBarHandler.hideProgress(); 70 | 71 | } 72 | 73 | @Override 74 | public void onError(Throwable throwable) { 75 | throwable.printStackTrace(); 76 | // mAppUtils.showSnackBar(mRecyclerForms, mAppUtils.getErrorMessage(throwable)); 77 | } 78 | 79 | @Override 80 | public void onException(String message) { 81 | // mAppUtils.showSnackBar(mRecyclerForms, message); 82 | } 83 | 84 | @Override 85 | public void onDestroyView() { 86 | super.onDestroyView(); 87 | mPresenter.detachView(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/module/fragmentsample/SamplePresenter.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.module.fragmentsample; 2 | 3 | import android.app.Activity; 4 | 5 | import com.sampleapp.api.RestService; 6 | import com.sampleapp.base.SampleApplication; 7 | import com.sampleapp.constants.ValueConstants; 8 | import com.sampleapp.mvpbase.BasePresenter; 9 | import com.sampleapp.utils.AppUtils; 10 | import com.sampleapp.utils.PreferenceManager; 11 | 12 | import javax.inject.Inject; 13 | import javax.inject.Named; 14 | 15 | import rx.Scheduler; 16 | 17 | /** 18 | * Created by saveen_dhiman on 05-August-17. 19 | * presenter class for {@link SampleFragment} 20 | */ 21 | public class SamplePresenter extends BasePresenter { 22 | 23 | @Inject 24 | PreferenceManager mPrefs; 25 | @Inject 26 | @Named(ValueConstants.MAIN_THREAD) 27 | Scheduler mMainThread; 28 | @Inject 29 | @Named(ValueConstants.NEW_THREAD) 30 | Scheduler mNewThread; 31 | @Inject 32 | AppUtils mAppUtils; 33 | 34 | @Inject 35 | RestService mRestService; 36 | 37 | @Inject 38 | public SamplePresenter() { 39 | } 40 | 41 | //inject dependency for presenter 42 | void injectDependency(Activity activity) { 43 | ((SampleApplication) activity.getApplication()).getAppComponent().inject(this); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/module/fragmentsample/SampleView.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.module.fragmentsample; 2 | 3 | 4 | import com.sampleapp.mvpbase.MvpView; 5 | 6 | /** 7 | * Created by saveen_dhiman on 05-August-17. 8 | * to be implemented by {@link SampleFragment} 9 | */ 10 | public interface SampleView extends MvpView { 11 | 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/module/login/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.module.login; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | 7 | import com.sampleapp.R; 8 | import com.sampleapp.base.BaseActivity; 9 | import com.sampleapp.utils.AppUtils; 10 | import com.sampleapp.utils.ProgressBarHandler; 11 | import com.sampleapp.utils.UtilsModule; 12 | import com.sampleapp.views.RemoveErrorEditText; 13 | 14 | import javax.inject.Inject; 15 | 16 | import butterknife.BindView; 17 | import butterknife.OnClick; 18 | import eu.inmite.android.lib.validations.form.FormValidator; 19 | import eu.inmite.android.lib.validations.form.annotations.MinLength; 20 | import eu.inmite.android.lib.validations.form.annotations.NotEmpty; 21 | import eu.inmite.android.lib.validations.form.callback.SimpleErrorPopupCallback; 22 | 23 | /** 24 | * Created by saveen_dhiman on 05-November-16. 25 | * contains login related view and data presentation 26 | */ 27 | 28 | public class LoginActivity extends BaseActivity implements LoginView { 29 | 30 | @Inject 31 | ProgressBarHandler mProgressHandler; 32 | @Inject 33 | LoginPresenter mLoginPresenter; 34 | @Inject 35 | AppUtils mAppUtils; 36 | 37 | @NotEmpty(messageId = R.string.warning_field_empty, order = 1) 38 | @BindView(R.id.edtUserName) 39 | RemoveErrorEditText mEdtUserName; 40 | 41 | @MinLength(value = 6, messageId = R.string.warning_password_length, order = 2) 42 | @BindView(R.id.edtPassword) 43 | RemoveErrorEditText mEdtPassword; 44 | 45 | @Override 46 | protected void onCreate(Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | 49 | //create component 50 | DaggerLoginComponent.builder() 51 | .utilsModule(new UtilsModule(this)) 52 | .loginModule(new LoginModule(this)) 53 | .build().inject(this); 54 | 55 | mLoginPresenter.attachView(this); 56 | } 57 | 58 | //set layout for this activity 59 | @Override 60 | public int getLayout() { 61 | return R.layout.activity_login; 62 | } 63 | 64 | //return intent for this activity 65 | public static Intent createIntent(Context context) { 66 | return new Intent(context, LoginActivity.class); 67 | } 68 | 69 | @Override 70 | public void onLoginSuccess() { 71 | 72 | } 73 | 74 | @Override 75 | public void closeApplication() { 76 | 77 | } 78 | 79 | @Override 80 | public void showProgress() { 81 | mProgressHandler.showProgress(); 82 | } 83 | 84 | @Override 85 | public void hideProgress() { 86 | mProgressHandler.hideProgress(); 87 | } 88 | 89 | @Override 90 | public void onError(Throwable t) { 91 | t.printStackTrace(); 92 | mAppUtils.showSnackBar(mEdtPassword, t.getLocalizedMessage()); 93 | } 94 | 95 | @Override 96 | public void onException(String message) { 97 | mAppUtils.showSnackBar(mEdtPassword, message); 98 | } 99 | 100 | //click event on views 101 | @OnClick({R.id.txtLogin}) 102 | public void onClick() { 103 | boolean isValid = FormValidator.validate(LoginActivity.this, new SimpleErrorPopupCallback(LoginActivity.this)); 104 | if (isValid) { 105 | mLoginPresenter.loginUser(mEdtUserName.getText().toString(), mEdtPassword.getText().toString()); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/module/login/LoginComponent.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.module.login; 2 | 3 | import com.sampleapp.utils.UtilsModule; 4 | 5 | import javax.inject.Singleton; 6 | 7 | import dagger.Component; 8 | 9 | /** 10 | * Created by saveen_dhiman on 05-November-16. 11 | * Component class for login activity 12 | */ 13 | @Singleton 14 | @Component(modules = {LoginModule.class, UtilsModule.class}) 15 | public interface LoginComponent { 16 | void inject(LoginActivity loginActivity); 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/module/login/LoginModule.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.module.login; 2 | 3 | import android.content.Context; 4 | 5 | import dagger.Module; 6 | import dagger.Provides; 7 | 8 | /** 9 | * Created by saveen_dhiman on 05-November-16. 10 | * provides dependencies for LoginActivity 11 | */ 12 | @Module 13 | public class LoginModule { 14 | 15 | private Context mContext; 16 | 17 | public LoginModule(Context mContext) { 18 | this.mContext = mContext; 19 | } 20 | 21 | //returns LoginPresenter object 22 | @Provides 23 | LoginPresenter getPresenter() { 24 | return new LoginPresenter(mContext); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/module/login/LoginPresenter.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.module.login; 2 | 3 | import android.content.Context; 4 | 5 | import com.google.firebase.iid.FirebaseInstanceId; 6 | import com.google.gson.Gson; 7 | import com.sampleapp.api.NetModule; 8 | import com.sampleapp.api.RestService; 9 | import com.sampleapp.constants.ApiConstants; 10 | import com.sampleapp.constants.ValueConstants; 11 | import com.sampleapp.model.request.LoginRequest; 12 | import com.sampleapp.model.response.LoginResponse; 13 | import com.sampleapp.mvpbase.BasePresenter; 14 | import com.sampleapp.utils.AppUtils; 15 | import com.sampleapp.utils.PreferenceManager; 16 | import com.sampleapp.utils.UtilsModule; 17 | 18 | import javax.inject.Inject; 19 | import javax.inject.Named; 20 | 21 | import rx.Scheduler; 22 | 23 | /** 24 | * Created by saveen_dhiman on 05-November-16. 25 | * Presenter class for LoginActivity 26 | * Contains all the business logic for main activity 27 | */ 28 | public class LoginPresenter extends BasePresenter { 29 | 30 | @Inject 31 | @Named(ValueConstants.MAIN_THREAD) 32 | Scheduler mMainThread; 33 | 34 | @Inject 35 | @Named(ValueConstants.NEW_THREAD) 36 | Scheduler mNewThread; 37 | 38 | @Inject 39 | RestService mRestService; 40 | 41 | @Inject 42 | PreferenceManager mprefs; 43 | 44 | @Inject 45 | AppUtils mUtils; 46 | 47 | public LoginPresenter(Context context) { 48 | //create component 49 | DaggerLoginPresenterComponent.builder() 50 | .netModule(new NetModule()) 51 | .utilsModule(new UtilsModule(context)).build().inject(this); 52 | } 53 | 54 | //login user api method 55 | public void loginUser(String userName, String password) { 56 | 57 | getMvpView().showProgress(); 58 | 59 | LoginRequest request = new LoginRequest(userName, password, 60 | ValueConstants.DEVICE_TYPE, FirebaseInstanceId.getInstance().getToken()); 61 | 62 | mRestService.login(request). 63 | subscribeOn(mNewThread). 64 | observeOn(mMainThread). 65 | subscribe(loginResponse -> { 66 | if (isViewAttached()) { 67 | getMvpView().hideProgress(); 68 | if (loginResponse.getResponse().getResult() == ApiConstants.STATUS_SUCCESS) { 69 | mprefs.setUserLoggedIn(true); 70 | LoginResponse.ResponseBean response = loginResponse.getResponse(); 71 | // response.setAvatar(loginResponse.getResponse().getDp_path() + loginResponse.getResponse().getAvatar()); 72 | mprefs.setUserData(new Gson().toJson(response)); 73 | getMvpView().onLoginSuccess(); 74 | } else { 75 | getMvpView().onException(loginResponse.getResponse().getErrorMSG()); 76 | } 77 | } 78 | }, throwable -> { 79 | if (isViewAttached()) { 80 | getMvpView().hideProgress(); 81 | getMvpView().onError(throwable); 82 | } 83 | }); 84 | 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/module/login/LoginPresenterComponent.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.module.login; 2 | 3 | import com.sampleapp.api.NetModule; 4 | import com.sampleapp.utils.UtilsModule; 5 | 6 | import javax.inject.Singleton; 7 | 8 | import dagger.Component; 9 | 10 | /** 11 | * Created by saveen_dhiman on 05-November-16. 12 | * Component class for login activity 13 | */ 14 | @Singleton 15 | @Component(modules = {NetModule.class, UtilsModule.class}) 16 | public interface LoginPresenterComponent { 17 | void inject(LoginPresenter loginPresenter); 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/module/login/LoginView.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.module.login; 2 | 3 | import com.sampleapp.mvpbase.MvpView; 4 | 5 | /** 6 | * Created by saveen_dhiman on 05-November-16. 7 | * contains methods to perform action via presenter 8 | */ 9 | public interface LoginView extends MvpView { 10 | 11 | void onLoginSuccess(); 12 | 13 | void closeApplication(); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/module/register/RegisterActivity.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.module.register; 2 | 3 | import android.os.Bundle; 4 | 5 | import com.sampleapp.R; 6 | import com.sampleapp.base.BaseActivity; 7 | 8 | /** 9 | * Created by saveen_dhiman on 05-November-16. 10 | * contains register related view and data presentation 11 | */ 12 | public class RegisterActivity extends BaseActivity implements RegisterMvpView{ 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | } 18 | 19 | @Override 20 | public int getLayout() { 21 | return R.layout.activity_register; 22 | } 23 | 24 | @Override 25 | public void OnSuccess() { 26 | 27 | } 28 | 29 | @Override 30 | public void showProgress() { 31 | 32 | } 33 | 34 | @Override 35 | public void hideProgress() { 36 | 37 | } 38 | 39 | @Override 40 | public void onError(Throwable t) { 41 | 42 | } 43 | 44 | @Override 45 | public void onException(String message) { 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/module/register/RegisterMvpView.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.module.register; 2 | 3 | import com.sampleapp.mvpbase.MvpView; 4 | 5 | /** 6 | * Created by saveen_dhiman on 05-November-16. 7 | * contains methods to perform action via presenter 8 | */ 9 | public interface RegisterMvpView extends MvpView { 10 | 11 | void OnSuccess(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/module/register/RegisterPresenter.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.module.register; 2 | 3 | import com.sampleapp.mvpbase.BasePresenter; 4 | 5 | /** 6 | * Created by saveen_dhiman on 05-November-16. 7 | * Presenter class for LoginActivity 8 | * Contains all the business logic for main activity 9 | */ 10 | public class RegisterPresenter extends BasePresenter { 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/mvpbase/BasePresenter.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.mvpbase; 2 | 3 | /** 4 | * Created by saveen_dhiman on 05-November-16. 5 | *

6 | * Base class that implements the Presenter interface and provides a base implementation for 7 | * attachView() and detachView(). It also handles keeping a reference to the mvpView that 8 | * can be accessed from the children classes by calling getMvpView(). 9 | */ 10 | public class BasePresenter implements Presenter { 11 | 12 | private T mMvpView; 13 | 14 | @Override 15 | public void attachView(T mvpView) { 16 | mMvpView = mvpView; 17 | } 18 | 19 | @Override 20 | public void detachView() { 21 | mMvpView = null; 22 | } 23 | 24 | public boolean isViewAttached() { 25 | return mMvpView != null; 26 | } 27 | 28 | public T getMvpView() { 29 | return mMvpView; 30 | } 31 | 32 | public void checkViewAttached() { 33 | if (!isViewAttached()) throw new MvpViewNotAttachedException(); 34 | } 35 | 36 | public static class MvpViewNotAttachedException extends RuntimeException { 37 | public MvpViewNotAttachedException() { 38 | super("Please call Presenter.attachView(MvpView) before" + 39 | " requesting data to the Presenter"); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/mvpbase/MvpView.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.mvpbase; 2 | 3 | /** 4 | * Created by saveen_dhiman on 05-November-16. 5 | *

6 | * Base interface that any class that wants to act as a View in the MVP (Model View Presenter) 7 | * pattern must implement. Generally this interface will be extended by a more specific interface 8 | * that then usually will be implemented by an Activity or Fragment. 9 | */ 10 | public interface MvpView { 11 | 12 | void showProgress(); 13 | 14 | void hideProgress(); 15 | 16 | void onError(Throwable t); 17 | 18 | void onException(String message); 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/mvpbase/Presenter.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.mvpbase; 2 | 3 | /** 4 | * Created by saveen_dhiman on 05-November-16. 5 | * Every presenter in the app must either implement this interface or extend BasePresenter 6 | * indicating the MvpView type that wants to be attached with. 7 | */ 8 | public interface Presenter { 9 | 10 | void attachView(V mvpView); 11 | 12 | void detachView(); 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/notification/PushMessagingService.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.notification; 2 | 3 | import com.google.firebase.messaging.FirebaseMessagingService; 4 | import com.google.firebase.messaging.RemoteMessage; 5 | 6 | import timber.log.Timber; 7 | 8 | /** 9 | * Created by saveen_dhiman on 05-November-16. 10 | * To display push notifications to user 11 | */ 12 | public class PushMessagingService extends FirebaseMessagingService { 13 | private static final String TAG = "MY_RITE_SERVICE"; 14 | 15 | @Override 16 | public void onMessageReceived(RemoteMessage remoteMessage) { 17 | // Handle data payload of FCM messages. 18 | Timber.e(TAG, "FCM Data Message: " + remoteMessage.getData()); 19 | } 20 | 21 | /** 22 | * Create and show a simple notification containing the received FCM message. 23 | * 24 | * @param messageBody FCM message body received. 25 | */ 26 | private void sendNotification(RemoteMessage messageBody) { 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/notification/SampleAppFirebaseInstanceIDService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of 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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.sampleapp.notification; 18 | 19 | import com.google.firebase.iid.FirebaseInstanceId; 20 | import com.google.firebase.iid.FirebaseInstanceIdService; 21 | 22 | import timber.log.Timber; 23 | 24 | /** 25 | * Created by saveen_dhiman on 05-November-16. 26 | * To get device token from firebase server for the purpose of push notifications 27 | */ 28 | 29 | public class SampleAppFirebaseInstanceIDService extends FirebaseInstanceIdService { 30 | 31 | /** 32 | * Called if InstanceID token is updated. This may occur if the security of 33 | * the previous token had been compromised. Note that this is called when the InstanceID token 34 | * is initially generated so this is where you would retrieve the token. 35 | */ 36 | // [START refresh_token] 37 | @Override 38 | public void onTokenRefresh() { 39 | // Get updated InstanceID token. 40 | String refreshedToken = FirebaseInstanceId.getInstance().getToken(); 41 | Timber.e("Refreshed token: " + refreshedToken); 42 | } 43 | // [END refresh_token] 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/utils/AppUtils.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.utils; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.location.LocationManager; 7 | import android.net.ConnectivityManager; 8 | import android.net.NetworkInfo; 9 | import android.net.Uri; 10 | import android.provider.Settings; 11 | import android.view.View; 12 | import android.view.inputmethod.InputMethodManager; 13 | import android.widget.Toast; 14 | 15 | import com.google.android.gms.common.ConnectionResult; 16 | import com.google.android.gms.common.GoogleApiAvailability; 17 | import com.sampleapp.R; 18 | 19 | /** 20 | * Created by saveen_dhiman on 05-November-16. 21 | *

22 | * Contains commonly used methods in an Android App 23 | */ 24 | public class AppUtils { 25 | 26 | private Context mContext; 27 | 28 | public AppUtils(Context context) { 29 | this.mContext = context; 30 | } 31 | 32 | /** 33 | * Description : Check if user is online or not 34 | * 35 | * @return true if online else false 36 | */ 37 | public boolean isOnline(View v) { 38 | ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 39 | NetworkInfo netInfo = cm.getActiveNetworkInfo(); 40 | if (netInfo != null && netInfo.isConnectedOrConnecting()) { 41 | return true; 42 | } 43 | showSnackBar(v, mContext.getString(R.string.toast_network_not_available)); 44 | return false; 45 | } 46 | 47 | 48 | /** 49 | * Description : Hide the soft keyboard 50 | * 51 | * @param view : Pass the current view 52 | */ 53 | public void hideSoftKeyboard(View view) { 54 | InputMethodManager inputMethodManager = (InputMethodManager) mContext.getSystemService(Activity.INPUT_METHOD_SERVICE); 55 | inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); 56 | } 57 | 58 | /** 59 | * Show snackbar 60 | * 61 | * @param view view clicked 62 | * @param text text to be displayed on snackbar 63 | */ 64 | public void showSnackBar(View view, String text) { 65 | // Snackbar.make(view, text, Snackbar.LENGTH_SHORT).show(); 66 | } 67 | 68 | /** 69 | * Show snackbar 70 | * 71 | * @param text text to be displayed on Toast 72 | */ 73 | public void showToast(String text) { 74 | Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show(); 75 | } 76 | 77 | /** 78 | * send email via. intent 79 | * 80 | * @param email to whom you want to send email 81 | */ 82 | public void sendEmail(Context context, String email) { 83 | Intent i = new Intent(Intent.ACTION_SEND); 84 | i.setType("message/rfc822"); 85 | i.putExtra(Intent.EXTRA_EMAIL, email); 86 | try { 87 | context.startActivity(Intent.createChooser(i, context.getResources().getString(R.string.send_mail))); 88 | } catch (android.content.ActivityNotFoundException ex) { 89 | Toast.makeText(context, context.getResources().getString(R.string.no_email_client), Toast.LENGTH_SHORT).show(); 90 | } 91 | } 92 | 93 | /** 94 | * To open a website in phone browser 95 | * 96 | * @param address valid email link 97 | */ 98 | public void openBrowser(String address) { 99 | try { 100 | if (!address.startsWith("http://") && !address.startsWith("https://")) { 101 | address = "http://" + address; 102 | } 103 | Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(address)); 104 | mContext.startActivity(browserIntent); 105 | } catch (Exception e) { 106 | showToast(mContext.getResources().getString(R.string.warning_invalid_link)); 107 | } 108 | } 109 | 110 | /** 111 | * Check the device to make sure it has the Google Play Services APK. If 112 | * it doesn't, display a dialog that allows users to download the APK from 113 | * the Google Play Store or enable it in the device's system settings. 114 | */ 115 | public boolean checkPlayServices() { 116 | GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance(); 117 | int resultCode = apiAvailability.isGooglePlayServicesAvailable(mContext); 118 | if (resultCode != ConnectionResult.SUCCESS) { 119 | if (apiAvailability.isUserResolvableError(resultCode)) { 120 | apiAvailability.getErrorDialog((Activity) mContext, resultCode, 9000) 121 | .show(); 122 | } else { 123 | showToast(mContext.getResources().getString(R.string.warning_play_services)); 124 | } 125 | return false; 126 | } 127 | return true; 128 | } 129 | 130 | /** 131 | * redirect user to your application settings in device 132 | */ 133 | public void redirectToAppSettings() { 134 | Intent intent = new Intent(); 135 | intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 136 | Uri uri = Uri.fromParts("package", mContext.getPackageName(), null); 137 | intent.setData(uri); 138 | mContext.startActivity(intent); 139 | } 140 | 141 | /** 142 | * check if user has enabled Gps of device 143 | * 144 | * @return true or false depending upon device Gps status 145 | */ 146 | public boolean isGpsEnabled() { 147 | final LocationManager manager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); 148 | return manager.isProviderEnabled(LocationManager.GPS_PROVIDER); 149 | } 150 | 151 | /** 152 | * Redirect user to enable GPS 153 | */ 154 | public void goToGpsSettings() { 155 | Intent callGPSSettingIntent = new Intent( 156 | Settings.ACTION_LOCATION_SOURCE_SETTINGS); 157 | mContext.startActivity(callGPSSettingIntent); 158 | } 159 | 160 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/utils/DateTimeUtils.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.utils; 2 | 3 | import android.annotation.SuppressLint; 4 | 5 | import java.text.DateFormat; 6 | import java.text.ParseException; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | import java.util.Locale; 10 | import java.util.TimeZone; 11 | 12 | /** 13 | * Created by saveen_dhiman on 05-November-16. 14 | * contains commonly used methods related to date & time conversion 15 | */ 16 | public class DateTimeUtils { 17 | /** 18 | * get date form timestamp 19 | * 20 | * @param timestamp time to be converter 21 | * @return date in string 22 | */ 23 | 24 | public String getDateFromTimestamp(String timestamp) { 25 | 26 | long time = Long.parseLong(timestamp) * 1000; 27 | try { 28 | DateFormat sdf = new SimpleDateFormat("dd MMMM yyyy", Locale.getDefault()); 29 | Date netDate = (new Date(time)); 30 | return sdf.format(netDate); 31 | } catch (Exception ex) { 32 | return "xx xxxx xxxx"; 33 | } 34 | } 35 | 36 | /** 37 | * To convert a date to timestamp 38 | * 39 | * @param dateToConvert date to be converted 40 | * @param dateFormat format of date entered 41 | * @return timestamp in milliseconds 42 | */ 43 | 44 | public long convertDateToTimeStamp(String dateToConvert, String dateFormat) { 45 | DateFormat formatter = new SimpleDateFormat(dateFormat, Locale.getDefault()); 46 | Date date = null; 47 | try { 48 | date = formatter.parse(dateToConvert); 49 | } catch (ParseException e) { 50 | e.printStackTrace(); 51 | } 52 | return date.getTime(); 53 | } 54 | 55 | /** 56 | * Get current timestamp in seconds 57 | * 58 | * @return current device time in seconds 59 | */ 60 | public static long getTimeStampInSeconds() { 61 | return System.currentTimeMillis() / 1000; 62 | } 63 | 64 | 65 | /** 66 | * get difference between current time and provided timezone 67 | * 68 | * @return 69 | */ 70 | public long getTimeOffset() { 71 | long currentTime = System.currentTimeMillis(); 72 | int edtOffset = TimeZone.getTimeZone("Your Time Zone").getOffset(currentTime); 73 | int current = TimeZone.getDefault().getOffset(currentTime); 74 | return current - edtOffset; 75 | } 76 | 77 | /** 78 | * Convert date from one format to another 79 | * 80 | * @param dateToConvert date to be converted 81 | * @param formatFrom the format of the date to be converted 82 | * @param formatTo the format of date you want the output 83 | * @return date in string as per the entered formats 84 | */ 85 | @SuppressLint("SimpleDateFormat") 86 | public String convertDateOneToAnother(String dateToConvert, String formatFrom, String formatTo) { 87 | String outputDateStr = null; 88 | DateFormat inputFormat = new SimpleDateFormat(formatFrom); 89 | DateFormat outputFormat = new SimpleDateFormat(formatTo); 90 | Date date; 91 | try { 92 | date = inputFormat.parse(dateToConvert); 93 | outputDateStr = outputFormat.format(date); 94 | } catch (ParseException e) { 95 | e.printStackTrace(); 96 | } 97 | return outputDateStr; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/utils/DialogsUtil.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.utils; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | 6 | import com.sampleapp.R; 7 | import com.sampleapp.interfaces.OnDialogButtonClickListener; 8 | 9 | /** 10 | * Created by saveen_dhiman on 05-November-16. 11 | * contains Dialogs to be used in the application 12 | */ 13 | public class DialogsUtil { 14 | 15 | private Context mContext; 16 | 17 | public DialogsUtil(Context context) { 18 | this.mContext = context; 19 | } 20 | 21 | /** 22 | * Return an alert dialog 23 | * 24 | * @param message message for the alert dialog 25 | * @param listener listener to trigger selection methods 26 | */ 27 | public void openAlertDialog(Context context, String message, String positiveBtnText, String negativeBtnText, 28 | final OnDialogButtonClickListener listener) { 29 | 30 | AlertDialog.Builder builder = new AlertDialog.Builder(context); 31 | builder.setPositiveButton(positiveBtnText, (dialog, which) -> { 32 | dialog.dismiss(); 33 | listener.onPositiveButtonClicked(); 34 | 35 | }); 36 | 37 | builder.setNegativeButton(negativeBtnText, (dialog, which) -> { 38 | dialog.dismiss(); 39 | listener.onNegativeButtonClicked(); 40 | 41 | }); 42 | builder.setTitle(context.getResources().getString(R.string.app_name)); 43 | builder.setMessage(message); 44 | builder.setIcon(android.R.drawable.ic_dialog_alert); 45 | builder.setCancelable(false); 46 | builder.create().show(); 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/utils/FragmentUtils.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.utils; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | 6 | /** 7 | * Created by saveen_dhiman on 05-November-16. 8 | * contains methods related to fragment transactions 9 | */ 10 | public class FragmentUtils { 11 | 12 | // replace fragment in a container 13 | public void replaceFragment(int container, FragmentManager manager, Fragment fragment) { 14 | manager.beginTransaction().replace(container, fragment).commitAllowingStateLoss(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/utils/ImageUtility.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.utils; 2 | 3 | /** 4 | * Created by saveen_dhiman on 05-November-16. 5 | * Image related utility methods 6 | */ 7 | 8 | import android.app.Activity; 9 | import android.content.Context; 10 | import android.content.Intent; 11 | import android.database.Cursor; 12 | import android.graphics.Bitmap; 13 | import android.graphics.Bitmap.Config; 14 | import android.graphics.BitmapFactory; 15 | import android.graphics.Canvas; 16 | import android.graphics.Matrix; 17 | import android.graphics.Paint; 18 | import android.media.ExifInterface; 19 | import android.net.Uri; 20 | import android.os.Environment; 21 | import android.provider.MediaStore; 22 | import android.support.v7.app.AlertDialog; 23 | import android.util.Base64; 24 | import android.util.Log; 25 | import android.widget.ImageView; 26 | 27 | import com.sampleapp.R; 28 | import com.squareup.picasso.Picasso; 29 | 30 | import java.io.ByteArrayOutputStream; 31 | import java.io.File; 32 | import java.io.FileNotFoundException; 33 | import java.io.FileOutputStream; 34 | import java.io.IOException; 35 | 36 | import okhttp3.MediaType; 37 | import okhttp3.RequestBody; 38 | import rx.Observable; 39 | import rx.Subscriber; 40 | 41 | public class ImageUtility { 42 | private Context context; 43 | 44 | public ImageUtility(Context context) { 45 | this.context = context; 46 | } 47 | 48 | public Uri CameraGalleryIntent(final int cameraRequestCode, final int galleryRequestCode) { 49 | final File root = getFile(); 50 | root.mkdirs(); 51 | String filename = getUniqueImageFilename(); 52 | File sdImageMainDirectory = new File(root, filename); 53 | final Uri outputFileUri = Uri.fromFile(sdImageMainDirectory); 54 | AlertDialog.Builder dialog = new AlertDialog.Builder(context); 55 | CharSequence items[] = new CharSequence[]{context.getResources().getString(R.string.camera), context.getResources().getString(R.string.gallery)}; 56 | dialog.setItems(items, (d, n) -> { 57 | switch (n) { 58 | case 0: 59 | Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 60 | intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri); 61 | ((Activity) context).startActivityForResult(intent, cameraRequestCode); 62 | break; 63 | case 1: 64 | Intent pickIntent = new Intent(Intent.ACTION_PICK); 65 | pickIntent.setType("image/*"); 66 | ((Activity) context).startActivityForResult(pickIntent, galleryRequestCode); 67 | break; 68 | default: 69 | break; 70 | } 71 | }); 72 | dialog.setTitle(context.getResources().getString(R.string.selection)); 73 | if (outputFileUri != null) { 74 | dialog.show(); 75 | } 76 | return outputFileUri; 77 | } 78 | 79 | /** 80 | * Compresses the image 81 | * 82 | * @param filePath : Location of image file 83 | * @return 84 | */ 85 | @SuppressWarnings("deprecation") 86 | public String compressImage(String filePath) { 87 | Bitmap scaledBitmap = null; 88 | 89 | BitmapFactory.Options options = new BitmapFactory.Options(); 90 | options.inJustDecodeBounds = true; 91 | Bitmap bmp = BitmapFactory.decodeFile(filePath, options); 92 | 93 | int actualHeight = options.outHeight; 94 | int actualWidth = options.outWidth; 95 | float maxHeight = 816.0f; 96 | float maxWidth = 612.0f; 97 | float imgRatio = actualWidth / actualHeight; 98 | float maxRatio = maxWidth / maxHeight; 99 | 100 | if (actualHeight > maxHeight || actualWidth > maxWidth) { 101 | if (imgRatio < maxRatio) { 102 | imgRatio = maxHeight / actualHeight; 103 | actualWidth = (int) (imgRatio * actualWidth); 104 | actualHeight = (int) maxHeight; 105 | } else if (imgRatio > maxRatio) { 106 | imgRatio = maxWidth / actualWidth; 107 | actualHeight = (int) (imgRatio * actualHeight); 108 | actualWidth = (int) maxWidth; 109 | } else { 110 | actualHeight = (int) maxHeight; 111 | actualWidth = (int) maxWidth; 112 | } 113 | } 114 | 115 | options.inSampleSize = ImageUtility.calculateInSampleSize(options, actualWidth, actualHeight); 116 | options.inJustDecodeBounds = false; 117 | options.inDither = false; 118 | options.inPurgeable = true; 119 | options.inInputShareable = true; 120 | options.inTempStorage = new byte[16 * 1024]; 121 | 122 | try { 123 | bmp = BitmapFactory.decodeFile(filePath, options); 124 | } catch (OutOfMemoryError exception) { 125 | exception.printStackTrace(); 126 | 127 | } 128 | try { 129 | scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Config.ARGB_8888); 130 | } catch (OutOfMemoryError exception) { 131 | exception.printStackTrace(); 132 | } 133 | 134 | float ratioX = actualWidth / (float) options.outWidth; 135 | float ratioY = actualHeight / (float) options.outHeight; 136 | float middleX = actualWidth / 2.0f; 137 | float middleY = actualHeight / 2.0f; 138 | 139 | Matrix scaleMatrix = new Matrix(); 140 | scaleMatrix.setScale(ratioX, ratioY, middleX, middleY); 141 | 142 | Canvas canvas = new Canvas(scaledBitmap); 143 | canvas.setMatrix(scaleMatrix); 144 | canvas.drawBitmap(bmp, middleX - bmp.getWidth() / 2, middleY - bmp.getHeight() / 2, new Paint( 145 | Paint.FILTER_BITMAP_FLAG)); 146 | 147 | ExifInterface exif; 148 | try { 149 | exif = new ExifInterface(filePath); 150 | 151 | int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0); 152 | Log.e("EXIF", "Exif: " + orientation); 153 | Matrix matrix = new Matrix(); 154 | if (orientation == 6) { 155 | matrix.postRotate(90); 156 | Log.e("EXIF", "Exif: " + orientation); 157 | } else if (orientation == 3) { 158 | matrix.postRotate(180); 159 | Log.e("EXIF", "Exif: " + orientation); 160 | } else if (orientation == 8) { 161 | matrix.postRotate(270); 162 | Log.e("EXIF", "Exif: " + orientation); 163 | } 164 | scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), 165 | matrix, true); 166 | } catch (IOException e) { 167 | e.printStackTrace(); 168 | } 169 | FileOutputStream out = null; 170 | String filename = getFilename(); 171 | try { 172 | out = new FileOutputStream(filename); 173 | scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 95, out); 174 | } catch (FileNotFoundException e) { 175 | e.printStackTrace(); 176 | } finally { 177 | if (bmp != null) { 178 | bmp.recycle(); 179 | bmp = null; 180 | } 181 | if (scaledBitmap != null) { 182 | scaledBitmap.recycle(); 183 | } 184 | } 185 | return filename; 186 | 187 | } 188 | 189 | public String getFilename() { 190 | 191 | final File root = getFile(); 192 | root.mkdirs(); 193 | final String filename = getUniqueImageFilename(); 194 | File file = new File(root, filename); 195 | return file.getAbsolutePath(); 196 | } 197 | 198 | private File getFile() { 199 | return new File(Environment.getExternalStorageDirectory() + File.separator + "SampleApp" 200 | + File.separator); 201 | } 202 | 203 | public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { 204 | final int height = options.outHeight; 205 | final int width = options.outWidth; 206 | int inSampleSize = 1; 207 | 208 | if (height > reqHeight || width > reqWidth) { 209 | if (width > height) { 210 | inSampleSize = Math.round((float) height / (float) reqHeight); 211 | } else { 212 | inSampleSize = Math.round((float) width / (float) reqWidth); 213 | } 214 | } 215 | return inSampleSize; 216 | } 217 | 218 | public static String getUniqueImageFilename() { 219 | return "img_" + System.currentTimeMillis() + ".png"; 220 | } 221 | 222 | public String getRealPathFromURI(Uri contentUri) { 223 | // can post image 224 | String[] proj = {MediaStore.Images.Media.DATA}; 225 | @SuppressWarnings("deprecation") 226 | Cursor cursor = ((Activity) context).managedQuery(contentUri, proj, // Which 227 | // columns 228 | // to 229 | // return 230 | null, // WHERE clause; which rows to return (all rows) 231 | null, // WHERE clause selection arguments (none) 232 | null); // Order-by clause (ascending by name) 233 | int column_index = cursor 234 | .getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 235 | cursor.moveToFirst(); 236 | return cursor.getString(column_index); 237 | } 238 | 239 | 240 | public void LoadImage(String url, ImageView imageView) { 241 | LoadImage(url, imageView, false); 242 | } 243 | 244 | public void LoadImage(String url, ImageView imageView, boolean isRounded) { 245 | Picasso.with(context).load(url).into(imageView); 246 | } 247 | 248 | /** 249 | * Compress image and convert to multipart 250 | * 251 | * @param filePath path of the file to be converted 252 | * @return multipart image for the path supplied 253 | */ 254 | public Observable getCompressedFile(final String filePath, final ImageUtility imageUtility) { 255 | return Observable.create(new Observable.OnSubscribe() { 256 | @Override 257 | public void call(Subscriber subscriber) { 258 | try { 259 | String newFilePath = getCompressedImage(filePath); 260 | subscriber.onNext(imageUtility.getRequestBodyImage(new File(newFilePath))); 261 | subscriber.onCompleted(); 262 | } catch (Exception e) { 263 | subscriber.onError(e); 264 | } 265 | } 266 | }); 267 | } 268 | 269 | /** 270 | * get request body image 271 | */ 272 | public RequestBody getRequestBodyImage(File file) { 273 | return RequestBody.create(MediaType.parse("image/png"), file); 274 | } 275 | 276 | /** 277 | * convert image to base 64 string 278 | * 279 | * @param filePath path of image 280 | * @return base 64 string 281 | */ 282 | public String getBase64Image(String filePath) { 283 | filePath = getCompressedImage(filePath); 284 | Bitmap bm = BitmapFactory.decodeFile(filePath); 285 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 286 | bm.compress(Bitmap.CompressFormat.PNG, 100, baos); //bm is the bitmap object 287 | byte[] b = baos.toByteArray(); 288 | return Base64.encodeToString(b, Base64.DEFAULT); 289 | } 290 | 291 | /** 292 | * get compressed image 293 | */ 294 | private String getCompressedImage(String filePath) { 295 | String newFilePath; 296 | int file_size = Integer.parseInt(String.valueOf(new File(filePath).length() >> 10)); 297 | if (file_size >= 120) { 298 | newFilePath = compressImage(filePath); 299 | } else { 300 | newFilePath = filePath; 301 | } 302 | return filePath; 303 | } 304 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/utils/LocationHelper.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.utils; 2 | 3 | import android.content.Context; 4 | import android.location.Address; 5 | import android.location.Geocoder; 6 | import android.location.Location; 7 | 8 | import com.google.android.gms.maps.model.LatLng; 9 | 10 | import java.io.IOException; 11 | import java.util.List; 12 | import java.util.Locale; 13 | 14 | /** 15 | * Created by saveen_dhiman on 05-November-16. 16 | * contains helper methods to manipulate user location 17 | */ 18 | public class LocationHelper { 19 | 20 | private Context mContext; 21 | 22 | public LocationHelper(Context context) { 23 | this.mContext = context; 24 | } 25 | 26 | /** 27 | * @param latitude latitude of address 28 | * @param longitude longitude of address 29 | * @return simplified address of location 30 | */ 31 | 32 | public String getSimplifiedAddress(double latitude, double longitude) { 33 | String location = ""; 34 | try { 35 | Geocoder geocoder = new Geocoder(mContext, Locale.getDefault()); 36 | List

addresses = geocoder.getFromLocation(latitude, longitude, 1); 37 | if (addresses.size() > 0) { 38 | Address address = addresses.get(0); 39 | String admin = address.getAdminArea(); 40 | String subLocality = address.getSubLocality(); 41 | String locality = address.getLocality(); 42 | if (admin.length() > 10) { 43 | admin = admin.substring(0, 10) + ".."; 44 | } 45 | if (locality != null && subLocality != null) { 46 | location = subLocality + "," + locality; 47 | } else if (subLocality != null) { 48 | location = subLocality + "," + admin; 49 | } else { 50 | location = locality + "," + admin; 51 | } 52 | } 53 | } catch (IOException e) { 54 | e.printStackTrace(); 55 | } 56 | 57 | return location; 58 | } 59 | 60 | /** 61 | * @param latitude latitude of address 62 | * @param longitude longitude of address 63 | * @return complete address of location 64 | */ 65 | 66 | public String getCompleteAddress(double latitude, double longitude) { 67 | String location = ""; 68 | try { 69 | Geocoder geocoder = new Geocoder(mContext, Locale.getDefault()); 70 | List
addresses = geocoder.getFromLocation(latitude, longitude, 1); 71 | if (addresses.size() > 0) { 72 | Address address = addresses.get(0); 73 | String state, city, zip, street; 74 | if (address.getAdminArea() != null) { 75 | state = address.getAdminArea(); 76 | } else { 77 | state = ""; 78 | } 79 | if (address.getLocality() != null) { 80 | city = address.getLocality(); 81 | } else { 82 | city = ""; 83 | } 84 | if (address.getPostalCode() != null) { 85 | zip = address.getPostalCode(); 86 | } else { 87 | zip = ""; 88 | } 89 | 90 | if (address.getThoroughfare() != null) { 91 | street = address.getSubLocality() + "," + address.getThoroughfare(); 92 | } else { 93 | street = address.getSubLocality() + "," + address.getFeatureName(); 94 | } 95 | location = street + "," + city + "," + zip + "," + state; 96 | } 97 | } catch (IOException e) { 98 | e.printStackTrace(); 99 | } 100 | 101 | return location; 102 | } 103 | 104 | /** 105 | * Calculate distance between two 106 | * 107 | * @param src lat/long of source 108 | * @param des lat/lng of destination 109 | * @return distance between two location in miles 110 | */ 111 | public double calculateDistance(LatLng src, LatLng des) { 112 | double distance; 113 | double finalValue = 0; 114 | try { 115 | Location locationA = new Location(""); 116 | locationA.setLatitude(src.latitude); 117 | locationA.setLongitude(src.longitude); 118 | Location locationB = new Location(""); 119 | locationB.setLatitude(des.latitude); 120 | locationB.setLongitude(des.longitude); 121 | distance = locationA.distanceTo(locationB) / 1000; 122 | finalValue = Math.round(distance * 100.0) / 100.0; 123 | } catch (Exception e) { 124 | e.printStackTrace(); 125 | } 126 | 127 | return finalValue; 128 | } 129 | 130 | /** 131 | * to get latitude and longitude of an address 132 | * 133 | * @param strAddress address string 134 | * @return lat and lng in comma separated string 135 | */ 136 | public String getLocationFromAddress(String strAddress) { 137 | 138 | Geocoder coder = new Geocoder(mContext); 139 | List
address; 140 | 141 | try { 142 | address = coder.getFromLocationName(strAddress, 1); 143 | if (address == null) { 144 | return null; 145 | } 146 | Address location = address.get(0); 147 | double lat = location.getLatitude(); 148 | double lng = location.getLongitude(); 149 | 150 | return lat + "," + lng; 151 | } catch (Exception e) { 152 | return null; 153 | } 154 | } 155 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/utils/LocationTracker.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.utils; 2 | 3 | import android.content.Context; 4 | import android.location.Location; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | 8 | import com.google.android.gms.common.ConnectionResult; 9 | import com.google.android.gms.common.api.GoogleApiClient; 10 | import com.google.android.gms.location.LocationListener; 11 | import com.google.android.gms.location.LocationRequest; 12 | import com.google.android.gms.location.LocationServices; 13 | import com.sampleapp.R; 14 | import com.sampleapp.base.SampleApplication; 15 | 16 | import javax.inject.Inject; 17 | 18 | import timber.log.Timber; 19 | 20 | @SuppressWarnings("MissingPermission") 21 | public class LocationTracker implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { 22 | 23 | private Context context; 24 | private GoogleApiClient mGoogleApiClient; 25 | private static int UPDATE_INTERVAL = 0; 26 | private static int FATEST_INTERVAL = 0; 27 | private static int DISPLACEMENT = 2000; // 2KM 28 | private LocationRequest mLocationRequest; 29 | private Location mLastLocation; 30 | private onLocationListener listener; 31 | 32 | @Inject 33 | AppUtils mAppUtils; 34 | 35 | public LocationTracker(Context context) { 36 | this.context = context; 37 | 38 | ((SampleApplication)context).getAppComponent().inject(this); 39 | 40 | if (mAppUtils.checkPlayServices()) { 41 | buildGoogleApiClient(); 42 | createLocationRequest(); 43 | if (mGoogleApiClient != null) { 44 | mGoogleApiClient.connect(); 45 | } 46 | } else { 47 | mAppUtils.showToast(context.getResources().getString(R.string.warning_play_services)); 48 | } 49 | } 50 | 51 | 52 | protected synchronized void buildGoogleApiClient() { 53 | mGoogleApiClient = new GoogleApiClient.Builder(context) 54 | .addConnectionCallbacks(this) 55 | .addOnConnectionFailedListener(this) 56 | .addApi(LocationServices.API).build(); 57 | } 58 | 59 | @Override 60 | public void onConnected(Bundle bundle) { 61 | displayLocation(); 62 | startLocationUpdates(); 63 | } 64 | 65 | @Override 66 | public void onConnectionSuspended(int i) { 67 | mGoogleApiClient.connect(); 68 | } 69 | 70 | @Override 71 | public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { 72 | Timber.e(connectionResult.toString()); 73 | } 74 | 75 | /** 76 | * Creating location request object 77 | */ 78 | private void createLocationRequest() { 79 | mLocationRequest = new LocationRequest(); 80 | mLocationRequest.setInterval(UPDATE_INTERVAL); 81 | mLocationRequest.setFastestInterval(FATEST_INTERVAL); 82 | mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); 83 | mLocationRequest.setSmallestDisplacement(DISPLACEMENT); 84 | } 85 | 86 | /** 87 | * Method to display the location on UI 88 | */ 89 | private void displayLocation() { 90 | mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); 91 | if (mLastLocation != null) { 92 | double latitude = mLastLocation.getLatitude(); 93 | double longitude = mLastLocation.getLongitude(); 94 | Timber.e(latitude + "," + longitude); 95 | listener.onConnected(mLastLocation); 96 | } 97 | } 98 | 99 | /** 100 | * Starting the location updates 101 | */ 102 | private void startLocationUpdates() { 103 | LocationServices.FusedLocationApi 104 | .requestLocationUpdates(mGoogleApiClient, mLocationRequest, locationListener); 105 | Timber.e("startLocationUpdates"); 106 | } 107 | 108 | /** 109 | * Stopping location updates 110 | */ 111 | public void stopLocationUpdates() { 112 | try { 113 | LocationServices.FusedLocationApi 114 | .removeLocationUpdates(mGoogleApiClient, locationListener); 115 | Timber.e("stopLocationUpdates"); 116 | } catch (Exception e) { 117 | e.printStackTrace(); 118 | } 119 | } 120 | 121 | private LocationListener locationListener = new LocationListener() { 122 | @Override 123 | public void onLocationChanged(Location location) { 124 | mLastLocation = location; 125 | displayLocation(); 126 | } 127 | }; 128 | 129 | public void setLocationListener(onLocationListener listener) { 130 | this.listener = listener; 131 | } 132 | 133 | public interface onLocationListener { 134 | void onConnected(Location location); 135 | } 136 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/utils/PreferenceManager.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | 6 | import com.google.gson.Gson; 7 | import com.sampleapp.constants.PrefernceConstants; 8 | import com.sampleapp.model.UserData; 9 | 10 | 11 | /** 12 | * Created by saveen_dhiman on 05-November-16. 13 | * Contains method to store and retrieve SharedPreferences data 14 | */ 15 | public class PreferenceManager { 16 | 17 | private static Context context1; 18 | 19 | public PreferenceManager(Context context) { 20 | PreferenceManager.context1 = context; 21 | } 22 | 23 | //get shared pref 24 | private SharedPreferences getPreferences() { 25 | return context1.getSharedPreferences(PrefernceConstants.PREFERENCE_NAME, Context.MODE_PRIVATE); 26 | } 27 | 28 | 29 | //save data of current logged in user 30 | public void setUserData(String userData) { 31 | getPreferences().edit().putString(PrefernceConstants.USER_DATA, userData).commit(); 32 | } 33 | 34 | //get user data as string 35 | private String getUserDataFromPref() { 36 | return getPreferences().getString(PrefernceConstants.USER_DATA, null); 37 | } 38 | 39 | //get saved data of current user as an object 40 | public UserData.ResponseBean.AuthBean getUserData() { 41 | UserData.ResponseBean.AuthBean userData = null; 42 | if (getUserDataFromPref() != null) { 43 | userData = new Gson().fromJson(getUserDataFromPref(), UserData.ResponseBean.AuthBean.class); 44 | } 45 | return userData; 46 | } 47 | 48 | //returns true when user is logged in 49 | public void setUserLoggedIn(boolean isLogin) { 50 | getPreferences().edit().putBoolean(PrefernceConstants.IS_LOGIN, isLogin).commit(); 51 | } 52 | 53 | //set true when user is logegd in else false 54 | public boolean isUserLoggedIn() { 55 | return getPreferences().getBoolean(PrefernceConstants.IS_LOGIN, false); 56 | } 57 | 58 | //clear user shared preferences 59 | public void clearPrefrences() { 60 | getPreferences().edit().clear().commit(); 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/utils/ProgressBarHandler.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.utils; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.support.v4.content.ContextCompat; 6 | import android.view.Gravity; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ProgressBar; 10 | import android.widget.RelativeLayout; 11 | 12 | import com.sampleapp.R; 13 | 14 | 15 | public class ProgressBarHandler { 16 | 17 | private ProgressBar mProgressBar; 18 | 19 | public ProgressBarHandler(Context context) { 20 | 21 | ViewGroup layout = (ViewGroup) ((Activity) context).findViewById(android.R.id.content).getRootView(); 22 | 23 | mProgressBar = new ProgressBar(context, null); 24 | mProgressBar.setIndeterminate(true); 25 | 26 | mProgressBar.getIndeterminateDrawable().setColorFilter(ContextCompat.getColor(context, R.color.colorPrimary), 27 | android.graphics.PorterDuff.Mode.MULTIPLY); 28 | 29 | RelativeLayout.LayoutParams params = new 30 | RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT); 31 | 32 | RelativeLayout rl = new RelativeLayout(context); 33 | 34 | rl.setGravity(Gravity.CENTER); 35 | rl.addView(mProgressBar); 36 | 37 | layout.addView(rl, params); 38 | 39 | hideProgress(); 40 | } 41 | 42 | public void showProgress() { 43 | mProgressBar.setVisibility(View.VISIBLE); 44 | } 45 | 46 | public void hideProgress() { 47 | mProgressBar.setVisibility(View.INVISIBLE); 48 | } 49 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/utils/UtilsModule.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.utils; 2 | 3 | import android.content.Context; 4 | 5 | import com.sampleapp.constants.ValueConstants; 6 | 7 | import javax.inject.Named; 8 | import javax.inject.Singleton; 9 | 10 | import dagger.Module; 11 | import dagger.Provides; 12 | import rx.Scheduler; 13 | import rx.android.schedulers.AndroidSchedulers; 14 | import rx.schedulers.Schedulers; 15 | 16 | /** 17 | * Created by saveen_dhiman on 05-November-16. 18 | * Provide injects for utility objects 19 | */ 20 | 21 | @Module 22 | public class UtilsModule { 23 | 24 | private Context mContext; 25 | 26 | public UtilsModule(Context context) { 27 | this.mContext = context; 28 | } 29 | 30 | // get AppUtils instance 31 | @Provides 32 | @Singleton 33 | public AppUtils getAppUtils() { 34 | return new AppUtils(mContext); 35 | } 36 | 37 | // get DateTimeUtils instance 38 | @Provides 39 | @Singleton 40 | public DateTimeUtils getDateTimeUtils() { 41 | return new DateTimeUtils(); 42 | } 43 | 44 | // get ProgressBarHandler instance 45 | @Provides 46 | @Singleton 47 | public ProgressBarHandler getProgressBar() { 48 | return new ProgressBarHandler(mContext); 49 | } 50 | 51 | //get dialog utils 52 | @Provides 53 | @Singleton 54 | public DialogsUtil getDialogUtils() { 55 | return new DialogsUtil(mContext); 56 | } 57 | 58 | //get new thread 59 | @Provides 60 | @Singleton 61 | @Named(ValueConstants.NEW_THREAD) 62 | public Scheduler getNewThread() { 63 | return Schedulers.io(); 64 | } 65 | 66 | //get main thread 67 | @Provides 68 | @Singleton 69 | @Named(ValueConstants.MAIN_THREAD) 70 | public Scheduler getMainThread() { 71 | return AndroidSchedulers.mainThread(); 72 | } 73 | 74 | //get Preference Manager 75 | @Provides 76 | @Singleton 77 | public PreferenceManager getPreferences() { 78 | return new PreferenceManager(mContext); 79 | } 80 | 81 | //get Fragment utils 82 | @Provides 83 | @Singleton 84 | public FragmentUtils getFragUtils() { 85 | return new FragmentUtils(); 86 | } 87 | 88 | //get location helper methods 89 | @Provides 90 | @Singleton 91 | public LocationHelper getLocationUtils() { 92 | return new LocationHelper(mContext); 93 | } 94 | 95 | //get location tracker 96 | @Provides 97 | @Singleton 98 | public LocationTracker getLocationTrackerOF() { 99 | return new LocationTracker(mContext); 100 | } 101 | 102 | //get image utils 103 | @Provides 104 | @Singleton 105 | public ImageUtility getImageUtils() { 106 | return new ImageUtility(mContext); 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /app/src/main/java/com/sampleapp/views/RemoveErrorEditText.java: -------------------------------------------------------------------------------- 1 | package com.sampleapp.views; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.text.Editable; 7 | import android.text.TextWatcher; 8 | import android.util.AttributeSet; 9 | import android.widget.EditText; 10 | 11 | /** 12 | * Created by saveen_dhiman on 05-November-16. 13 | * Custom editText to remove error on editText field when onTextChange is called 14 | */ 15 | public class RemoveErrorEditText extends EditText { 16 | public RemoveErrorEditText(Context context) { 17 | super(context); 18 | removeError(); 19 | } 20 | 21 | public RemoveErrorEditText(Context context, AttributeSet attrs) { 22 | super(context, attrs); 23 | removeError(); 24 | } 25 | 26 | public RemoveErrorEditText(Context context, AttributeSet attrs, int defStyleAttr) { 27 | super(context, attrs, defStyleAttr); 28 | removeError(); 29 | } 30 | 31 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 32 | public RemoveErrorEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 33 | super(context, attrs, defStyleAttr, defStyleRes); 34 | removeError(); 35 | } 36 | 37 | 38 | private void removeError() { 39 | 40 | addTextChangedListener(new TextWatcher() { 41 | @Override 42 | public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { 43 | } 44 | 45 | @Override 46 | public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { 47 | } 48 | 49 | @Override 50 | public void afterTextChanged(Editable editable) { 51 | setError(null); 52 | } 53 | }); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/general_click_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/general_click_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 19 | 20 | 25 | 26 | 31 | 32 |