├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── kotlincleancode4android │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── kotlincleancode4android │ │ │ ├── AppController.kt │ │ │ ├── FlightModel.kt │ │ │ ├── Util.kt │ │ │ ├── boardingScreen │ │ │ ├── BoardingActivity.kt │ │ │ ├── BoardingConfigurator.kt │ │ │ ├── BoardingInteractor.kt │ │ │ ├── BoardingPresenter.kt │ │ │ ├── BoardingRouter.kt │ │ │ ├── BoardingWorker.kt │ │ │ └── CheckINModel.kt │ │ │ ├── homescreen │ │ │ ├── FlightListAdapter.kt │ │ │ ├── FlightWorker.kt │ │ │ ├── HomeConfigurator.kt │ │ │ ├── HomeFragment.kt │ │ │ ├── HomeInteractor.kt │ │ │ ├── HomeModels.kt │ │ │ ├── HomePresenter.kt │ │ │ ├── HomeRouter.kt │ │ │ └── MainActivity.kt │ │ │ └── pastTripScreen │ │ │ └── PastTripFragment.kt │ └── res │ │ ├── drawable-v24 │ │ ├── ic_launcher_foreground.xml │ │ ├── ic_plan_landing.xml │ │ ├── ic_plan_takeoff.xml │ │ ├── shape_rectangle_fill_light.xml │ │ └── shape_rectangle_stroke.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_boarding.xml │ │ ├── activity_main.xml │ │ ├── activity_past_trip.xml │ │ ├── cell_trip_list.xml │ │ ├── fragment_home.xml │ │ └── fragment_past_trip.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── values │ │ ├── colors.xml │ │ ├── ids.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── backup_descriptor.xml │ └── test │ └── java │ └── com │ └── example │ └── kotlincleancode4android │ ├── HomeFragmentUnitTest.kt │ ├── HomeInteractorUnitTest.kt │ ├── HomePresenterUnitTest.kt │ └── HomeRouterUnitTest.kt ├── build.gradle ├── doc └── images │ └── kotlinCleanCode.png ├── gradle.properties └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches/build_file_checksums.ser 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | .DS_Store 9 | /build 10 | /captures 11 | .externalNativeBuild 12 | 13 | 14 | gradlew* 15 | *.iml 16 | .gradle 17 | /local.properties 18 | /.idea/workspace.xml 19 | /.idea/libraries 20 | .DS_Store 21 | /build 22 | /captures 23 | .externalNativeBuild 24 | build/ 25 | projectFilesBackup/ 26 | gradle/ 27 | .gradle/ 28 | .idea/** 29 | .notidea/ 30 | *.DS_Store 31 | *.iml 32 | app/build/** 33 | 34 | 35 | # built application files 36 | *.apk 37 | *.ap_ 38 | 39 | # files for the dex VM 40 | *.dex 41 | 42 | # Java class files 43 | *.class 44 | 45 | # built native files (uncomment if you build your own) 46 | # *.o 47 | # *.so 48 | 49 | # generated files 50 | bin/ 51 | gen/ 52 | 53 | # Ignore gradle files 54 | .gradle/ 55 | build/ 56 | 57 | # Local configuration file (sdk path, etc) 58 | local.properties 59 | 60 | # Proguard folder generated by Eclipse 61 | proguard/ 62 | 63 | # Eclipse Metadata 64 | .metadata/ 65 | 66 | # Mac OS X clutter 67 | *.DS_Store 68 | 69 | # Windows clutter 70 | Thumbs.db 71 | # Intellij IDEA (see https://intellij-support.jetbrains.com/entries/23393067) 72 | .idea/workspace.xml 73 | .idea/tasks.xml 74 | .idea/datasources.xml 75 | .idea/dataSources.ids 76 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Mohanraj Karatadipalayam 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Test Driven Android Development - Kotlin Clean Code For Android 2 | #### Inspired from [Clean Architecture][1] from Uncle Bob, [Google Android samples][3] and [Clean Swift][2] 3 | ##### This design is chosen with a singular focus - testability. 4 | ##### Want to learn about Android Clean Code ? follow [here][7] 5 | 6 | 7 | ![Image of CleanCode](/doc/images/kotlinCleanCode.png) 8 | 9 | 10 | ## Quick Start 11 | 1. Clone and open in Android Studio 12 | 2. It should work with out any issues 13 | 3. When running the unit test cases choose the debug variant `unitTest`, **it will not work with `debug` or `release` variants** 14 | 15 | 16 | ## Whats Next ? 17 | Want to use it your projects - bothered about the too much boilerplate code ? You can generate them with in few seconds - check [here][5] 18 | 19 | ### Contribute 20 | Welcome to contribute, feel free to change and open a PR. 21 | 22 | ### License 23 | [MIT License][6] 24 | 25 | #### TODO 26 | 1. Create example test cases for Router 27 | 2. Create code and test examples for the detail page. 28 | 3. Create example for Fragments 29 | 30 | #### Inspiration 31 | 32 | This project ideas are n't new in any way. Credit has to be given to the following projects, listed in autobiographical order. 33 | 34 | [Clean Architecture][1] 35 | 36 | [clean-swift][2] 37 | 38 | [1]: https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html 39 | [2]: http://clean-swift.com 40 | [3]: https://github.com/googlesamples/android-testing 41 | [4]: https://riggaroo.co.za/custom-file-templates-android-studio/ 42 | [5]: https://github.com/kmmraj/kt-clean-code4Android-generator 43 | [6]: ./LICENSE 44 | [7]: https://medium.com/@kmmraj/kotlin-clean-code-4-android-part-1-3d01703ebea8 45 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | gradlew* 3 | *.iml 4 | .gradle 5 | /local.properties 6 | /.idea/workspace.xml 7 | /.idea/libraries 8 | .DS_Store 9 | /build 10 | /captures 11 | .externalNativeBuild 12 | build/ 13 | projectFilesBackup/ 14 | gradle/ 15 | .gradle/ 16 | .idea/** 17 | .notidea/ 18 | *.DS_Store 19 | *.iml 20 | app/build/** 21 | 22 | 23 | # built application files 24 | *.apk 25 | *.ap_ 26 | 27 | # files for the dex VM 28 | *.dex 29 | 30 | # Java class files 31 | *.class 32 | 33 | # built native files (uncomment if you build your own) 34 | # *.o 35 | # *.so 36 | 37 | # generated files 38 | bin/ 39 | gen/ 40 | 41 | # Ignore gradle files 42 | .gradle/ 43 | build/ 44 | 45 | # Local configuration file (sdk path, etc) 46 | local.properties 47 | 48 | # Proguard folder generated by Eclipse 49 | proguard/ 50 | 51 | # Eclipse Metadata 52 | .metadata/ 53 | 54 | # Mac OS X clutter 55 | *.DS_Store 56 | 57 | # Windows clutter 58 | Thumbs.db 59 | # Intellij IDEA (see https://intellij-support.jetbrains.com/entries/23393067) 60 | .idea/workspace.xml 61 | .idea/tasks.xml 62 | .idea/datasources.xml 63 | .idea/dataSources.ids -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | 8 | ext { 9 | leakcanary_android_version = "1.5.4" 10 | support_lib_version = "27.1.1" 11 | constraint_layout_version = "1.1.3" 12 | ktlint_version = "0.29.0" 13 | junit_version = "4.12" 14 | robolectric_version = "3.8" 15 | test_runner_version = "1.0.2" 16 | espresso_core_version = "3.0.2" 17 | } 18 | 19 | android { 20 | compileSdkVersion 27 21 | defaultConfig { 22 | applicationId "com.example.kotlincleancode4android" 23 | minSdkVersion 16 24 | targetSdkVersion 27 25 | versionCode 1 26 | versionName "1.0" 27 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 28 | } 29 | buildTypes { 30 | release { 31 | minifyEnabled false 32 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 33 | buildConfigField 'boolean', 'memoryTest', 'true' 34 | } 35 | debug { 36 | buildConfigField 'boolean', 'memoryTest', 'true' 37 | } 38 | 39 | unitTest { 40 | buildConfigField 'boolean', 'memoryTest', 'false' 41 | } 42 | } 43 | 44 | testOptions { 45 | unitTests { 46 | includeAndroidResources = true 47 | } 48 | } 49 | 50 | configurations { 51 | ktlint 52 | } 53 | 54 | defaultConfig { 55 | vectorDrawables.useSupportLibrary = true 56 | } 57 | } 58 | 59 | dependencies { 60 | implementation fileTree(dir: 'libs', include: ['*.jar']) 61 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 62 | implementation "com.android.support:appcompat-v7:$support_lib_version" 63 | implementation "com.android.support.constraint:constraint-layout:$constraint_layout_version" 64 | implementation "com.android.support:design:$support_lib_version" 65 | 66 | ktlint "com.github.shyiko:ktlint:$ktlint_version" 67 | 68 | testImplementation "junit:junit:$junit_version" 69 | testImplementation "org.robolectric:robolectric:$robolectric_version" 70 | 71 | 72 | androidTestImplementation "com.android.support.test:runner:$test_runner_version" 73 | androidTestImplementation "com.android.support.test.espresso:espresso-core:$espresso_core_version" 74 | 75 | 76 | debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakcanary_android_version" 77 | implementation "com.squareup.leakcanary:leakcanary-android:$leakcanary_android_version" 78 | releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakcanary_android_version" 79 | 80 | 81 | } 82 | 83 | 84 | task ktlint(type: JavaExec, group: "verification") { 85 | description = "Check Kotlin code style." 86 | main = "com.github.shyiko.ktlint.Main" 87 | classpath = configurations.ktlint 88 | args "src/**/*.kt" 89 | // to generate report in checkstyle format prepend following args: 90 | // "--reporter=plain", "--reporter=checkstyle,output=${buildDir}/ktlint.xml" 91 | // see https://github.com/shyiko/ktlint#usage for more 92 | } 93 | check.dependsOn ktlint 94 | 95 | task ktlintFormat(type: JavaExec, group: "formatting") { 96 | description = "Fix Kotlin code style deviations." 97 | main = "com.github.shyiko.ktlint.Main" 98 | classpath = configurations.ktlint 99 | args "-F", "src/**/*.kt" 100 | } 101 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/kotlincleancode4android/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android 2 | 3 | import android.support.test.InstrumentationRegistry 4 | import android.support.test.runner.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getTargetContext() 22 | assertEquals("com.example.kotlincleancode4android", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/AppController.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android 2 | 3 | import android.app.Application 4 | import com.squareup.leakcanary.LeakCanary 5 | 6 | /** 7 | * Created by Mohanraj Karatadipalayam on 12/10/18. 8 | */ 9 | class AppController: Application() { 10 | override fun onCreate() { 11 | super.onCreate() 12 | // TODO - Create a debugTest build variant 13 | if(BuildConfig.memoryTest) { 14 | if (LeakCanary.isInAnalyzerProcess(this)) { 15 | // This process is dedicated to LeakCanary for heap analysis. 16 | // You should not init your app in this process. 17 | return 18 | } 19 | LeakCanary.install(this) 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/FlightModel.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android 2 | 3 | import android.os.Parcel 4 | import android.os.Parcelable 5 | 6 | /** 7 | * Created by Mohanraj Karatadipalayam on 06/10/18. 8 | */ 9 | 10 | // Inline function to create Parcel Creator 11 | inline fun createParcel(crossinline createFromParcel: (Parcel) -> T?): Parcelable.Creator = 12 | object : Parcelable.Creator { 13 | override fun createFromParcel(source: Parcel): T? = createFromParcel(source) 14 | override fun newArray(size: Int): Array = arrayOfNulls(size) 15 | } 16 | 17 | // custom readParcelable to avoid reflection 18 | fun Parcel.readParcelable(creator: Parcelable.Creator): T? { 19 | if (readString() != null) return creator.createFromParcel(this) else return null 20 | } 21 | 22 | open class FlightModel( 23 | var flightName: String, 24 | var startingTime: String, 25 | var departureCity: String, 26 | var arrivalCity: String, 27 | var departureTime: String, 28 | var arrivalTime: String 29 | ): Parcelable { 30 | 31 | constructor(parcelIn: Parcel) : this( 32 | flightName = parcelIn.readString(), 33 | startingTime = parcelIn.readString(), 34 | departureCity = parcelIn.readString(), 35 | arrivalCity = parcelIn.readString(), 36 | departureTime = parcelIn.readString(), 37 | arrivalTime = parcelIn.readString() 38 | ) 39 | 40 | 41 | 42 | override fun describeContents(): Int { 43 | return 0 44 | } 45 | 46 | override fun writeToParcel(dest: Parcel, flags: Int) { 47 | dest.writeString(flightName) 48 | dest.writeString(startingTime) 49 | dest.writeString(departureCity) 50 | dest.writeString(arrivalCity) 51 | dest.writeString(departureTime) 52 | dest.writeString(arrivalTime) 53 | } 54 | 55 | companion object { 56 | @JvmField @Suppress("unused") 57 | val CREATOR = createParcel { FlightModel(it) } 58 | } 59 | } 60 | 61 | 62 | class FlightViewModel( 63 | var noOfDaysToFly: String? = null, 64 | flightName: String, 65 | startingTime: String, 66 | departureCity: String, 67 | arrivalCity: String, 68 | departureTime: String, 69 | arrivalTime: String 70 | ): FlightModel( 71 | flightName, 72 | startingTime, 73 | departureCity, 74 | arrivalCity, 75 | departureTime, 76 | arrivalTime 77 | ) { 78 | 79 | constructor(parcelIn: Parcel): this( 80 | noOfDaysToFly = parcelIn.readString(), 81 | flightName = parcelIn.readString(), 82 | startingTime = parcelIn.readString(), 83 | departureCity = parcelIn.readString(), 84 | arrivalCity = parcelIn.readString(), 85 | departureTime = parcelIn.readString(), 86 | arrivalTime = parcelIn.readString() 87 | ) 88 | 89 | 90 | override fun describeContents(): Int { 91 | return 0 92 | } 93 | 94 | override fun writeToParcel(dest: Parcel, flags: Int) { 95 | dest.writeString(noOfDaysToFly) 96 | super.writeToParcel(dest, flags) 97 | 98 | } 99 | 100 | companion object { 101 | @JvmField @Suppress("unused") 102 | val CREATOR = createParcel { FlightViewModel(it) } 103 | } 104 | 105 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/Util.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android 2 | 3 | import android.support.v4.app.FragmentTransaction 4 | import android.support.v7.app.AppCompatActivity 5 | import java.util.Calendar 6 | import java.util.concurrent.TimeUnit 7 | 8 | /** 9 | * Created by Mohanraj Karatadipalayam on 06/10/18. 10 | */ 11 | 12 | class ArrayEmptyException(var msg: String? = "ArrayEmptyException") : RuntimeException() 13 | 14 | object CalendarUtil { 15 | 16 | fun getCalendar(date: String?): Calendar { 17 | // Date should be in the format YYYY/MM/DD if not return 18 | if (date != null && !date.isEmpty() && date.length == 10) { 19 | val year = Integer.parseInt(date.substring(0, 4)) 20 | val month = Integer.parseInt(date.substring(5, 7)) 21 | val day = Integer.parseInt(date.substring(8, 10)) 22 | val startingTime = Calendar.getInstance() 23 | startingTime.set(year, month - 1, day, 0, 0, 0) 24 | return startingTime 25 | } 26 | return Calendar.getInstance() 27 | } 28 | 29 | fun getDaysDiff(startTime: Long, endTime: Long): Long { 30 | val msDiff: Long 31 | if (endTime > startTime) { 32 | msDiff = endTime - startTime 33 | } else { 34 | msDiff = startTime - endTime 35 | } 36 | // Log.e(TAG,"diff is "+ daysDiff); 37 | return TimeUnit.MILLISECONDS.toDays(msDiff) 38 | } 39 | } 40 | 41 | inline fun AppCompatActivity.transact(action: FragmentTransaction.() -> Unit) { 42 | supportFragmentManager.beginTransaction().apply { 43 | action() 44 | }.commit() 45 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/boardingScreen/BoardingActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.boardingScreen 2 | 3 | import android.support.v7.app.AppCompatActivity 4 | import android.os.Bundle 5 | import android.widget.TextView 6 | import com.example.kotlincleancode4android.FlightModel 7 | import com.example.kotlincleancode4android.R 8 | 9 | interface BoardingActivityInput { 10 | fun displayBoardingData(viewModel: BoardingViewModel) 11 | } 12 | 13 | 14 | class BoardingActivity : AppCompatActivity(), BoardingActivityInput { 15 | 16 | var output: BoardingInteractorInput? = null 17 | var router: BoardingRouter? = null 18 | 19 | private var flightModel: FlightModel? = null 20 | private var passengerName: TextView? = null 21 | private var flightCode: TextView? = null 22 | private var departureCity: TextView? = null 23 | private var arrivalCity: TextView? = null 24 | private var boardingTime: TextView? = null 25 | private var departureTime: TextView? = null 26 | private var departureDate: TextView? = null 27 | private var arrivalTime: TextView? = null 28 | private var gate: TextView? = null 29 | private var terminal: TextView? = null 30 | private var seat: TextView? = null 31 | 32 | override fun onCreate(savedInstanceState: Bundle?) { 33 | super.onCreate(savedInstanceState) 34 | setContentView(R.layout.activity_boarding) 35 | flightModel = intent.getParcelableExtra("flight") 36 | bindViews() 37 | 38 | // Do the setup 39 | BoardingConfigurator.configure(this) 40 | val aBoardingRequest = BoardingRequest() 41 | 42 | // Populate the request 43 | output?.fetchBoardingData(aBoardingRequest) 44 | 45 | // Do other work 46 | } 47 | 48 | private fun bindViews() { 49 | passengerName = findViewById(R.id.tv_passengerName) 50 | flightCode = findViewById(R.id.tv_flightNumberValue) 51 | departureCity = findViewById(R.id.tv_departureAirport) 52 | arrivalCity = findViewById(R.id.tv_arrivalAirport) 53 | boardingTime = findViewById(R.id.tv_boardingTime) 54 | departureTime = findViewById(R.id.tv_departureTime) 55 | arrivalTime = findViewById(R.id.tv_arrivalTime) 56 | departureDate = findViewById(R.id.tv_departureDate) 57 | gate = findViewById(R.id.tv_gateValue) 58 | terminal = findViewById(R.id.tv_terminalValue) 59 | seat = findViewById(R.id.tv_seatValue) 60 | } 61 | 62 | 63 | override fun displayBoardingData(viewModel: BoardingViewModel) { 64 | // Log.e(TAG, "displayBoardingData() called with: viewModel = [$viewModel]") 65 | // Log.e(TAG, "displayBoardingData() called with: flightModel = [$flightModel]") 66 | // Deal with the data 67 | val checkINModel = viewModel.checkINModel 68 | passengerName?.text = "Mohan Karats" 69 | arrivalCity?.text = flightModel?.arrivalCity 70 | arrivalTime?.text = flightModel?.arrivalTime 71 | departureCity?.text = flightModel?.departureCity 72 | departureTime?.text = flightModel?.departureTime 73 | departureDate?.text = flightModel?.startingTime 74 | 75 | gate?.text = checkINModel?.gate 76 | terminal?.text = checkINModel?.terminal 77 | seat?.text = checkINModel?.seat 78 | } 79 | 80 | companion object { 81 | const val TAG = "BoardingActivity" 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/boardingScreen/BoardingConfigurator.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.boardingScreen 2 | 3 | import java.lang.ref.WeakReference 4 | 5 | /** 6 | * Created by Mohanraj Karatadipalayam on 08/10/18. 7 | */ 8 | 9 | object BoardingConfigurator { 10 | 11 | fun configure(activity: BoardingActivity) { 12 | 13 | val router = BoardingRouter() 14 | router.activity = WeakReference(activity) 15 | 16 | val presenter = BoardingPresenter() 17 | presenter.output = WeakReference(activity) 18 | 19 | val interactor = BoardingInteractor() 20 | interactor.output = presenter 21 | 22 | // if (activity.output == null) { 23 | activity.output = interactor 24 | // } 25 | // if (activity.router == null) { 26 | activity.router = router 27 | // } 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/boardingScreen/BoardingInteractor.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.boardingScreen 2 | 3 | /** 4 | * Created by Mohanraj Karatadipalayam on 08/10/18. 5 | */ 6 | interface BoardingInteractorInput { 7 | fun fetchBoardingData(request: BoardingRequest) 8 | } 9 | 10 | class BoardingInteractor: BoardingInteractorInput { 11 | 12 | var output: BoardingPresenterInput? = null 13 | private var internalBoardingWorkerInput: BoardingWorkerInput? = null 14 | 15 | private var boardingWorkerInput: BoardingWorkerInput 16 | get() = if (internalBoardingWorkerInput == null) BoardingWorker() 17 | else 18 | internalBoardingWorkerInput!! 19 | set(boardingWorkerInput) { 20 | this.internalBoardingWorkerInput = boardingWorkerInput 21 | } 22 | 23 | override fun fetchBoardingData(request: BoardingRequest) { 24 | internalBoardingWorkerInput = boardingWorkerInput 25 | val aBoardingResponse = BoardingResponse() 26 | // Call the workers 27 | aBoardingResponse.checkINModel = internalBoardingWorkerInput?.getCheckINDetails(request) 28 | output?.presentBoardingData(aBoardingResponse) 29 | } 30 | 31 | companion object { 32 | const val TAG = "BoardingInteractor" 33 | } 34 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/boardingScreen/BoardingPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.boardingScreen 2 | 3 | import java.lang.ref.WeakReference 4 | 5 | /** 6 | * Created by Mohanraj Karatadipalayam on 08/10/18. 7 | */ 8 | interface BoardingPresenterInput { 9 | fun presentBoardingData(response: BoardingResponse) 10 | } 11 | 12 | class BoardingPresenter : BoardingPresenterInput { 13 | 14 | var output: WeakReference? = null 15 | 16 | override fun presentBoardingData(response: BoardingResponse) { 17 | // Log.e(TAG, "presentBoardingData() called with: response = [" + response + "]"); 18 | // Do your decoration or filtering here 19 | // Model and Viewmodel is same here 20 | val boardingViewModel = BoardingViewModel() 21 | boardingViewModel.checkINModel = response.checkINModel 22 | output?.get()?.displayBoardingData(boardingViewModel) 23 | } 24 | 25 | companion object { 26 | const val TAG = "BoardingPresenter" 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/boardingScreen/BoardingRouter.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.boardingScreen 2 | 3 | import android.content.Intent 4 | import android.view.View 5 | import android.widget.AdapterView 6 | import java.lang.ref.WeakReference 7 | 8 | /** 9 | * Created by Mohanraj Karatadipalayam on 08/10/18. 10 | */ 11 | internal interface BoardingRouterInput { 12 | fun navigateToSomeWhere(position: Int): Intent 13 | fun passDataToNextScene(position: Int, intent: Intent) 14 | } 15 | 16 | class BoardingRouter : BoardingRouterInput, AdapterView.OnItemClickListener { 17 | 18 | var activity: WeakReference? = null 19 | 20 | override fun navigateToSomeWhere(position: Int): Intent { 21 | // Based on the position or some other data decide what is the next scene 22 | // Intent intent = new Intent(activity.get(),NextActivity.class); 23 | // return intent; 24 | return Intent() 25 | } 26 | 27 | override fun passDataToNextScene(position: Int, intent: Intent) { 28 | // Based on the position or some other data decide the data for the next scene 29 | // BoardingModel flight = activity.get().listOfSomething.get(position); 30 | // intent.putExtra("flight",flight); 31 | } 32 | 33 | override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) { 34 | // Log.e(TAG, "onItemClick() called with: parent = [" + parent + "], view = [" + view + "], position = [" + position + "], id = [" + id + "]"); 35 | val intent = navigateToSomeWhere(position) 36 | passDataToNextScene(position, intent) 37 | activity?.get()?.startActivity(intent) 38 | } 39 | 40 | companion object { 41 | const val TAG = "BoardingRouter" 42 | } 43 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/boardingScreen/BoardingWorker.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.boardingScreen 2 | 3 | /** 4 | * Created by Mohanraj Karatadipalayam on 08/10/18. 5 | */ 6 | interface BoardingWorkerInput { 7 | // Define needed interfaces 8 | fun getCheckINDetails(boardingRequest: BoardingRequest): CheckINModel 9 | } 10 | 11 | class BoardingWorker: BoardingWorkerInput { 12 | 13 | override fun getCheckINDetails(boardingRequest: BoardingRequest): CheckINModel { 14 | val checkINModel = CheckINModel() 15 | checkINModel.flightName = "" 16 | checkINModel.startingTime = "" 17 | checkINModel.gate = "24" 18 | checkINModel.terminal = "2" 19 | checkINModel.seat = "6A" 20 | return checkINModel 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/boardingScreen/CheckINModel.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.boardingScreen 2 | 3 | /** 4 | * Created by Mohanraj Karatadipalayam on 08/10/18. 5 | */ 6 | data class CheckINModel( 7 | var flightName: String? = null, 8 | var startingTime: String? = null, 9 | var terminal: String? = null, 10 | var gate: String? = null, 11 | var seat: String? = null 12 | ) 13 | 14 | // filter to have only the needed data 15 | data class BoardingViewModel(var checkINModel: CheckINModel? = null) 16 | 17 | data class BoardingRequest(var ffNumber: String? = null) 18 | 19 | data class BoardingResponse(var checkINModel: CheckINModel? = null) 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/homescreen/FlightListAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.homescreen 2 | 3 | import android.content.Context 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.BaseAdapter 8 | import android.widget.TextView 9 | import com.example.kotlincleancode4android.FlightViewModel 10 | import com.example.kotlincleancode4android.R 11 | import java.util.ArrayList 12 | 13 | /** 14 | * Created by Mohanraj Karatadipalayam on 08/10/18. 15 | */ 16 | // TODO - check the context, should it be a WeakReference 17 | class FlightListAdapter(context: Context, 18 | private val listOfVMFlights: ArrayList) : BaseAdapter() { 19 | 20 | private val layoutInflater: LayoutInflater = LayoutInflater.from(context) 21 | 22 | override fun getCount(): Int { 23 | return listOfVMFlights.size 24 | } 25 | 26 | override fun getItem(position: Int): Any { 27 | return listOfVMFlights[position] 28 | } 29 | 30 | override fun getItemId(position: Int): Long { 31 | return position.toLong() 32 | } 33 | 34 | override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { 35 | var view = convertView 36 | 37 | if (view == null) { 38 | view = layoutInflater.inflate(R.layout.cell_trip_list, null) 39 | view?.let { 40 | val viewHolder = ViewHolder() 41 | viewHolder.flightNameTextView = view.findViewById(R.id.tv_flightNumberValue) as TextView 42 | viewHolder.startTimeTextView = view.findViewById(R.id.tv_flightTimeDescription) as TextView 43 | view.tag = viewHolder 44 | } 45 | } 46 | val viewHolder = view?.tag as ViewHolder 47 | viewHolder.flightNameTextView?.text = listOfVMFlights[position].flightName 48 | viewHolder.startTimeTextView?.text = listOfVMFlights[position].noOfDaysToFly 49 | return view 50 | } 51 | } 52 | 53 | class ViewHolder { 54 | var flightNameTextView: TextView? = null 55 | var startTimeTextView: TextView? = null 56 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/homescreen/FlightWorker.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.homescreen 2 | 3 | import com.example.kotlincleancode4android.FlightModel 4 | import java.util.ArrayList 5 | 6 | /** 7 | * Created by Mohanraj Karatadipalayam on 06/10/18. 8 | */ 9 | interface FlightWorkerInput { 10 | val futureFlights: ArrayList 11 | val pastFlights: ArrayList 12 | } 13 | 14 | class FlightWorker : FlightWorkerInput { 15 | 16 | override val futureFlights: ArrayList 17 | get() { 18 | 19 | val flightsList = ArrayList() 20 | 21 | val flight1 = FlightModel(flightName = "9Z 231", 22 | startingTime = "2018/10/31", 23 | departureCity = "BLR", 24 | arrivalCity = "CJB", 25 | departureTime = "06:00", 26 | arrivalTime = "06:50") 27 | 28 | flightsList.add(flight1) 29 | 30 | val flight2 = FlightModel(flightName = "9Z 15", 31 | startingTime = "2017/02/31", 32 | departureCity = "BLR", 33 | arrivalCity = "CJB", 34 | departureTime = "09:00", 35 | arrivalTime = "09:50") 36 | flightsList.add(flight2) 37 | 38 | val flight3 = FlightModel(flightName = "9Z 142", 39 | startingTime = "2017/12/31", 40 | departureCity = "BLR", 41 | arrivalCity = "CJB", 42 | departureTime = "18:10", 43 | arrivalTime = "19:00") 44 | flightsList.add(flight3) 45 | 46 | return flightsList 47 | } 48 | 49 | override val pastFlights: ArrayList 50 | get() { 51 | 52 | val flightsList = ArrayList() 53 | 54 | val flight1 = FlightModel(flightName = "9Z 231", 55 | startingTime = "2015/10/31", 56 | departureCity = "BLR", 57 | arrivalCity = "CJB", 58 | departureTime = "06:00", 59 | arrivalTime = "06:50") 60 | 61 | flightsList.add(flight1) 62 | 63 | val flight2 = FlightModel(flightName = "9Z 15", 64 | startingTime = "2015/11/31", 65 | departureCity = "BLR", 66 | arrivalCity = "CJB", 67 | departureTime = "09:00", 68 | arrivalTime = "09:50") 69 | flightsList.add(flight2) 70 | 71 | val flight3 = FlightModel(flightName = "9Z 142", 72 | startingTime = "2015/12/31", 73 | departureCity = "BLR", 74 | arrivalCity = "CJB", 75 | departureTime = "18:10", 76 | arrivalTime = "19:00") 77 | flightsList.add(flight3) 78 | 79 | return flightsList 80 | } 81 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/homescreen/HomeConfigurator.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.homescreen 2 | 3 | import java.lang.ref.WeakReference 4 | 5 | /** 6 | * Created by Mohanraj Karatadipalayam on 06/10/18. 7 | */ 8 | 9 | object HomeConfigurator { 10 | 11 | fun configureFragment(fragment: HomeFragment) { 12 | 13 | val router = HomeRouter() 14 | router.fragment = WeakReference(fragment) 15 | 16 | val presenter = HomePresenter() 17 | presenter.output = WeakReference(fragment) 18 | 19 | val interactor = HomeInteractor() 20 | interactor.output = presenter 21 | 22 | fragment.output = interactor 23 | fragment.router = router 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/homescreen/HomeFragment.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.homescreen 2 | 3 | 4 | import android.content.Context 5 | import android.os.Bundle 6 | import android.support.v4.app.Fragment 7 | import android.util.Log 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import android.view.ViewGroup 11 | import android.widget.ListView 12 | import com.example.kotlincleancode4android.FlightViewModel 13 | import com.example.kotlincleancode4android.R 14 | import java.util.ArrayList 15 | 16 | /** 17 | * Created by Mohanraj Karatadipalayam on 08/10/18. 18 | */ 19 | 20 | interface HomeFragmentInput { 21 | fun displayHomeMetaData(viewModel: HomeViewModel) 22 | } 23 | 24 | class HomeFragment : Fragment(), HomeFragmentInput { 25 | 26 | var listOfVMFlights: ArrayList = arrayListOf() 27 | lateinit var output: HomeInteractorInput 28 | lateinit var router: HomeRouter 29 | lateinit var homeFragmentListener: HomeFragmentListener 30 | 31 | 32 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 33 | savedInstanceState: Bundle?): View? { 34 | // Inflate the layout for this fragment 35 | val view = inflater.inflate(R.layout.fragment_home, container, false) 36 | 37 | HomeConfigurator.configureFragment(this) 38 | fetchData() 39 | createFlightListView(view) 40 | 41 | return view 42 | } 43 | 44 | override fun onAttach(context: Context?) { 45 | super.onAttach(context) 46 | // This makes sure that the container activity has implemented 47 | // the callback interface. If not, it throws an exception 48 | try { 49 | homeFragmentListener = activity as HomeFragmentListener 50 | } catch (e: ClassCastException) { 51 | throw ClassCastException(activity!!.toString() + " must implement HomeFragmentListener") 52 | } 53 | } 54 | 55 | fun fetchData() { 56 | // create Request and set the needed input 57 | val homeRequest = HomeRequest() 58 | homeRequest.isFutureTrips = true 59 | // Call the output to fetch the data 60 | output.fetchHomeData(homeRequest) 61 | } 62 | 63 | private fun createFlightListView(view: View) { 64 | val listView = view.findViewById(R.id.listOfFlights) 65 | listView.adapter = FlightListAdapter(this.requireContext(),listOfVMFlights) 66 | listView.isClickable = true 67 | listView.onItemClickListener = router 68 | } 69 | 70 | override fun displayHomeMetaData(viewModel: HomeViewModel) { 71 | Log.d(HomeFragment.TAG, "displayHomeMetaData() called with: viewModel = [$viewModel]") 72 | listOfVMFlights = viewModel.listOfFlights!! 73 | } 74 | 75 | companion object { 76 | const val TAG = "HomeFragment" 77 | } 78 | } 79 | 80 | interface HomeFragmentListener{ 81 | fun startPastTripFragment(fragment: Fragment) 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/homescreen/HomeInteractor.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.homescreen 2 | 3 | import android.util.Log 4 | import com.example.kotlincleancode4android.ArrayEmptyException 5 | 6 | /** 7 | * Created by Mohanraj Karatadipalayam on 06/10/18. 8 | */ 9 | 10 | interface HomeInteractorInput { 11 | fun fetchHomeData(request: HomeRequest) 12 | } 13 | 14 | class HomeInteractor : HomeInteractorInput { 15 | 16 | var output: HomePresenterInput? = null 17 | var flightWorkerInput: FlightWorkerInput? = null 18 | get() { return field ?: FlightWorker()} 19 | 20 | 21 | override fun fetchHomeData(request: HomeRequest) { 22 | Log.d(TAG, "In method fetchHomeData") 23 | val homeResponse = HomeResponse() 24 | if (request.isFutureTrips) { 25 | homeResponse.listOfFlights = flightWorkerInput?.futureFlights 26 | } else { 27 | homeResponse.listOfFlights = flightWorkerInput?.pastFlights 28 | } 29 | //TODO : Add failure case here 30 | if (null == homeResponse.listOfFlights || homeResponse.listOfFlights!!.isEmpty()) { 31 | throw ArrayEmptyException("Empty Flight List") 32 | } 33 | 34 | output?.presentHomeMetaData(homeResponse) 35 | } 36 | 37 | companion object { 38 | const val TAG = "HomeInteractor" 39 | } 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/homescreen/HomeModels.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.homescreen 2 | 3 | import com.example.kotlincleancode4android.FlightModel 4 | import com.example.kotlincleancode4android.FlightViewModel 5 | import java.util.ArrayList 6 | 7 | /** 8 | * Created by Mohanraj Karatadipalayam on 06/10/18. 9 | */ 10 | data class HomeViewModel( 11 | // TODO - filter to have only the needed data 12 | var listOfFlights: ArrayList? = null 13 | ) 14 | data class HomeRequest( var isFutureTrips: Boolean = false) 15 | data class HomeResponse(var listOfFlights: ArrayList? = null) 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/homescreen/HomePresenter.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.homescreen 2 | 3 | import android.util.Log 4 | import com.example.kotlincleancode4android.FlightViewModel 5 | import java.lang.ref.WeakReference 6 | import java.util.Calendar 7 | import java.util.concurrent.TimeUnit 8 | 9 | /** 10 | * Created by Mohanraj Karatadipalayam on 06/10/18. 11 | */ 12 | interface HomePresenterInput { 13 | fun presentHomeMetaData(response: HomeResponse) 14 | } 15 | 16 | class HomePresenter : HomePresenterInput { 17 | 18 | var output: WeakReference? = null 19 | var currentTime: Calendar? = null 20 | get() = if (field == null) Calendar.getInstance() else field 21 | 22 | override fun presentHomeMetaData(response: HomeResponse) { 23 | Log.d(TAG, "presentHomeMetaData() called with: response = [$response]"); 24 | // Do your decoration or filtering here 25 | val homeViewModel = HomeViewModel() 26 | homeViewModel.listOfFlights = ArrayList() 27 | 28 | if (response.listOfFlights != null) { 29 | 30 | for (fm in response.listOfFlights!!) { 31 | val fvm = FlightViewModel(noOfDaysToFly = null, 32 | departureCity = fm.departureCity, 33 | arrivalCity = fm.arrivalCity, 34 | flightName = fm.flightName, 35 | startingTime = fm.startingTime, 36 | departureTime = fm.departureTime, 37 | arrivalTime = fm.arrivalTime) 38 | 39 | // Decoration 40 | val startingTime = getCalendar(fvm.startingTime) 41 | startingTime?.let { 42 | val startTime = it 43 | currentTime?.let { 44 | val daysDiff = getDaysDiff(it.timeInMillis, startTime.timeInMillis) 45 | setDaysFlyDecorationText(fvm, daysDiff, it.timeInMillis, startTime.timeInMillis) 46 | } 47 | } 48 | homeViewModel.listOfFlights?.add(fvm) 49 | } 50 | output?.get()?.displayHomeMetaData(homeViewModel) 51 | } 52 | } 53 | 54 | private fun setDaysFlyDecorationText(fvm: FlightViewModel, daysDiff: Long, startTime: Long, endTime: Long) { 55 | if (endTime > startTime) { 56 | fvm.noOfDaysToFly = "You have $daysDiff days to fly" 57 | } else { 58 | // daysDiff =-daysDiff; 59 | fvm.noOfDaysToFly = "It has been $daysDiff days since you flew" 60 | } 61 | } 62 | 63 | private fun getCalendar(date: String?): Calendar? { 64 | // Date should be in the format YYYY/MM/DD if not return 65 | if (date != null && !date.isEmpty() && date.length == 10) { 66 | val year = Integer.parseInt(date.substring(0, 4)) 67 | val month = Integer.parseInt(date.substring(5, 7)) 68 | val day = Integer.parseInt(date.substring(8, 10)) 69 | val startingTime = Calendar.getInstance() 70 | startingTime.set(year, month - 1, day, 0, 0, 0) 71 | return startingTime 72 | } 73 | return null 74 | } 75 | 76 | private fun getDaysDiff(startTime: Long, endTime: Long): Long { 77 | val msDiff: Long = if (endTime > startTime) { 78 | endTime - startTime 79 | } else { 80 | startTime - endTime 81 | } 82 | val daysDiff = TimeUnit.MILLISECONDS.toDays(msDiff) 83 | Log.d(TAG, "diff is $daysDiff") 84 | return daysDiff 85 | } 86 | 87 | companion object { 88 | const val TAG = "HomePresenter" 89 | } 90 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/homescreen/HomeRouter.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.homescreen 2 | 3 | 4 | import android.os.Bundle 5 | import android.support.v4.app.Fragment 6 | import android.util.Log 7 | import android.view.View 8 | import android.widget.AdapterView 9 | import com.example.kotlincleancode4android.CalendarUtil 10 | import com.example.kotlincleancode4android.pastTripScreen.PastTripFragment 11 | import java.lang.ref.WeakReference 12 | import java.util.Calendar 13 | 14 | /** 15 | * Created by Mohanraj Karatadipalayam on 06/10/18. 16 | */ 17 | 18 | internal interface HomeRouterInput { 19 | fun determineNextScreen(position: Int): Fragment 20 | fun passDataToNextScene(position: Int, nextFragment: Fragment) 21 | } 22 | 23 | class HomeRouter : HomeRouterInput, AdapterView.OnItemClickListener { 24 | var fragment: WeakReference? = null 25 | var currentTime: Calendar? = null 26 | get() = if (field == null) Calendar.getInstance() else field 27 | 28 | 29 | override fun determineNextScreen(position: Int): Fragment { 30 | // Based on the position or some other data decide what is the next scene 31 | 32 | val flight = fragment?.get()?.listOfVMFlights?.get(position) 33 | val startingTime = CalendarUtil.getCalendar(flight?.startingTime) 34 | 35 | return if (isFutureFlight(startingTime)) { 36 | // Intent(activity!!.get(), BoardingActivity::class.java) 37 | HomeFragment() 38 | } else { 39 | // Intent(activity!!.get(), PastTripFragment::class.java) 40 | PastTripFragment() 41 | } 42 | } 43 | 44 | override fun passDataToNextScene(position: Int, nextFragment: Fragment) { 45 | // Based on the position or some other data decide the data for the next scene 46 | val flight = fragment?.get()?.listOfVMFlights?.get(position) 47 | val args = Bundle() 48 | args.putParcelable("flight",flight) 49 | nextFragment.arguments = args 50 | } 51 | 52 | override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) { 53 | Log.d(TAG, "onItemClick() called with: parent = [$parent], view = [$view], position = [$position], id = [$id]"); 54 | val nextFragment = determineNextScreen(position) 55 | passDataToNextScene(position, nextFragment) 56 | fragment?.get()?.homeFragmentListener?.startPastTripFragment(nextFragment) 57 | // TODO - Decide should we start the fragment from here or from the activity ? 58 | } 59 | 60 | private fun isFutureFlight(startingTime: Calendar): Boolean { 61 | val startTimeInMills = startingTime.timeInMillis 62 | val currentTimeInMills = currentTime?.timeInMillis 63 | currentTimeInMills?.let { 64 | return startTimeInMills >= currentTimeInMills 65 | } 66 | return false 67 | } 68 | 69 | companion object { 70 | const val TAG = "HomeRouter" 71 | } 72 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/homescreen/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Mohanraj Karatadipalayam on 06/10/18. 3 | */ 4 | 5 | package com.example.kotlincleancode4android.homescreen 6 | 7 | import android.os.Bundle 8 | import android.support.v4.app.Fragment 9 | import android.support.v7.app.AppCompatActivity 10 | import com.example.kotlincleancode4android.R 11 | import com.example.kotlincleancode4android.transact 12 | 13 | 14 | class MainActivity : AppCompatActivity(),HomeFragmentListener { 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | setContentView(R.layout.activity_main) 19 | supportActionBar?.hide() 20 | showFragment(HomeFragment()) 21 | } 22 | 23 | private fun showFragment(fragment: Fragment) { 24 | transact { 25 | replace(R.id.container, fragment) 26 | setCustomAnimations(R.anim.abc_fade_in, R.anim.abc_fade_out) 27 | } 28 | } 29 | 30 | override fun startPastTripFragment(fragment: Fragment) { 31 | showFragment(fragment) 32 | } 33 | 34 | companion object { 35 | const val TAG = "MainActivity" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/kotlincleancode4android/pastTripScreen/PastTripFragment.kt: -------------------------------------------------------------------------------- 1 | package com.example.kotlincleancode4android.pastTripScreen 2 | 3 | import android.os.Bundle 4 | import android.support.v4.app.Fragment 5 | import android.util.Log 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import android.widget.TextView 10 | import com.example.kotlincleancode4android.FlightModel 11 | import com.example.kotlincleancode4android.R 12 | 13 | class PastTripFragment : Fragment() { 14 | 15 | private var flightModel: FlightModel? = null 16 | 17 | private var passengerName: TextView? = null 18 | private var departureCity: TextView? = null 19 | private var arrivalCity: TextView? = null 20 | private var boardingTime: TextView? = null 21 | private var departureTime: TextView? = null 22 | private var arrivalTime: TextView? = null 23 | 24 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 25 | savedInstanceState: Bundle?): View? { 26 | // Inflate the layout for this fragment 27 | val view = inflater.inflate(R.layout.fragment_past_trip, container, false) 28 | flightModel = this.arguments?.getParcelable("flight") 29 | bindViews(view) 30 | displayTripData(flightModel) 31 | return view 32 | } 33 | 34 | private fun bindViews(view: View) { 35 | passengerName = view.findViewById(R.id.tv_passengerName) 36 | departureCity = view.findViewById(R.id.tv_departureAirport) 37 | arrivalCity = view.findViewById(R.id.tv_arrivalAirport) 38 | boardingTime = view.findViewById(R.id.tv_boardingTime) 39 | departureTime = view.findViewById(R.id.tv_departureTime) 40 | arrivalTime = view.findViewById(R.id.tv_arrivalTime) 41 | } 42 | 43 | private fun displayTripData(fightModel: FlightModel?) { 44 | Log.e(TAG, "displayBoardingData() called with: viewModel = [$fightModel]") 45 | // Deal with the data 46 | passengerName?.text = "Mr. Mohan Karats" 47 | // mFlightCode.setText(flightModel.flightName); 48 | arrivalCity?.text = flightModel?.arrivalCity 49 | arrivalTime?.text = flightModel?.arrivalTime 50 | departureCity?.text = flightModel?.departureCity 51 | departureTime?.text = flightModel?.departureTime 52 | } 53 | 54 | companion object { 55 | const val TAG = "PastTripFragment" 56 | } 57 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_plan_landing.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_plan_takeoff.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/shape_rectangle_fill_light.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/shape_rectangle_stroke.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_boarding.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 24 | 25 | 36 | 37 | 47 | 48 | 59 | 60 | 71 | 72 | 84 | 85 | 95 | 96 | 106 | 107 | 118 | 119 | 130 | 131 | 142 | 143 | 155 | 156 | 157 | 158 | 168 | 169 | 178 | 179 | 189 | 190 | 191 | 200 | 201 | 211 | 212 | 223 | 224 | 234 | 235 | 247 | 260 | 261 | 277 | 278 | 289 | 290 | 301 | 302 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_past_trip.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 20 | 21 | 32 | 33 | 44 | 45 | 56 | 57 | 67 | 68 | 78 | 79 | 92 | 93 | 106 | 107 | 119 | 120 | 132 | 133 | 144 | 145 | 156 | 157 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /app/src/main/res/layout/cell_trip_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 26 | 27 | 39 | 40 | 57 | 58 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_past_trip.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 20 | 21 | 32 | 33 | 44 | 45 | 56 | 57 | 67 | 68 | 78 | 79 | 92 | 93 | 106 | 107 | 119 | 120 | 132 | 133 | 144 | 145 | 156 | 157 | 168 | 169 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmmraj/KotlinCleanCode4Android/c2446d21576bfa079a1b5ff8a1bbd5bb038fda13/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmmraj/KotlinCleanCode4Android/c2446d21576bfa079a1b5ff8a1bbd5bb038fda13/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmmraj/KotlinCleanCode4Android/c2446d21576bfa079a1b5ff8a1bbd5bb038fda13/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmmraj/KotlinCleanCode4Android/c2446d21576bfa079a1b5ff8a1bbd5bb038fda13/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmmraj/KotlinCleanCode4Android/c2446d21576bfa079a1b5ff8a1bbd5bb038fda13/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmmraj/KotlinCleanCode4Android/c2446d21576bfa079a1b5ff8a1bbd5bb038fda13/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmmraj/KotlinCleanCode4Android/c2446d21576bfa079a1b5ff8a1bbd5bb038fda13/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmmraj/KotlinCleanCode4Android/c2446d21576bfa079a1b5ff8a1bbd5bb038fda13/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmmraj/KotlinCleanCode4Android/c2446d21576bfa079a1b5ff8a1bbd5bb038fda13/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmmraj/KotlinCleanCode4Android/c2446d21576bfa079a1b5ff8a1bbd5bb038fda13/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #3f51b5 5 | #303f9f 6 | #FF4081 7 | #807F80 8 | #80ff0000 9 | #3FBAEB 10 | 11 | #7986CB 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | KotlinCleanCode4Android 3 | Trip Detail 4 | PASSENGER 5 | MR. MOHAN KARATS 6 | BLR 7 | CJB 8 | 9F 2465 9 | BOARDING TIME 10 | 02:10 PM 11 | DEPARTURE 12 | 02:40 PM 13 | 03:10 PM 14 | ARRIVAL 15 | 00:15 16 | BOARDING IN 17 | TERMINAL 18 | GATE 19 | SEAT 20 | 1 21 | 6A 22 | 01A 23 | DEPARTURE DATE 24 | 2018 Jan 15 25 | Depature Airport Code 26 | Arrival Airport Code 27 | To Airport 28 | FLIGHT 29 | PNR 30 | Z1Y2X3 31 | Flight Image 32 | Image 33 | Image Departure City 34 | Image Arrival City 35 | Image Email Button 36 | Image Take Off 37 | Image Plane Landing 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 |