├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── colors.xml │ │ │ │ └── styles.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 │ │ │ ├── layout │ │ │ │ ├── activity_step4.xml │ │ │ │ ├── activity_step5.xml │ │ │ │ ├── activity_step6.xml │ │ │ │ ├── activity_step7.xml │ │ │ │ ├── activity_step8.xml │ │ │ │ ├── activity_step9.xml │ │ │ │ ├── step6_second_fragment.xml │ │ │ │ ├── step6_first_fragment.xml │ │ │ │ ├── step7_profile_fragment.xml │ │ │ │ ├── step9_profile_fragment.xml │ │ │ │ ├── activity_step1.xml │ │ │ │ ├── activity_step2.xml │ │ │ │ ├── step8_main_fragment.xml │ │ │ │ ├── step5_first_fragment.xml │ │ │ │ ├── step4_first_view.xml │ │ │ │ ├── step8_form_fragment.xml │ │ │ │ ├── step5_second_fragment.xml │ │ │ │ ├── step7_enter_profile_data_fragment.xml │ │ │ │ ├── step9_enter_profile_data_fragment.xml │ │ │ │ ├── step4_second_view.xml │ │ │ │ ├── step7_create_login_credentials_fragment.xml │ │ │ │ ├── step9_create_login_credentials_fragment.xml │ │ │ │ ├── step7_login_fragment.xml │ │ │ │ ├── step9_login_fragment.xml │ │ │ │ ├── activity_step3.xml │ │ │ │ └── activity_main.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── anim │ │ │ │ ├── slide_out_to_left.xml │ │ │ │ ├── slide_out_to_right.xml │ │ │ │ ├── slide_in_from_left.xml │ │ │ │ └── slide_in_from_right.xml │ │ │ ├── drawable │ │ │ │ ├── ic_arrow_back_black_24dp.xml │ │ │ │ ├── ic_tag_faces_black_24dp.xml │ │ │ │ └── ic_launcher_background.xml │ │ │ └── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── zhuinden │ │ │ │ └── simplestacktutorials │ │ │ │ ├── steps │ │ │ │ ├── step_3 │ │ │ │ │ ├── Step3ButtonConfiguration.kt │ │ │ │ │ ├── Step3Screen.kt │ │ │ │ │ ├── Step3SecondScreen.kt │ │ │ │ │ ├── Step3FirstScreen.kt │ │ │ │ │ └── Step3Activity.kt │ │ │ │ ├── step_5 │ │ │ │ │ ├── Step5BaseFragment.kt │ │ │ │ │ ├── Step5Utils.kt │ │ │ │ │ ├── Step5FirstScreen.kt │ │ │ │ │ ├── Step5SecondScreen.kt │ │ │ │ │ ├── Step5Screen.kt │ │ │ │ │ ├── Step5FirstFragment.kt │ │ │ │ │ ├── Step5SecondFragment.kt │ │ │ │ │ ├── Step5Activity.kt │ │ │ │ │ └── FragmentStateChanger.java │ │ │ │ ├── step_6 │ │ │ │ │ ├── Step6BaseFragment.kt │ │ │ │ │ ├── Step6Utils.kt │ │ │ │ │ ├── Step6FirstScreen.kt │ │ │ │ │ ├── Step6SecondScreen.kt │ │ │ │ │ ├── Step6Screen.kt │ │ │ │ │ ├── Step6SecondFragment.kt │ │ │ │ │ ├── Step6FirstFragment.kt │ │ │ │ │ ├── Step6Activity.kt │ │ │ │ │ └── FragmentStateChanger.java │ │ │ │ ├── step_4 │ │ │ │ │ ├── Step4Utils.kt │ │ │ │ │ ├── Step4FirstScreen.kt │ │ │ │ │ ├── Step4SecondScreen.kt │ │ │ │ │ ├── Step4Screen.kt │ │ │ │ │ ├── Step4FirstView.kt │ │ │ │ │ ├── Step4Activity.kt │ │ │ │ │ └── Step4SecondView.kt │ │ │ │ ├── step_7 │ │ │ │ │ ├── core │ │ │ │ │ │ ├── navigation │ │ │ │ │ │ │ ├── BaseFragment.kt │ │ │ │ │ │ │ ├── NavUtils.kt │ │ │ │ │ │ │ ├── FragmentKey.kt │ │ │ │ │ │ │ └── FragmentStateChanger.java │ │ │ │ │ │ └── viewmodels │ │ │ │ │ │ │ ├── HasServices.kt │ │ │ │ │ │ │ └── ViewModelUtils.kt │ │ │ │ │ ├── features │ │ │ │ │ │ ├── registration │ │ │ │ │ │ │ ├── EnterProfileDataKey.kt │ │ │ │ │ │ │ ├── CreateLoginCredentialsKey.kt │ │ │ │ │ │ │ ├── EnterProfileDataFragment.kt │ │ │ │ │ │ │ ├── CreateLoginCredentialsFragment.kt │ │ │ │ │ │ │ └── RegistrationViewModel.kt │ │ │ │ │ │ ├── login │ │ │ │ │ │ │ ├── LoginKey.kt │ │ │ │ │ │ │ ├── LoginViewModel.kt │ │ │ │ │ │ │ └── LoginFragment.kt │ │ │ │ │ │ └── profile │ │ │ │ │ │ │ ├── ProfileKey.kt │ │ │ │ │ │ │ ├── ProfileFragment.kt │ │ │ │ │ │ │ └── ProfileViewModel.kt │ │ │ │ │ ├── AuthenticationManager.kt │ │ │ │ │ ├── ServiceProvider.kt │ │ │ │ │ └── Step7Activity.kt │ │ │ │ ├── step_9 │ │ │ │ │ ├── utils │ │ │ │ │ │ └── RxRelayUtils.kt │ │ │ │ │ ├── core │ │ │ │ │ │ ├── navigation │ │ │ │ │ │ │ ├── NavUtils.kt │ │ │ │ │ │ │ ├── BaseFragment.kt │ │ │ │ │ │ │ ├── FragmentKey.kt │ │ │ │ │ │ │ └── FragmentStateChanger.java │ │ │ │ │ │ └── viewmodels │ │ │ │ │ │ │ ├── HasServices.kt │ │ │ │ │ │ │ └── ViewModelUtils.kt │ │ │ │ │ ├── features │ │ │ │ │ │ ├── registration │ │ │ │ │ │ │ ├── EnterProfileDataKey.kt │ │ │ │ │ │ │ ├── CreateLoginCredentialsKey.kt │ │ │ │ │ │ │ ├── EnterProfileDataFragment.kt │ │ │ │ │ │ │ ├── CreateLoginCredentialsFragment.kt │ │ │ │ │ │ │ └── RegistrationViewModel.kt │ │ │ │ │ │ ├── profile │ │ │ │ │ │ │ ├── ProfileFragment.kt │ │ │ │ │ │ │ ├── ProfileKey.kt │ │ │ │ │ │ │ └── ProfileViewModel.kt │ │ │ │ │ │ └── login │ │ │ │ │ │ │ ├── LoginKey.kt │ │ │ │ │ │ │ ├── LoginFragment.kt │ │ │ │ │ │ │ └── LoginViewModel.kt │ │ │ │ │ ├── AuthenticationManager.kt │ │ │ │ │ ├── ServiceProvider.kt │ │ │ │ │ └── Step9Activity.kt │ │ │ │ ├── step_8 │ │ │ │ │ ├── core │ │ │ │ │ │ ├── navigation │ │ │ │ │ │ │ ├── NavUtils.kt │ │ │ │ │ │ │ ├── BaseFragment.kt │ │ │ │ │ │ │ ├── FragmentKey.kt │ │ │ │ │ │ │ └── FragmentStateChanger.java │ │ │ │ │ │ └── viewmodels │ │ │ │ │ │ │ ├── HasServices.kt │ │ │ │ │ │ │ ├── ServiceProvider.kt │ │ │ │ │ │ │ └── ViewModelUtils.kt │ │ │ │ │ ├── features │ │ │ │ │ │ ├── main │ │ │ │ │ │ │ ├── MainViewModel.kt │ │ │ │ │ │ │ ├── MainFragment.kt │ │ │ │ │ │ │ └── MainKey.kt │ │ │ │ │ │ └── form │ │ │ │ │ │ │ ├── FormKey.kt │ │ │ │ │ │ │ ├── FormViewModel.kt │ │ │ │ │ │ │ └── FormFragment.kt │ │ │ │ │ └── Step8Activity.kt │ │ │ │ ├── step_2 │ │ │ │ │ └── Step2Activity.kt │ │ │ │ └── step_1 │ │ │ │ │ └── Step1Activity.kt │ │ │ │ ├── utils │ │ │ │ └── Utils.kt │ │ │ │ └── app │ │ │ │ └── MainActivity.kt │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── zhuinden │ │ │ └── simplestacktutorials │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── zhuinden │ │ └── simplestacktutorials │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .idea ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── encodings.xml ├── vcs.xml ├── runConfigurations.xml ├── gradle.xml └── misc.xml ├── .gitignore ├── gradle.properties ├── gradlew.bat ├── README.md └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | rootProject.name='SimpleStackTutorials' 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SimpleStackTutorials 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuinden/simple-stack-tutorials/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuinden/simple-stack-tutorials/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuinden/simple-stack-tutorials/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuinden/simple-stack-tutorials/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuinden/simple-stack-tutorials/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuinden/simple-stack-tutorials/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuinden/simple-stack-tutorials/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuinden/simple-stack-tutorials/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuinden/simple-stack-tutorials/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuinden/simple-stack-tutorials/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zhuinden/simple-stack-tutorials/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jan 15 00:57:59 CET 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_3/Step3ButtonConfiguration.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_3 2 | 3 | import android.view.View 4 | 5 | data class Step3ButtonConfiguration( 6 | val buttonText: String, 7 | val buttonAction: (View) -> Unit 8 | ) -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_step4.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_step5.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_step6.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_step7.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_step8.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_step9.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /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/java/com/zhuinden/simplestacktutorials/steps/step_5/Step5BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_5 2 | 3 | import androidx.fragment.app.Fragment 4 | 5 | abstract class Step5BaseFragment : Fragment() { 6 | fun getScreen(): T = requireArguments().getParcelable("FRAGMENT_KEY")!! 7 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_6/Step6BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_6 2 | 3 | import androidx.fragment.app.Fragment 4 | 5 | abstract class Step6BaseFragment : Fragment() { 6 | fun getScreen(): T = requireArguments().getParcelable("FRAGMENT_KEY")!! 7 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_4/Step4Utils.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_4 2 | 3 | import android.view.View 4 | import com.zhuinden.simplestack.Backstack 5 | import com.zhuinden.simplestack.navigator.Navigator 6 | 7 | val View.backstack: Backstack 8 | get() = Navigator.getBackstack(context) -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_out_to_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_out_to_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_from_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_from_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_7/core/navigation/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_7.core.navigation 2 | 3 | import androidx.fragment.app.Fragment 4 | 5 | abstract class BaseFragment : Fragment() { 6 | fun getScreen(): T = requireArguments().getParcelable("FRAGMENT_KEY")!! 7 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_5/Step5Utils.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_5 2 | 3 | import androidx.fragment.app.Fragment 4 | import com.zhuinden.simplestack.Backstack 5 | import com.zhuinden.simplestack.navigator.Navigator 6 | 7 | val Fragment.backstack: Backstack 8 | get() = Navigator.getBackstack(requireContext()) -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_6/Step6Utils.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_6 2 | 3 | import androidx.fragment.app.Fragment 4 | import com.zhuinden.simplestack.Backstack 5 | import com.zhuinden.simplestack.navigator.Navigator 6 | 7 | val Fragment.backstack: Backstack 8 | get() = Navigator.getBackstack(requireContext()) -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_3/Step3Screen.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_3 2 | 3 | import android.os.Parcelable 4 | 5 | abstract class Step3Screen : Parcelable { 6 | abstract val titleText: String 7 | 8 | abstract val centerText: String 9 | 10 | abstract val buttonConfiguration: Step3ButtonConfiguration? 11 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_9/utils/RxRelayUtils.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_9.utils 2 | 3 | import com.jakewharton.rxrelay2.BehaviorRelay 4 | 5 | fun BehaviorRelay.get(): T = value!! 6 | 7 | fun BehaviorRelay.getOrNull(): T? = value 8 | 9 | fun BehaviorRelay.set(value: T) { 10 | this.accept(value) 11 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_7/core/navigation/NavUtils.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_7.core.navigation 2 | 3 | import androidx.fragment.app.Fragment 4 | import com.zhuinden.simplestack.Backstack 5 | import com.zhuinden.simplestack.navigator.Navigator 6 | 7 | val Fragment.backstack: Backstack 8 | get() = Navigator.getBackstack(requireContext()) -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_8/core/navigation/NavUtils.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_8.core.navigation 2 | 3 | import androidx.fragment.app.Fragment 4 | import com.zhuinden.simplestack.Backstack 5 | import com.zhuinden.simplestack.navigator.Navigator 6 | 7 | val Fragment.backstack: Backstack 8 | get() = Navigator.getBackstack(requireContext()) -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_9/core/navigation/NavUtils.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_9.core.navigation 2 | 3 | import androidx.fragment.app.Fragment 4 | import com.zhuinden.simplestack.Backstack 5 | import com.zhuinden.simplestack.navigator.Navigator 6 | 7 | val Fragment.backstack: Backstack 8 | get() = Navigator.getBackstack(requireContext()) -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_6/Step6FirstScreen.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_6 2 | 3 | import androidx.fragment.app.Fragment 4 | import kotlinx.android.parcel.Parcelize 5 | 6 | @Parcelize 7 | data class Step6FirstScreen(private val placeholder: String = "") : Step6Screen() { 8 | override fun instantiateFragment(): Fragment = Step6FirstFragment() 9 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_6/Step6SecondScreen.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_6 2 | 3 | import androidx.fragment.app.Fragment 4 | import kotlinx.android.parcel.Parcelize 5 | 6 | @Parcelize 7 | data class Step6SecondScreen(private val placeholder: String = "") : Step6Screen() { 8 | override fun instantiateFragment(): Fragment = Step6SecondFragment() 9 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_back_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_4/Step4FirstScreen.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_4 2 | 3 | import com.zhuinden.simplestacktutorials.R 4 | import kotlinx.android.parcel.Parcelize 5 | 6 | @Parcelize 7 | data class Step4FirstScreen(private val placeholder: String = "") : Step4Screen() { // generate equals/hashCode/toString 8 | override fun layout(): Int = R.layout.step4_first_view 9 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_7/core/viewmodels/HasServices.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_7.core.viewmodels 2 | 3 | import com.zhuinden.simplestack.ScopeKey 4 | import com.zhuinden.simplestack.ServiceBinder 5 | 6 | interface HasServices: ScopeKey { 7 | fun bindServices(serviceBinder: ServiceBinder) 8 | 9 | override fun getScopeTag(): String = javaClass.name 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_8/core/viewmodels/HasServices.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_8.core.viewmodels 2 | 3 | import com.zhuinden.simplestack.ScopeKey 4 | import com.zhuinden.simplestack.ServiceBinder 5 | 6 | interface HasServices: ScopeKey { 7 | fun bindServices(serviceBinder: ServiceBinder) 8 | 9 | override fun getScopeTag(): String = javaClass.name 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_9/core/navigation/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_9.core.navigation 2 | 3 | import androidx.annotation.LayoutRes 4 | import androidx.fragment.app.Fragment 5 | 6 | abstract class BaseFragment(@LayoutRes layoutId: Int) : Fragment(layoutId) { 7 | fun getScreen(): T = requireArguments().getParcelable("FRAGMENT_KEY")!! 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_9/core/viewmodels/HasServices.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_9.core.viewmodels 2 | 3 | import com.zhuinden.simplestack.ScopeKey 4 | import com.zhuinden.simplestack.ServiceBinder 5 | 6 | interface HasServices : ScopeKey { 7 | fun bindServices(serviceBinder: ServiceBinder) 8 | 9 | override fun getScopeTag(): String = javaClass.name 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_8/core/navigation/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_8.core.navigation 2 | 3 | import androidx.annotation.LayoutRes 4 | import androidx.fragment.app.Fragment 5 | 6 | abstract class BaseFragment(@LayoutRes layoutRes: Int) : Fragment(layoutRes) { 7 | fun getScreen(): T = requireArguments().getParcelable("FRAGMENT_KEY")!! 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_4/Step4SecondScreen.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_4 2 | 3 | import com.zhuinden.simplestacktutorials.R 4 | import kotlinx.android.parcel.Parcelize 5 | 6 | @Parcelize 7 | data class Step4SecondScreen(private val placeholder: String = "") : 8 | Step4Screen() { // generate equals/hashCode/toString 9 | override fun layout(): Int = R.layout.step4_second_view 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_5/Step5FirstScreen.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_5 2 | 3 | import androidx.fragment.app.Fragment 4 | import kotlinx.android.parcel.Parcelize 5 | 6 | @Parcelize 7 | data class Step5FirstScreen(private val placeholder: String = "") : 8 | Step5Screen() { // generate equals/hashCode/toString 9 | override fun instantiateFragment(): Fragment = Step5FirstFragment() 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_5/Step5SecondScreen.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_5 2 | 3 | import androidx.fragment.app.Fragment 4 | import kotlinx.android.parcel.Parcelize 5 | 6 | @Parcelize 7 | data class Step5SecondScreen(private val placeholder: String = "") : 8 | Step5Screen() { // generate equals/hashCode/toString 9 | override fun instantiateFragment(): Fragment = Step5SecondFragment() 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_3/Step3SecondScreen.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_3 2 | 3 | import kotlinx.android.parcel.Parcelize 4 | 5 | @Parcelize 6 | class Step3SecondScreen : Step3Screen() { 7 | override val titleText: String 8 | get() = "Second title" 9 | override val centerText: String 10 | get() = "Second screen" 11 | override val buttonConfiguration: Step3ButtonConfiguration? 12 | get() = null 13 | } -------------------------------------------------------------------------------- /app/src/test/java/com/zhuinden/simplestacktutorials/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_4/Step4Screen.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_4 2 | 3 | import android.os.Parcelable 4 | import com.zhuinden.simplestack.navigator.DefaultViewKey 5 | import com.zhuinden.simplestack.navigator.ViewChangeHandler 6 | import com.zhuinden.simplestack.navigator.changehandlers.SegueViewChangeHandler 7 | 8 | abstract class Step4Screen : DefaultViewKey, Parcelable { 9 | override fun viewChangeHandler(): ViewChangeHandler = SegueViewChangeHandler() 10 | } -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_5/Step5Screen.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_5 2 | 3 | import android.os.Bundle 4 | import android.os.Parcelable 5 | import androidx.fragment.app.Fragment 6 | 7 | abstract class Step5Screen : Parcelable { 8 | open val fragmentTag: String 9 | get() = toString() 10 | 11 | protected abstract fun instantiateFragment(): Fragment 12 | 13 | fun createFragment(): Fragment = instantiateFragment().apply { 14 | arguments = (arguments ?: Bundle()).also { bundle -> 15 | bundle.putParcelable("FRAGMENT_KEY", this@Step5Screen) 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_6/Step6Screen.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_6 2 | 3 | import android.os.Bundle 4 | import android.os.Parcelable 5 | import androidx.fragment.app.Fragment 6 | 7 | abstract class Step6Screen : Parcelable { 8 | open val fragmentTag: String 9 | get() = toString() 10 | 11 | protected abstract fun instantiateFragment(): Fragment 12 | 13 | fun createFragment(): Fragment = instantiateFragment().apply { 14 | arguments = (arguments ?: Bundle()).also { bundle -> 15 | bundle.putParcelable("FRAGMENT_KEY", this@Step6Screen) 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_3/Step3FirstScreen.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_3 2 | 3 | import com.zhuinden.simplestack.navigator.Navigator 4 | import kotlinx.android.parcel.Parcelize 5 | 6 | @Parcelize 7 | class Step3FirstScreen : Step3Screen() { 8 | override val titleText: String 9 | get() = "First title" 10 | override val centerText: String 11 | get() = "First screen" 12 | override val buttonConfiguration: Step3ButtonConfiguration? 13 | get() = Step3ButtonConfiguration("Navigate forward") { view -> 14 | Navigator.getBackstack(view.context).goTo(Step3SecondScreen()) 15 | } 16 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_7/features/registration/EnterProfileDataKey.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_7.features.registration 2 | 3 | import androidx.fragment.app.Fragment 4 | import com.zhuinden.simplestack.ScopeKey 5 | import com.zhuinden.simplestacktutorials.steps.step_7.core.navigation.FragmentKey 6 | import kotlinx.android.parcel.Parcelize 7 | 8 | @Parcelize 9 | data class EnterProfileDataKey(private val placeholder: String = ""): FragmentKey(), ScopeKey.Child { 10 | override fun instantiateFragment(): Fragment = EnterProfileDataFragment() 11 | 12 | override fun getParentScopes(): List = listOf("registration") 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_9/features/registration/EnterProfileDataKey.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_9.features.registration 2 | 3 | import androidx.fragment.app.Fragment 4 | import com.zhuinden.simplestack.ScopeKey 5 | import com.zhuinden.simplestacktutorials.steps.step_9.core.navigation.FragmentKey 6 | import kotlinx.android.parcel.Parcelize 7 | 8 | @Parcelize 9 | data class EnterProfileDataKey(private val placeholder: String = "") : FragmentKey(), ScopeKey.Child { 10 | override fun instantiateFragment(): Fragment = EnterProfileDataFragment() 11 | 12 | override fun getParentScopes(): List = listOf("registration") 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_7/core/navigation/FragmentKey.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_7.core.navigation 2 | 3 | import android.os.Bundle 4 | import android.os.Parcelable 5 | import androidx.fragment.app.Fragment 6 | 7 | abstract class FragmentKey: Parcelable { 8 | open val fragmentTag: String 9 | get() = toString() 10 | 11 | protected abstract fun instantiateFragment(): Fragment 12 | 13 | fun createFragment(): Fragment = instantiateFragment().apply { 14 | arguments = (arguments ?: Bundle()).also { bundle -> 15 | bundle.putParcelable("FRAGMENT_KEY", this@FragmentKey) 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_8/core/navigation/FragmentKey.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_8.core.navigation 2 | 3 | import android.os.Bundle 4 | import android.os.Parcelable 5 | import androidx.fragment.app.Fragment 6 | 7 | abstract class FragmentKey: Parcelable { 8 | open val fragmentTag: String 9 | get() = toString() 10 | 11 | protected abstract fun instantiateFragment(): Fragment 12 | 13 | fun createFragment(): Fragment = instantiateFragment().apply { 14 | arguments = (arguments ?: Bundle()).also { bundle -> 15 | bundle.putParcelable("FRAGMENT_KEY", this@FragmentKey) 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_9/core/navigation/FragmentKey.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_9.core.navigation 2 | 3 | import android.os.Bundle 4 | import android.os.Parcelable 5 | import androidx.fragment.app.Fragment 6 | 7 | abstract class FragmentKey : Parcelable { 8 | open val fragmentTag: String 9 | get() = toString() 10 | 11 | protected abstract fun instantiateFragment(): Fragment 12 | 13 | fun createFragment(): Fragment = instantiateFragment().apply { 14 | arguments = (arguments ?: Bundle()).also { bundle -> 15 | bundle.putParcelable("FRAGMENT_KEY", this@FragmentKey) 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_7/features/registration/CreateLoginCredentialsKey.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_7.features.registration 2 | 3 | import androidx.fragment.app.Fragment 4 | import com.zhuinden.simplestack.ScopeKey 5 | import com.zhuinden.simplestacktutorials.steps.step_7.core.navigation.FragmentKey 6 | import kotlinx.android.parcel.Parcelize 7 | 8 | @Parcelize 9 | data class CreateLoginCredentialsKey(private val placeholder: String = ""): FragmentKey(), ScopeKey.Child { 10 | override fun instantiateFragment(): Fragment = CreateLoginCredentialsFragment() 11 | 12 | override fun getParentScopes(): List = listOf("registration") 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_9/features/profile/ProfileFragment.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_9.features.profile 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import android.widget.Toast 6 | import com.zhuinden.simplestacktutorials.R 7 | import com.zhuinden.simplestacktutorials.steps.step_9.core.navigation.BaseFragment 8 | 9 | class ProfileFragment : BaseFragment(R.layout.step9_profile_fragment) { 10 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 11 | super.onViewCreated(view, savedInstanceState) 12 | 13 | Toast.makeText(requireContext(), "Welcome!", Toast.LENGTH_LONG).show() 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_9/features/registration/CreateLoginCredentialsKey.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_9.features.registration 2 | 3 | import androidx.fragment.app.Fragment 4 | import com.zhuinden.simplestack.ScopeKey 5 | import com.zhuinden.simplestacktutorials.steps.step_9.core.navigation.FragmentKey 6 | import kotlinx.android.parcel.Parcelize 7 | 8 | @Parcelize 9 | data class CreateLoginCredentialsKey(private val placeholder: String = "") : FragmentKey(), ScopeKey.Child { 10 | override fun instantiateFragment(): Fragment = CreateLoginCredentialsFragment() 11 | 12 | override fun getParentScopes(): List = listOf("registration") 13 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_tag_faces_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_8/core/viewmodels/ServiceProvider.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_8.core.viewmodels 2 | 3 | import com.zhuinden.simplestack.ScopedServices 4 | import com.zhuinden.simplestack.ServiceBinder 5 | import com.zhuinden.simplestacktutorials.steps.step_8.core.navigation.FragmentKey 6 | 7 | class ServiceProvider : ScopedServices { 8 | override fun bindServices(serviceBinder: ServiceBinder) { 9 | val key = serviceBinder.getKey() 10 | 11 | val scope = serviceBinder.scopeTag 12 | 13 | if (key is HasServices && key.scopeTag == scope) { 14 | key.bindServices(serviceBinder) // screen-bound shared services 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_6/Step6SecondFragment.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_6 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import com.zhuinden.simplestacktutorials.R 8 | 9 | class Step6SecondFragment : Step6BaseFragment() { 10 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = 11 | inflater.inflate(R.layout.step6_second_fragment, container, false) 12 | 13 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 14 | super.onViewCreated(view, savedInstanceState) 15 | 16 | val args = getScreen() // get args passed from previous screen 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/step6_second_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /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/main/res/layout/step6_first_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/step7_profile_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/step9_profile_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/zhuinden/simplestacktutorials/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.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.getInstrumentation().targetContext 22 | assertEquals("com.zhuinden.simplestacktutorials", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_4/Step4FirstView.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_4 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.widget.FrameLayout 6 | import com.zhuinden.simplestacktutorials.utils.onClick 7 | import kotlinx.android.synthetic.main.step4_first_view.view.* 8 | 9 | class Step4FirstView : FrameLayout { 10 | constructor(context: Context) : super(context) 11 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) 12 | constructor(context: Context, attrs: AttributeSet?, defaultStyleRes: Int) : super(context, attrs, defaultStyleRes) 13 | 14 | override fun onFinishInflate() { 15 | super.onFinishInflate() 16 | 17 | step4FirstButton.onClick { 18 | backstack.goTo(Step4SecondScreen()) 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_4/Step4Activity.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_4 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | import com.zhuinden.simplestack.History 6 | import com.zhuinden.simplestack.navigator.Navigator 7 | import com.zhuinden.simplestacktutorials.R 8 | import kotlinx.android.synthetic.main.activity_step4.* 9 | 10 | class Step4Activity : AppCompatActivity() { 11 | override fun onCreate(savedInstanceState: Bundle?) { 12 | super.onCreate(savedInstanceState) 13 | setContentView(R.layout.activity_step4) 14 | 15 | Navigator.install(this, step4Root, History.of(Step4FirstScreen())) 16 | } 17 | 18 | override fun onBackPressed() { 19 | if (!Navigator.onBackPressed(this)) { 20 | super.onBackPressed() 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_8/features/main/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_8.features.main 2 | 3 | import com.zhuinden.simplestack.Bundleable 4 | import com.zhuinden.simplestacktutorials.steps.step_8.features.form.FormViewModel 5 | import com.zhuinden.statebundle.StateBundle 6 | 7 | class MainViewModel: FormViewModel.ResultHandler, Bundleable { 8 | var state: String = "" 9 | private set 10 | 11 | override fun handleResult(someData: String, moreData: String) { 12 | this.state = "$someData $moreData" 13 | } 14 | 15 | override fun toBundle(): StateBundle = StateBundle().apply { 16 | putString("state", state) 17 | } 18 | 19 | override fun fromBundle(bundle: StateBundle?) { 20 | bundle?.run { 21 | state = getString("state", "") 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_7/features/login/LoginKey.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_7.features.login 2 | 3 | import androidx.fragment.app.Fragment 4 | import com.zhuinden.simplestack.ServiceBinder 5 | import com.zhuinden.simplestacktutorials.steps.step_7.core.navigation.FragmentKey 6 | import com.zhuinden.simplestacktutorials.steps.step_7.core.viewmodels.HasServices 7 | import com.zhuinden.simplestacktutorials.steps.step_7.core.viewmodels.add 8 | import kotlinx.android.parcel.Parcelize 9 | 10 | @Parcelize 11 | data class LoginKey(private val placeholder: String = ""): FragmentKey(), HasServices { 12 | override fun bindServices(serviceBinder: ServiceBinder) { 13 | with(serviceBinder) { 14 | add(LoginViewModel(lookupService("appContext"), backstack)) 15 | } 16 | } 17 | 18 | override fun instantiateFragment(): Fragment = LoginFragment() 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_9/features/login/LoginKey.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_9.features.login 2 | 3 | import androidx.fragment.app.Fragment 4 | import com.zhuinden.simplestack.ServiceBinder 5 | import com.zhuinden.simplestacktutorials.steps.step_9.core.navigation.FragmentKey 6 | import com.zhuinden.simplestacktutorials.steps.step_9.core.viewmodels.HasServices 7 | import com.zhuinden.simplestacktutorials.steps.step_9.core.viewmodels.add 8 | import kotlinx.android.parcel.Parcelize 9 | 10 | @Parcelize 11 | data class LoginKey(private val placeholder: String = "") : FragmentKey(), HasServices { 12 | override fun bindServices(serviceBinder: ServiceBinder) { 13 | with(serviceBinder) { 14 | add(LoginViewModel(lookupService("appContext"), backstack)) 15 | } 16 | } 17 | 18 | override fun instantiateFragment(): Fragment = LoginFragment() 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_7/features/profile/ProfileKey.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_7.features.profile 2 | 3 | import androidx.fragment.app.Fragment 4 | import com.zhuinden.simplestack.ServiceBinder 5 | import com.zhuinden.simplestacktutorials.steps.step_7.core.navigation.FragmentKey 6 | import com.zhuinden.simplestacktutorials.steps.step_7.core.viewmodels.HasServices 7 | import com.zhuinden.simplestacktutorials.steps.step_7.core.viewmodels.add 8 | import kotlinx.android.parcel.Parcelize 9 | 10 | @Parcelize 11 | data class ProfileKey(private val placeholder: String = ""): FragmentKey(), HasServices { 12 | override fun bindServices(serviceBinder: ServiceBinder) { 13 | with(serviceBinder) { 14 | add(ProfileViewModel(lookupService("appContext"), backstack)) 15 | } 16 | } 17 | 18 | override fun instantiateFragment(): Fragment = ProfileFragment() 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_9/features/profile/ProfileKey.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_9.features.profile 2 | 3 | import androidx.fragment.app.Fragment 4 | import com.zhuinden.simplestack.ServiceBinder 5 | import com.zhuinden.simplestacktutorials.steps.step_9.core.navigation.FragmentKey 6 | import com.zhuinden.simplestacktutorials.steps.step_9.core.viewmodels.HasServices 7 | import com.zhuinden.simplestacktutorials.steps.step_9.core.viewmodels.add 8 | import kotlinx.android.parcel.Parcelize 9 | 10 | @Parcelize 11 | data class ProfileKey(private val placeholder: String = "") : FragmentKey(), HasServices { 12 | override fun bindServices(serviceBinder: ServiceBinder) { 13 | with(serviceBinder) { 14 | add(ProfileViewModel(lookupService("appContext"), backstack)) 15 | } 16 | } 17 | 18 | override fun instantiateFragment(): Fragment = ProfileFragment() 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_7/features/profile/ProfileFragment.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_7.features.profile 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.Toast 8 | import com.zhuinden.simplestacktutorials.R 9 | import com.zhuinden.simplestacktutorials.steps.step_7.core.navigation.BaseFragment 10 | 11 | class ProfileFragment: BaseFragment() { 12 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = 13 | inflater.inflate(R.layout.step7_profile_fragment, container, false) 14 | 15 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 16 | super.onViewCreated(view, savedInstanceState) 17 | 18 | Toast.makeText(requireContext(), "Welcome!", Toast.LENGTH_LONG).show() 19 | } 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_5/Step5FirstFragment.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_5 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import com.zhuinden.simplestacktutorials.R 8 | import com.zhuinden.simplestacktutorials.utils.onClick 9 | import kotlinx.android.synthetic.main.step5_first_fragment.* 10 | 11 | class Step5FirstFragment : Step5BaseFragment() { 12 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = 13 | inflater.inflate(R.layout.step5_first_fragment, container, false) 14 | 15 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 16 | super.onViewCreated(view, savedInstanceState) 17 | 18 | step5FirstButton.onClick { 19 | backstack.goTo(Step5SecondScreen()) 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_9/features/profile/ProfileViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_9.features.profile 2 | 3 | import android.content.Context 4 | import com.zhuinden.simplestack.Backstack 5 | import com.zhuinden.simplestack.History 6 | import com.zhuinden.simplestack.ScopedServices 7 | import com.zhuinden.simplestack.StateChange 8 | import com.zhuinden.simplestacktutorials.steps.step_9.AuthenticationManager 9 | import com.zhuinden.simplestacktutorials.steps.step_9.features.login.LoginKey 10 | 11 | class ProfileViewModel( 12 | private val appContext: Context, 13 | private val backstack: Backstack 14 | ) : ScopedServices.Activated { 15 | override fun onServiceActive() { 16 | if (!AuthenticationManager.isAuthenticated(appContext)) { 17 | backstack.setHistory(History.of(LoginKey()), StateChange.REPLACE) 18 | } 19 | } 20 | 21 | override fun onServiceInactive() { 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_8/features/form/FormKey.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_8.features.form 2 | 3 | import androidx.fragment.app.Fragment 4 | import com.zhuinden.simplestack.ServiceBinder 5 | import com.zhuinden.simplestacktutorials.steps.step_8.core.navigation.FragmentKey 6 | import com.zhuinden.simplestacktutorials.steps.step_8.core.viewmodels.HasServices 7 | import com.zhuinden.simplestacktutorials.steps.step_8.core.viewmodels.add 8 | import com.zhuinden.simplestacktutorials.steps.step_8.core.viewmodels.lookup 9 | import kotlinx.android.parcel.Parcelize 10 | 11 | @Parcelize 12 | data class FormKey(private val placeholder: String = ""): FragmentKey(), HasServices { 13 | override fun instantiateFragment(): Fragment = FormFragment() 14 | 15 | override fun bindServices(serviceBinder: ServiceBinder) { 16 | with(serviceBinder) { 17 | add(FormViewModel(lookup(), backstack)) 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_5/Step5SecondFragment.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_5 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import com.zhuinden.simplestacktutorials.R 8 | import com.zhuinden.simplestacktutorials.utils.onClick 9 | import kotlinx.android.synthetic.main.step5_second_fragment.* 10 | 11 | class Step5SecondFragment : Step5BaseFragment() { 12 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = 13 | inflater.inflate(R.layout.step5_second_fragment, container, false) 14 | 15 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 16 | super.onViewCreated(view, savedInstanceState) 17 | 18 | val args = getScreen() // get args passed from previous screen 19 | 20 | step5SecondBack.onClick { 21 | backstack.goBack() 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_4/Step4SecondView.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_4 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.widget.FrameLayout 6 | import com.zhuinden.simplestack.Backstack 7 | import com.zhuinden.simplestacktutorials.utils.onClick 8 | import kotlinx.android.synthetic.main.step4_second_view.view.* 9 | 10 | class Step4SecondView : FrameLayout { 11 | constructor(context: Context) : super(context) 12 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) 13 | constructor(context: Context, attrs: AttributeSet?, defaultStyleRes: Int) : super(context, attrs, defaultStyleRes) 14 | 15 | override fun onFinishInflate() { 16 | super.onFinishInflate() 17 | 18 | if (isInEditMode) { 19 | return 20 | } 21 | 22 | val args = Backstack.getKey(context) // get args passed from previous screen 23 | 24 | step4SecondBack.onClick { 25 | backstack.goBack() 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/zhuinden/simplestacktutorials/steps/step_7/features/profile/ProfileViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.zhuinden.simplestacktutorials.steps.step_7.features.profile 2 | 3 | import android.content.Context 4 | import android.os.Handler 5 | import android.os.Looper 6 | import com.zhuinden.simplestack.Backstack 7 | import com.zhuinden.simplestack.History 8 | import com.zhuinden.simplestack.ScopedServices 9 | import com.zhuinden.simplestack.StateChange 10 | import com.zhuinden.simplestacktutorials.steps.step_7.AuthenticationManager 11 | import com.zhuinden.simplestacktutorials.steps.step_7.features.login.LoginKey 12 | 13 | class ProfileViewModel( 14 | private val appContext: Context, 15 | private val backstack: Backstack 16 | ) : ScopedServices.Activated { 17 | private val handler = Handler(Looper.getMainLooper()) 18 | 19 | override fun onServiceActive() { 20 | if (!AuthenticationManager.isAuthenticated(appContext)) { 21 | backstack.setHistory(History.of(LoginKey()), StateChange.REPLACE) 22 | } 23 | } 24 | 25 | override fun onServiceInactive() { 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_step1.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 20 | 21 |