diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.EditSuperHeroActivityTest_showsJustOneSuperHero.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.EditSuperHeroActivityTest_showsJustOneSuperHero.png deleted file mode 100644 index e371f10..0000000 Binary files a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.EditSuperHeroActivityTest_showsJustOneSuperHero.png and /dev/null differ diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.EditSuperHeroFragmentTest_showsJustOneSuperHero.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.EditSuperHeroFragmentTest_showsJustOneSuperHero.png new file mode 100644 index 0000000..05afe07 Binary files /dev/null and b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.EditSuperHeroFragmentTest_showsJustOneSuperHero.png differ diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.MainActivityTest_doesNotShowAvengersBadgeIfASuperHeroIsNotPartOfTheAvengersTeam.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.MainActivityTest_doesNotShowAvengersBadgeIfASuperHeroIsNotPartOfTheAvengersTeam.png deleted file mode 100644 index 1158877..0000000 Binary files a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.MainActivityTest_doesNotShowAvengersBadgeIfASuperHeroIsNotPartOfTheAvengersTeam.png and /dev/null differ diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.MainActivityTest_showsAvengersBadgeIfASuperHeroIsPartOfTheAvengersTeam.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.MainActivityTest_showsAvengersBadgeIfASuperHeroIsPartOfTheAvengersTeam.png deleted file mode 100644 index abb57f0..0000000 Binary files a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.MainActivityTest_showsAvengersBadgeIfASuperHeroIsPartOfTheAvengersTeam.png and /dev/null differ diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.MainActivityTest_showsEmptyCaseIfThereAreNoSuperHeroes.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.MainActivityTest_showsEmptyCaseIfThereAreNoSuperHeroes.png deleted file mode 100644 index 2b7b895..0000000 Binary files a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.MainActivityTest_showsEmptyCaseIfThereAreNoSuperHeroes.png and /dev/null differ diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.MainActivityTest_showsJustOneSuperHero.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.MainActivityTest_showsJustOneSuperHero.png deleted file mode 100644 index 946a06a..0000000 Binary files a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.MainActivityTest_showsJustOneSuperHero.png and /dev/null differ diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.MainActivityTest_showsSuperHeroesIfThereAreSomeSuperHeroes.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.MainActivityTest_showsSuperHeroesIfThereAreSomeSuperHeroes.png deleted file mode 100644 index 1158877..0000000 Binary files a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.MainActivityTest_showsSuperHeroesIfThereAreSomeSuperHeroes.png and /dev/null differ diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroDetailActivityTest_doesNotShowAvengersBadgeIfSuperHeroIsNotPartOfTheAvengersTeam.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroDetailActivityTest_doesNotShowAvengersBadgeIfSuperHeroIsNotPartOfTheAvengersTeam.png deleted file mode 100644 index 1b253ea..0000000 Binary files a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroDetailActivityTest_doesNotShowAvengersBadgeIfSuperHeroIsNotPartOfTheAvengersTeam.png and /dev/null differ diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroDetailActivityTest_showsAvengersBadgeIfSuperHeroIsPartOfTheAvengersTeam.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroDetailActivityTest_showsAvengersBadgeIfSuperHeroIsPartOfTheAvengersTeam.png deleted file mode 100644 index d251740..0000000 Binary files a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroDetailActivityTest_showsAvengersBadgeIfSuperHeroIsPartOfTheAvengersTeam.png and /dev/null differ diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroDetailFragmentTest_doesNotShowAvengersBadgeIfSuperHeroIsNotPartOfTheAvengersTeam.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroDetailFragmentTest_doesNotShowAvengersBadgeIfSuperHeroIsNotPartOfTheAvengersTeam.png new file mode 100644 index 0000000..f2d3e7e Binary files /dev/null and b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroDetailFragmentTest_doesNotShowAvengersBadgeIfSuperHeroIsNotPartOfTheAvengersTeam.png differ diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroDetailFragmentTest_showsAvengersBadgeIfSuperHeroIsPartOfTheAvengersTeam.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroDetailFragmentTest_showsAvengersBadgeIfSuperHeroIsPartOfTheAvengersTeam.png new file mode 100644 index 0000000..7ee853e Binary files /dev/null and b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroDetailFragmentTest_showsAvengersBadgeIfSuperHeroIsPartOfTheAvengersTeam.png differ diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentTest_doesNotShowAvengersBadgeIfASuperHeroIsNotPartOfTheAvengersTeam.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentTest_doesNotShowAvengersBadgeIfASuperHeroIsNotPartOfTheAvengersTeam.png new file mode 100644 index 0000000..ef40813 Binary files /dev/null and b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentTest_doesNotShowAvengersBadgeIfASuperHeroIsNotPartOfTheAvengersTeam.png differ diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentTest_showsAvengersBadgeIfASuperHeroIsPartOfTheAvengersTeam.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentTest_showsAvengersBadgeIfASuperHeroIsPartOfTheAvengersTeam.png new file mode 100644 index 0000000..96a5a18 Binary files /dev/null and b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentTest_showsAvengersBadgeIfASuperHeroIsPartOfTheAvengersTeam.png differ diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentTest_showsEmptyCaseIfThereAreNoSuperHeroes.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentTest_showsEmptyCaseIfThereAreNoSuperHeroes.png new file mode 100644 index 0000000..75d0bdd Binary files /dev/null and b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentTest_showsEmptyCaseIfThereAreNoSuperHeroes.png differ diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentTest_showsJustOneSuperHero.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentTest_showsJustOneSuperHero.png new file mode 100644 index 0000000..49b465f Binary files /dev/null and b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentTest_showsJustOneSuperHero.png differ diff --git a/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentTest_showsSuperHeroesIfThereAreSomeSuperHeroes.png b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentTest_showsSuperHeroesIfThereAreSomeSuperHeroes.png new file mode 100644 index 0000000..ef40813 Binary files /dev/null and b/app/screenshots/com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentTest_showsSuperHeroesIfThereAreSomeSuperHeroes.png differ diff --git a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroActivityTest.kt b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroFragmentTest.kt similarity index 73% rename from app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroActivityTest.kt rename to app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroFragmentTest.kt index 9fc82c1..668d700 100644 --- a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroActivityTest.kt +++ b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroFragmentTest.kt @@ -11,8 +11,7 @@ import org.kodein.di.erased.bind import org.kodein.di.erased.instance import org.mockito.Mock -class EditSuperHeroActivityTest : - AcceptanceTest(EditSuperHeroActivity::class.java) { +class EditSuperHeroFragmentTest : FragmentTest() { companion object { private const val ANY_ID = "#1" @@ -20,12 +19,13 @@ class EditSuperHeroActivityTest : @Mock private lateinit var repository: SuperHeroRepository + override val fragmentBlock = { EditSuperHeroFragment() } @Test fun showsJustOneSuperHero() { val superHero = givenThereIsASuperHero() - val activity = startActivity(superHero) + val activity = startFragment(superHero) compareScreenshot(activity) } @@ -42,10 +42,12 @@ class EditSuperHeroActivityTest : return superHero } - private fun startActivity(superHero: SuperHero): EditSuperHeroActivity { - val args = Bundle() - args.putString("super_hero_id_key", superHero.id) - return startActivity(args) + private fun startFragment(superHero: SuperHero): EditSuperHeroFragment { + val args = Bundle().apply { + putString("superHeroId", superHero.id) + putString("superHeroName", superHero.name) + } + return startFragment(args) } override val testDependencies = Kodein.Module("Test dependencies", allowSilentOverride = true) { diff --git a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/AcceptanceTest.kt b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/FragmentTest.kt similarity index 66% rename from app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/AcceptanceTest.kt rename to app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/FragmentTest.kt index 73304e9..fa6d28f 100644 --- a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/AcceptanceTest.kt +++ b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/FragmentTest.kt @@ -1,16 +1,15 @@ package com.karumi.jetpack.superheroes.ui.view -import android.app.Activity -import android.content.Intent import android.os.Bundle +import androidx.fragment.app.Fragment +import androidx.fragment.app.testing.launchFragmentInContainer import androidx.test.core.app.ApplicationProvider -import androidx.test.espresso.intent.rule.IntentsTestRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.LargeTest import androidx.test.platform.app.InstrumentationRegistry +import com.karumi.jetpack.superheroes.R import com.karumi.jetpack.superheroes.SuperHeroesApplication import org.junit.Before -import org.junit.Rule import org.junit.runner.RunWith import org.kodein.di.Kodein import org.kodein.di.erased.bind @@ -20,15 +19,9 @@ import java.util.concurrent.Executor @LargeTest @RunWith(AndroidJUnit4::class) -abstract class AcceptanceTest(clazz: Class) : ScreenshotTest { +abstract class FragmentTest : ScreenshotTest { - companion object { - private const val doNotLaunchActivityAtLunch = false - } - - @Rule - @JvmField - val testRule: IntentsTestRule = IntentsTestRule(clazz, true, doNotLaunchActivityAtLunch) + abstract val fragmentBlock: () -> F @Before fun setup() { @@ -42,10 +35,10 @@ abstract class AcceptanceTest(clazz: Class) : ScreenshotTest { }) } - fun startActivity(args: Bundle = Bundle()): T { - val intent = Intent() - intent.putExtras(args) - return testRule.launchActivity(intent) + protected fun startFragment(args: Bundle? = null): F { + val fragment = fragmentBlock() + launchFragmentInContainer(args, R.style.AppTheme) { fragment as Fragment } + return fragment } abstract val testDependencies: Kodein.Module diff --git a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/ScreenshotTest.kt b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/ScreenshotTest.kt index a1592c4..732b55d 100644 --- a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/ScreenshotTest.kt +++ b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/ScreenshotTest.kt @@ -1,18 +1,19 @@ package com.karumi.jetpack.superheroes.ui.view -import android.app.Activity import android.content.Context import android.util.DisplayMetrics import android.view.View import android.view.WindowManager +import androidx.fragment.app.Fragment import androidx.recyclerview.widget.RecyclerView import androidx.test.platform.app.InstrumentationRegistry import com.facebook.testing.screenshot.Screenshot import com.facebook.testing.screenshot.ViewHelpers interface ScreenshotTest { - fun compareScreenshot(activity: Activity) { - Screenshot.snapActivity(activity).record() + fun compareScreenshot(fragment: Fragment) { + Thread.sleep(100) + Screenshot.snapActivity(fragment.requireActivity()).record() } fun compareScreenshot(holder: RecyclerView.ViewHolder, height: Int) { diff --git a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailActivityTest.kt b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailFragmentTest.kt similarity index 82% rename from app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailActivityTest.kt rename to app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailFragmentTest.kt index e960984..712b42b 100644 --- a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailActivityTest.kt +++ b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailFragmentTest.kt @@ -11,12 +11,11 @@ import org.kodein.di.erased.bind import org.kodein.di.erased.instance import org.mockito.Mock -class SuperHeroDetailActivityTest : AcceptanceTest( - SuperHeroDetailActivity::class.java -) { +class SuperHeroDetailFragmentTest : FragmentTest() { @Mock private lateinit var repository: SuperHeroRepository + override val fragmentBlock = { SuperHeroDetailFragment() } @Test fun showsAvengersBadgeIfSuperHeroIsPartOfTheAvengersTeam() { @@ -45,10 +44,12 @@ class SuperHeroDetailActivityTest : AcceptanceTest( return superHero } - private fun startActivity(superHero: SuperHero): SuperHeroDetailActivity { - val args = Bundle() - args.putString("super_hero_id_key", superHero.id) - return startActivity(args) + private fun startActivity(superHero: SuperHero): SuperHeroDetailFragment { + val args = Bundle().apply { + putString("superHeroId", superHero.id) + putString("superHeroName", superHero.name) + } + return startFragment(args) } override val testDependencies = Kodein.Module("Test dependencies", allowSilentOverride = true) { diff --git a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/MainActivityTest.kt b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroesFragmentTest.kt similarity index 89% rename from app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/MainActivityTest.kt rename to app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroesFragmentTest.kt index ae7db5e..9b5afc0 100644 --- a/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/MainActivityTest.kt +++ b/app/src/androidTest/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroesFragmentTest.kt @@ -1,6 +1,7 @@ package com.karumi.jetpack.superheroes.ui.view import android.os.Looper +import androidx.fragment.app.Fragment import androidx.paging.PagedList import androidx.paging.PositionalDataSource import com.karumi.jetpack.superheroes.data.repository.SuperHeroRepository @@ -14,7 +15,7 @@ import org.kodein.di.erased.instance import org.mockito.Mock import java.util.concurrent.Executors.newSingleThreadExecutor -class MainActivityTest : AcceptanceTest(MainActivity::class.java) { +class SuperHeroesFragmentTest : FragmentTest() { companion object { private const val ANY_NUMBER_OF_SUPER_HEROES = 100 @@ -22,12 +23,13 @@ class MainActivityTest : AcceptanceTest(MainActivity::class.java) @Mock private lateinit var repository: SuperHeroRepository + override val fragmentBlock = { SuperHeroesFragment() } @Test fun showsEmptyCaseIfThereAreNoSuperHeroes() { givenThereAreNoSuperHeroes() - val activity = startActivity() + val activity = startFragment() compareScreenshot(activity) } @@ -36,7 +38,7 @@ class MainActivityTest : AcceptanceTest(MainActivity::class.java) fun showsJustOneSuperHero() { givenThereAreSomeSuperHeroes(1) - val activity = startActivity() + val activity = startFragment() compareScreenshot(activity) } @@ -45,7 +47,7 @@ class MainActivityTest : AcceptanceTest(MainActivity::class.java) fun showsSuperHeroesIfThereAreSomeSuperHeroes() { givenThereAreSomeSuperHeroes(ANY_NUMBER_OF_SUPER_HEROES) - val activity = startActivity() + val activity = startFragment() compareScreenshot(activity) } @@ -54,7 +56,7 @@ class MainActivityTest : AcceptanceTest(MainActivity::class.java) fun showsAvengersBadgeIfASuperHeroIsPartOfTheAvengersTeam() { givenThereAreSomeAvengers(ANY_NUMBER_OF_SUPER_HEROES) - val activity = startActivity() + val activity = startFragment() compareScreenshot(activity) } @@ -63,14 +65,14 @@ class MainActivityTest : AcceptanceTest(MainActivity::class.java) fun doesNotShowAvengersBadgeIfASuperHeroIsNotPartOfTheAvengersTeam() { givenThereAreSomeSuperHeroes(ANY_NUMBER_OF_SUPER_HEROES) - val activity = startActivity() + val activity = startFragment() compareScreenshot(activity) } - private fun compareScreenshot(activity: MainActivity) { + override fun compareScreenshot(fragment: Fragment) { Thread.sleep(100) - super.compareScreenshot(activity) + super.compareScreenshot(fragment) } private fun givenThereAreSomeAvengers(numberOfAvengers: Int): List = diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a67a88e..8bf46ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,11 +21,6 @@ - - - \ No newline at end of file diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/common/ViewModelFactory.kt b/app/src/main/java/com/karumi/jetpack/superheroes/common/ViewModelFactory.kt index 175acd4..379796e 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/common/ViewModelFactory.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/common/ViewModelFactory.kt @@ -4,7 +4,7 @@ import android.app.Application import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProviders -import com.karumi.jetpack.superheroes.ui.view.BaseActivity +import com.karumi.jetpack.superheroes.ui.view.BaseFragment import org.kodein.di.DKodein import org.kodein.di.Kodein import org.kodein.di.KodeinAware @@ -26,7 +26,7 @@ class ViewModelFactory( inline fun T.viewModel(): Lazy where T : KodeinAware, - T : BaseActivity<*> { + T : BaseFragment<*> { return lazy { ViewModelProviders.of(this, direct.instance()).get(VM::class.java) } } diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/BaseFragment.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/BaseFragment.kt new file mode 100644 index 0000000..13a3efa --- /dev/null +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/BaseFragment.kt @@ -0,0 +1,52 @@ +package com.karumi.jetpack.superheroes.ui.view + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.databinding.ViewDataBinding +import androidx.fragment.app.Fragment +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.ViewModelProvider +import com.karumi.jetpack.superheroes.common.ViewModelFactory +import org.kodein.di.Kodein +import org.kodein.di.KodeinAware +import org.kodein.di.android.closestKodein +import org.kodein.di.erased.bind +import org.kodein.di.erased.instance +import org.kodein.di.erased.singleton + +abstract class BaseFragment : Fragment(), KodeinAware { + + private val appKodein by closestKodein { requireActivity() } + override val kodein: Kodein = Kodein.lazy { + extend(appKodein) + includeViewModelFactory() + import(activityModules) + } + + abstract val layoutId: Int + abstract val activityModules: Kodein.Module + abstract val viewModel: AndroidViewModel + protected lateinit var binding: T + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = DataBindingUtil.inflate(layoutInflater, layoutId, container, false) + binding.setLifecycleOwner(this) + configureBinding(binding) + return binding.root + } + + private fun Kodein.MainBuilder.includeViewModelFactory() { + bind() with singleton { + ViewModelFactory(instance(), instance()) + } + } + + abstract fun configureBinding(binding: T) +} \ No newline at end of file diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroActivity.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroActivity.kt deleted file mode 100644 index 2a55183..0000000 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroActivity.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.karumi.jetpack.superheroes.ui.view - -import android.app.Activity -import android.content.Intent -import android.os.Bundle -import androidx.appcompat.widget.Toolbar -import androidx.lifecycle.Observer -import com.karumi.jetpack.superheroes.R -import com.karumi.jetpack.superheroes.common.bindViewModel -import com.karumi.jetpack.superheroes.common.module -import com.karumi.jetpack.superheroes.common.viewModel -import com.karumi.jetpack.superheroes.databinding.EditSuperHeroActivityBinding -import com.karumi.jetpack.superheroes.domain.usecase.GetSuperHeroById -import com.karumi.jetpack.superheroes.domain.usecase.SaveSuperHero -import com.karumi.jetpack.superheroes.ui.viewmodel.EditSuperHeroViewModel -import kotlinx.android.synthetic.main.edit_super_hero_activity.* -import org.kodein.di.erased.bind -import org.kodein.di.erased.instance -import org.kodein.di.erased.provider - -class EditSuperHeroActivity : BaseActivity() { - - companion object { - private const val SUPER_HERO_ID_KEY = "super_hero_id_key" - - fun open(activity: Activity, superHeroId: String) { - val intent = Intent(activity, EditSuperHeroActivity::class.java) - intent.putExtra(SUPER_HERO_ID_KEY, superHeroId) - activity.startActivity(intent) - } - } - - override val viewModel: EditSuperHeroViewModel by viewModel() - override val layoutId = R.layout.edit_super_hero_activity - override val toolbarView: Toolbar - get() = toolbar - private val superHeroId: String by lazy { intent?.extras?.getString(SUPER_HERO_ID_KEY) ?: "" } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - title = superHeroId - } - - override fun configureBinding(binding: EditSuperHeroActivityBinding) { - binding.viewModel = viewModel - viewModel.isClosing.observe(this, Observer { finish() }) - viewModel.prepare(superHeroId) - } - - override val activityModules = module { - bindViewModel() with provider { - EditSuperHeroViewModel(instance(), instance(), instance()) - } - bind() with provider { GetSuperHeroById(instance()) } - bind() with provider { SaveSuperHero(instance()) } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroFragment.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroFragment.kt new file mode 100644 index 0000000..816f63b --- /dev/null +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/EditSuperHeroFragment.kt @@ -0,0 +1,41 @@ +package com.karumi.jetpack.superheroes.ui.view + +import android.os.Bundle +import android.view.View +import androidx.lifecycle.Observer +import androidx.navigation.fragment.navArgs +import com.karumi.jetpack.superheroes.R +import com.karumi.jetpack.superheroes.common.bindViewModel +import com.karumi.jetpack.superheroes.common.module +import com.karumi.jetpack.superheroes.common.viewModel +import com.karumi.jetpack.superheroes.databinding.EditSuperHeroFragmentBinding +import com.karumi.jetpack.superheroes.domain.usecase.GetSuperHeroById +import com.karumi.jetpack.superheroes.domain.usecase.SaveSuperHero +import com.karumi.jetpack.superheroes.ui.viewmodel.EditSuperHeroViewModel +import org.kodein.di.erased.bind +import org.kodein.di.erased.instance +import org.kodein.di.erased.provider + +class EditSuperHeroFragment : BaseFragment() { + override val layoutId = R.layout.edit_super_hero_fragment + override val viewModel: EditSuperHeroViewModel by viewModel() + private val args: EditSuperHeroFragmentArgs by navArgs() + + override fun configureBinding(binding: EditSuperHeroFragmentBinding) { + binding.viewModel = viewModel + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + viewModel.isClosing.observe(this, Observer { requireActivity().onBackPressed() }) + viewModel.prepare(args.superHeroId) + } + + override val activityModules = module { + bindViewModel() with provider { + EditSuperHeroViewModel(instance(), instance(), instance()) + } + bind() with provider { GetSuperHeroById(instance()) } + bind() with provider { SaveSuperHero(instance()) } + } +} diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/MainActivity.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/MainActivity.kt index b463615..2cc8ee4 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/MainActivity.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/MainActivity.kt @@ -1,70 +1,23 @@ package com.karumi.jetpack.superheroes.ui.view import android.os.Bundle -import androidx.appcompat.widget.Toolbar -import androidx.lifecycle.Observer -import androidx.paging.PagedList -import androidx.recyclerview.widget.LinearLayoutManager +import androidx.appcompat.app.AppCompatActivity +import androidx.navigation.findNavController +import androidx.navigation.ui.AppBarConfiguration +import androidx.navigation.ui.setupWithNavController import com.karumi.jetpack.superheroes.R -import com.karumi.jetpack.superheroes.common.bindViewModel -import com.karumi.jetpack.superheroes.common.module -import com.karumi.jetpack.superheroes.common.viewModel -import com.karumi.jetpack.superheroes.databinding.MainActivityBinding -import com.karumi.jetpack.superheroes.domain.model.SuperHero -import com.karumi.jetpack.superheroes.domain.usecase.GetSuperHeroes -import com.karumi.jetpack.superheroes.ui.view.adapter.SuperHeroesAdapter -import com.karumi.jetpack.superheroes.ui.viewmodel.SuperHeroesViewModel import kotlinx.android.synthetic.main.main_activity.* -import org.kodein.di.erased.bind -import org.kodein.di.erased.instance -import org.kodein.di.erased.provider - -class MainActivity : BaseActivity() { - - override val viewModel: SuperHeroesViewModel by viewModel() - private lateinit var adapter: SuperHeroesAdapter - override val layoutId: Int = R.layout.main_activity - override val toolbarView: Toolbar - get() = toolbar +class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - initializeAdapter() - initializeRecyclerView() - viewModel.prepare() - viewModel.idOfSuperHeroToOpen.observe(this, Observer { openDetail(it) }) - viewModel.superHeroes.observe(this, Observer> { showSuperHeroes(it) }) - } - - override fun configureBinding(binding: MainActivityBinding) { - binding.viewModel = viewModel - } - - private fun initializeAdapter() { - adapter = SuperHeroesAdapter(viewModel) - } - - private fun initializeRecyclerView() { - recycler_view.layoutManager = LinearLayoutManager(this) - recycler_view.setHasFixedSize(true) - recycler_view.adapter = adapter - } - - private fun showSuperHeroes(superHeroes: PagedList) { - adapter.submitList(superHeroes) - } - - private fun openDetail(id: String) { - SuperHeroDetailActivity.open( - activity = this, - superHeroId = id - ) + setContentView(R.layout.main_activity) + configureToolbar() } - override val activityModules = module { - bindViewModel() with provider { - SuperHeroesViewModel(instance(), instance()) - } - bind() with provider { GetSuperHeroes(instance()) } + private fun configureToolbar() { + val navController = findNavController(R.id.nav_host_fragment) + val appBarConfiguration = AppBarConfiguration(navController.graph) + toolbar.setupWithNavController(navController, appBarConfiguration) } } diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailActivity.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailActivity.kt deleted file mode 100644 index d42d041..0000000 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailActivity.kt +++ /dev/null @@ -1,55 +0,0 @@ -package com.karumi.jetpack.superheroes.ui.view - -import android.app.Activity -import android.content.Intent -import androidx.appcompat.widget.Toolbar -import androidx.lifecycle.Observer -import com.karumi.jetpack.superheroes.R -import com.karumi.jetpack.superheroes.common.bindViewModel -import com.karumi.jetpack.superheroes.common.module -import com.karumi.jetpack.superheroes.common.viewModel -import com.karumi.jetpack.superheroes.databinding.SuperHeroDetailActivityBinding -import com.karumi.jetpack.superheroes.domain.usecase.GetSuperHeroById -import com.karumi.jetpack.superheroes.ui.viewmodel.SuperHeroDetailViewModel -import kotlinx.android.synthetic.main.super_hero_detail_activity.* -import org.kodein.di.erased.bind -import org.kodein.di.erased.instance -import org.kodein.di.erased.provider - -class SuperHeroDetailActivity : - BaseActivity() { - companion object { - private const val SUPER_HERO_ID_KEY = "super_hero_id_key" - - fun open(activity: Activity, superHeroId: String) { - val intent = Intent(activity, SuperHeroDetailActivity::class.java) - intent.putExtra(SUPER_HERO_ID_KEY, superHeroId) - activity.startActivity(intent) - } - } - - override val viewModel: SuperHeroDetailViewModel by viewModel() - override val layoutId: Int = R.layout.super_hero_detail_activity - override val toolbarView: Toolbar - get() = toolbar - private val superHeroId: String by lazy { intent?.extras?.getString(SUPER_HERO_ID_KEY) ?: "" } - - override fun configureBinding(binding: SuperHeroDetailActivityBinding) { - binding.viewModel = viewModel - viewModel.idOfSuperHeroToEdit.observe(this, Observer { openEditSuperHero(it) }) - viewModel.superHero.observe(this, Observer { title = it?.name }) - viewModel.prepare(superHeroId) - } - - private fun openEditSuperHero(superHeroId: String?) { - superHeroId ?: return - EditSuperHeroActivity.open(this, superHeroId) - } - - override val activityModules = module { - bindViewModel() with provider { - SuperHeroDetailViewModel(instance(), instance()) - } - bind() with provider { GetSuperHeroById(instance()) } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailFragment.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailFragment.kt new file mode 100644 index 0000000..2d1c066 --- /dev/null +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroDetailFragment.kt @@ -0,0 +1,45 @@ +package com.karumi.jetpack.superheroes.ui.view + +import androidx.lifecycle.Observer +import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs +import com.karumi.jetpack.superheroes.R +import com.karumi.jetpack.superheroes.common.bindViewModel +import com.karumi.jetpack.superheroes.common.module +import com.karumi.jetpack.superheroes.common.viewModel +import com.karumi.jetpack.superheroes.databinding.SuperHeroDetailFragmentBinding +import com.karumi.jetpack.superheroes.domain.usecase.GetSuperHeroById +import com.karumi.jetpack.superheroes.ui.view.SuperHeroDetailFragmentDirections.Companion.actionSuperHeroDetailFragmentToEditSuperHeroFragment +import com.karumi.jetpack.superheroes.ui.viewmodel.SuperHeroDetailViewModel +import com.karumi.jetpack.superheroes.ui.viewmodel.SuperHeroToEdit +import org.kodein.di.erased.bind +import org.kodein.di.erased.instance +import org.kodein.di.erased.provider + +class SuperHeroDetailFragment : BaseFragment() { + override val layoutId = R.layout.super_hero_detail_fragment + override val viewModel: SuperHeroDetailViewModel by viewModel() + private val args: SuperHeroDetailFragmentArgs by navArgs() + + override fun configureBinding(binding: SuperHeroDetailFragmentBinding) { + binding.viewModel = viewModel + viewModel.superHeroToEdit.observe(this, Observer { openEditSuperHero(it) }) + viewModel.prepare(args.superHeroId) + } + + private fun openEditSuperHero(superHeroToEdit: SuperHeroToEdit?) { + superHeroToEdit ?: return + val directions = actionSuperHeroDetailFragmentToEditSuperHeroFragment( + superHeroToEdit.id, + superHeroToEdit.name + ) + findNavController().navigate(directions) + } + + override val activityModules = module { + bindViewModel() with provider { + SuperHeroDetailViewModel(instance(), instance()) + } + bind() with provider { GetSuperHeroById(instance()) } + } +} diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroesFragment.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroesFragment.kt new file mode 100644 index 0000000..f701f69 --- /dev/null +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/view/SuperHeroesFragment.kt @@ -0,0 +1,72 @@ +package com.karumi.jetpack.superheroes.ui.view + +import android.os.Bundle +import android.view.View +import androidx.lifecycle.Observer +import androidx.navigation.fragment.findNavController +import androidx.paging.PagedList +import androidx.recyclerview.widget.LinearLayoutManager +import com.karumi.jetpack.superheroes.R +import com.karumi.jetpack.superheroes.common.bindViewModel +import com.karumi.jetpack.superheroes.common.module +import com.karumi.jetpack.superheroes.common.viewModel +import com.karumi.jetpack.superheroes.databinding.SuperHeroesFragmentBinding +import com.karumi.jetpack.superheroes.domain.model.SuperHero +import com.karumi.jetpack.superheroes.domain.usecase.GetSuperHeroes +import com.karumi.jetpack.superheroes.ui.view.SuperHeroesFragmentDirections.Companion.actionSuperHeroesFragmentToSuperHeroDetailFragment +import com.karumi.jetpack.superheroes.ui.view.adapter.SuperHeroesAdapter +import com.karumi.jetpack.superheroes.ui.viewmodel.SuperHeroToOpen +import com.karumi.jetpack.superheroes.ui.viewmodel.SuperHeroesViewModel +import kotlinx.android.synthetic.main.super_heroes_fragment.* +import org.kodein.di.erased.bind +import org.kodein.di.erased.instance +import org.kodein.di.erased.provider + +class SuperHeroesFragment : BaseFragment() { + + override val layoutId = R.layout.super_heroes_fragment + override val viewModel: SuperHeroesViewModel by viewModel() + private lateinit var adapter: SuperHeroesAdapter + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initializeAdapter() + initializeRecyclerView() + viewModel.prepare() + viewModel.superHeroToOpen.observe(this, Observer { openDetail(it) }) + viewModel.superHeroes.observe(this, Observer> { showSuperHeroes(it) }) + } + + override fun configureBinding(binding: SuperHeroesFragmentBinding) { + binding.viewModel = viewModel + } + + private fun initializeAdapter() { + adapter = SuperHeroesAdapter(viewModel) + } + + private fun initializeRecyclerView() { + recycler_view.layoutManager = LinearLayoutManager(requireContext()) + recycler_view.setHasFixedSize(true) + recycler_view.adapter = adapter + } + + private fun showSuperHeroes(superHeroes: PagedList) { + adapter.submitList(superHeroes) + } + + private fun openDetail(superHeroToOpen: SuperHeroToOpen) { + val directions = actionSuperHeroesFragmentToSuperHeroDetailFragment( + superHeroToOpen.id, + superHeroToOpen.name + ) + findNavController().navigate(directions) + } + + override val activityModules = module { + bindViewModel() with provider { + SuperHeroesViewModel(instance(), instance()) + } + bind() with provider { GetSuperHeroes(instance()) } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/viewmodel/SuperHeroDetailViewModel.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/viewmodel/SuperHeroDetailViewModel.kt index cf0369d..5ddc991 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/viewmodel/SuperHeroDetailViewModel.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/viewmodel/SuperHeroDetailViewModel.kt @@ -15,14 +15,14 @@ class SuperHeroDetailViewModel( val isLoading = MutableLiveData() val superHero = MediatorLiveData() - val idOfSuperHeroToEdit = SingleLiveEvent() + val superHeroToEdit = SingleLiveEvent() fun prepare(id: String) { loadSuperHero(id) } fun onEditSelected() { - idOfSuperHeroToEdit.value = superHero.value?.id + superHeroToEdit.value = superHero.value?.let { SuperHeroToEdit(it.id, it.name) } } private fun loadSuperHero(id: String) { @@ -33,3 +33,5 @@ class SuperHeroDetailViewModel( } } } + +data class SuperHeroToEdit(val id: String, val name: String) diff --git a/app/src/main/java/com/karumi/jetpack/superheroes/ui/viewmodel/SuperHeroesViewModel.kt b/app/src/main/java/com/karumi/jetpack/superheroes/ui/viewmodel/SuperHeroesViewModel.kt index 53f0021..3e5a477 100644 --- a/app/src/main/java/com/karumi/jetpack/superheroes/ui/viewmodel/SuperHeroesViewModel.kt +++ b/app/src/main/java/com/karumi/jetpack/superheroes/ui/viewmodel/SuperHeroesViewModel.kt @@ -17,7 +17,7 @@ class SuperHeroesViewModel( val isLoading = MutableLiveData() val isShowingEmptyCase = MutableLiveData() val superHeroes = MediatorLiveData>() - val idOfSuperHeroToOpen = SingleLiveEvent() + val superHeroToOpen = SingleLiveEvent() fun prepare() { isLoading.value = true @@ -28,11 +28,13 @@ class SuperHeroesViewModel( } } - override fun onSuperHeroClicked(id: String) { - idOfSuperHeroToOpen.value = id + override fun onSuperHeroClicked(id: String, name: String) { + superHeroToOpen.value = SuperHeroToOpen(id, name) } } interface SuperHeroesListener { - fun onSuperHeroClicked(id: String) -} \ No newline at end of file + fun onSuperHeroClicked(id: String, name: String) +} + +data class SuperHeroToOpen(val id: String, val name: String) \ No newline at end of file diff --git a/app/src/main/res/layout/edit_super_hero_activity.xml b/app/src/main/res/layout/edit_super_hero_fragment.xml similarity index 93% rename from app/src/main/res/layout/edit_super_hero_activity.xml rename to app/src/main/res/layout/edit_super_hero_fragment.xml index 7a3aa82..5bf1adc 100644 --- a/app/src/main/res/layout/edit_super_hero_activity.xml +++ b/app/src/main/res/layout/edit_super_hero_fragment.xml @@ -20,19 +20,10 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - + app:layout_constraintTop_toTopOf="parent"> - + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context="com.karumi.jetpack.superheroes.ui.view.MainActivity"> - - - - - - - - - - - - - - - - + android:layout_height="?attr/actionBarSize" + android:background="?attr/colorPrimary" + android:theme="@style/AppTheme.AppBarOverlay" + app:layout_constraintTop_toTopOf="parent" + app:popupTheme="@style/AppTheme.PopupOverlay" /> + + - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/super_hero_detail_activity.xml b/app/src/main/res/layout/super_hero_detail_fragment.xml similarity index 91% rename from app/src/main/res/layout/super_hero_detail_activity.xml rename to app/src/main/res/layout/super_hero_detail_fragment.xml index ed43b0f..ef8e173 100644 --- a/app/src/main/res/layout/super_hero_detail_activity.xml +++ b/app/src/main/res/layout/super_hero_detail_fragment.xml @@ -15,28 +15,18 @@ + android:layout_height="match_parent"> - - diff --git a/app/src/main/res/layout/super_hero_row.xml b/app/src/main/res/layout/super_hero_row.xml index f2f266a..9f1e2a5 100644 --- a/app/src/main/res/layout/super_hero_row.xml +++ b/app/src/main/res/layout/super_hero_row.xml @@ -20,7 +20,7 @@ + android:onClick="@{ () -> listener.onSuperHeroClicked(superHero.id, superHero.name) }"> + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/navigation_graph.xml b/app/src/main/res/navigation/navigation_graph.xml new file mode 100644 index 0000000..3f00894 --- /dev/null +++ b/app/src/main/res/navigation/navigation_graph.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + \ No newline at end of file