From dd6b1cf526be9aa2b4c66efc3b8b5fd8ec7cad2f Mon Sep 17 00:00:00 2001 From: Diego Recalde Date: Sun, 19 Jan 2020 20:07:51 -0500 Subject: [PATCH 1/2] Issue #48: Use Navigation Component to go from the Splash Screen to the Categories Screen. - Added dependencies for Navigation Component with Safe Args. - Added Navigation Component for current Activities. Signed-off-by: Diego Recalde --- build.gradle | 9 +- buildSrc/src/main/java/Dependencies.kt | 20 +++-- presentation/build.gradle | 4 + presentation/src/main/AndroidManifest.xml | 7 +- .../coders/mu8/StartingNavHostActivity.kt | 39 ++++++++ .../mu8/categories/CategoriesActivity.kt | 69 -------------- .../mu8/categories/CategoriesFragment.kt | 68 ++++++++++++++ .../mu8/characters/CharactersActivity.kt | 71 --------------- .../mu8/characters/CharactersFragment.kt | 78 ++++++++++++++++ .../coders/mu8/comics/ComicsActivity.kt | 88 ------------------ .../coders/mu8/comics/ComicsFragment.kt | 89 +++++++++++++++++++ .../coders/mu8/splash/SplashActivity.kt | 37 -------- .../coders/mu8/splash/SplashFragment.kt | 44 +++++++++ .../mu8/utils/PresentationExtensions.kt | 12 ++- .../main/res/layout/activity_categories.xml | 26 ------ .../src/main/res/layout/activity_comics.xml | 38 -------- .../src/main/res/layout/activity_nav_host.xml | 19 ++++ .../src/main/res/layout/fragment_list.xml | 6 ++ ...haracters.xml => fragment_loader_list.xml} | 8 +- ...ctivity_splash.xml => fragment_splash.xml} | 13 ++- .../src/main/res/navigation/nav_graph.xml | 39 ++++++++ presentation/src/main/res/values/strings.xml | 2 + 22 files changed, 426 insertions(+), 360 deletions(-) create mode 100644 presentation/src/main/java/com/architect/coders/mu8/StartingNavHostActivity.kt delete mode 100644 presentation/src/main/java/com/architect/coders/mu8/categories/CategoriesActivity.kt create mode 100644 presentation/src/main/java/com/architect/coders/mu8/categories/CategoriesFragment.kt delete mode 100644 presentation/src/main/java/com/architect/coders/mu8/characters/CharactersActivity.kt create mode 100644 presentation/src/main/java/com/architect/coders/mu8/characters/CharactersFragment.kt delete mode 100644 presentation/src/main/java/com/architect/coders/mu8/comics/ComicsActivity.kt create mode 100644 presentation/src/main/java/com/architect/coders/mu8/comics/ComicsFragment.kt delete mode 100644 presentation/src/main/java/com/architect/coders/mu8/splash/SplashActivity.kt create mode 100644 presentation/src/main/java/com/architect/coders/mu8/splash/SplashFragment.kt delete mode 100644 presentation/src/main/res/layout/activity_categories.xml delete mode 100644 presentation/src/main/res/layout/activity_comics.xml create mode 100644 presentation/src/main/res/layout/activity_nav_host.xml create mode 100644 presentation/src/main/res/layout/fragment_list.xml rename presentation/src/main/res/layout/{activity_characters.xml => fragment_loader_list.xml} (84%) rename presentation/src/main/res/layout/{activity_splash.xml => fragment_splash.xml} (81%) create mode 100644 presentation/src/main/res/navigation/nav_graph.xml diff --git a/build.gradle b/build.gradle index 2242038..44813b1 100644 --- a/build.gradle +++ b/build.gradle @@ -5,10 +5,11 @@ buildscript { maven { url 'https://maven.fabric.io/public' } } dependencies { - classpath GradleDependencies.androidGradlePlugin - classpath KotlinDependencies.kotlinGradlePlugin - classpath SupportDependencies.googleService - classpath SupportDependencies.fabricTools + classpath ClasspathDependencies.androidGradlePlugin + classpath ClasspathDependencies.kotlinGradlePlugin + classpath ClasspathDependencies.googleService + classpath ClasspathDependencies.fabricTools + classpath ClasspathDependencies.safeArgs } } diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index abf0847..bfb898a 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -22,7 +22,6 @@ object Versions { internal const val testJunit = "1.1.1" internal const val robolectric = "4.3.1" internal const val coroutinesTest = "1.2.1" - internal const val lifecycleVersion = "2.1.0" internal const val firebaseAnalytics = "17.2.0" internal const val crashlytics = "2.10.1" internal const val googleService = "4.3.2" @@ -30,14 +29,24 @@ object Versions { internal const val materialVersion = "1.0.0" internal const val cardView = "28.0.0" internal const val roomVersion = "2.2.3" -} -object GradleDependencies { - const val androidGradlePlugin = "com.android.tools.build:gradle:${Versions.androidGradlePlugin}" + // Jetpack + internal const val lifecycleVersion = "2.1.0" + internal const val navigationVersion = "2.1.0" } object JetPackDependencies { const val lifecycle = "androidx.lifecycle:lifecycle-extensions:${Versions.lifecycleVersion}" + const val navigationFragment = "androidx.navigation:navigation-fragment-ktx:${Versions.navigationVersion}" + const val navigationUi = "androidx.navigation:navigation-ui-ktx:${Versions.navigationVersion}" +} + +object ClasspathDependencies { + const val androidGradlePlugin = "com.android.tools.build:gradle:${Versions.androidGradlePlugin}" + const val fabricTools = "io.fabric.tools:gradle:${Versions.fabricTools}" + const val googleService = "com.google.gms:google-services:${Versions.googleService}" + const val kotlinGradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}" + const val safeArgs = "androidx.navigation:navigation-safe-args-gradle-plugin:${Versions.navigationVersion}" } object SupportDependencies { @@ -49,13 +58,10 @@ object SupportDependencies { const val cardView = "com.android.support:cardview-v7:${Versions.cardView}" const val firebaseAnalytics = "com.google.firebase:firebase-analytics:${Versions.firebaseAnalytics}" const val crashlytics = "com.crashlytics.sdk.android:crashlytics:${Versions.crashlytics}" - const val fabricTools = "io.fabric.tools:gradle:${Versions.fabricTools}" - const val googleService = "com.google.gms:google-services:${Versions.googleService}" } object KotlinDependencies { const val kotlinStdLib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Versions.kotlin}" - const val kotlinGradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}" const val coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.coroutines}" } diff --git a/presentation/build.gradle b/presentation/build.gradle index 6320397..5727664 100644 --- a/presentation/build.gradle +++ b/presentation/build.gradle @@ -3,6 +3,7 @@ apply plugin: 'com.google.gms.google-services' apply plugin: 'io.fabric' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: "androidx.navigation.safeargs.kotlin" apply from: "$rootDir/detekt.gradle" android { @@ -26,6 +27,7 @@ android { } dependencies { + implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation project(":domain") implementation project(":data") implementation fileTree(dir: 'libs', include: ['*.jar']) @@ -33,6 +35,8 @@ dependencies { implementation KotlinDependencies.kotlinStdLib implementation JetPackDependencies.lifecycle + implementation JetPackDependencies.navigationFragment + implementation JetPackDependencies.navigationUi implementation SupportDependencies.coreKtx implementation SupportDependencies.appCompat diff --git a/presentation/src/main/AndroidManifest.xml b/presentation/src/main/AndroidManifest.xml index c35a47b..8d2caa5 100644 --- a/presentation/src/main/AndroidManifest.xml +++ b/presentation/src/main/AndroidManifest.xml @@ -15,16 +15,13 @@ android:theme="@style/AppTheme" tools:ignore="AllowBackup,GoogleAppIndexingWarning"> - + - - - + - \ No newline at end of file diff --git a/presentation/src/main/java/com/architect/coders/mu8/StartingNavHostActivity.kt b/presentation/src/main/java/com/architect/coders/mu8/StartingNavHostActivity.kt new file mode 100644 index 0000000..0ccbdcb --- /dev/null +++ b/presentation/src/main/java/com/architect/coders/mu8/StartingNavHostActivity.kt @@ -0,0 +1,39 @@ +package com.architect.coders.mu8 + +import android.os.Bundle +import android.view.View.GONE +import android.view.View.VISIBLE +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar + +class StartingNavHostActivity : AppCompatActivity() { + + private lateinit var toolbar: Toolbar + private lateinit var toolbarTitle: TextView + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_nav_host) + + toolbar = findViewById(R.id.toolbar) + + setSupportActionBar(toolbar) + supportActionBar?.setDisplayShowTitleEnabled(false) + + toolbarTitle = toolbar.findViewById(R.id.toolbar_title) + toolbarTitle.text = getString(R.string.app_name) + } + + fun setToolbarTitle(title: String) { + if (::toolbarTitle.isInitialized) toolbarTitle.text = title + } + + fun hideToolbar() { + if (::toolbar.isInitialized) toolbar.visibility = GONE + } + + fun showToolbar() { + if (::toolbar.isInitialized) toolbar.visibility = VISIBLE + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/architect/coders/mu8/categories/CategoriesActivity.kt b/presentation/src/main/java/com/architect/coders/mu8/categories/CategoriesActivity.kt deleted file mode 100644 index 6aca803..0000000 --- a/presentation/src/main/java/com/architect/coders/mu8/categories/CategoriesActivity.kt +++ /dev/null @@ -1,69 +0,0 @@ -package com.architect.coders.mu8.categories - -import android.os.Bundle -import android.widget.TextView -import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.Toolbar -import androidx.lifecycle.Observer -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.architect.coders.mu8.R -import com.architect.coders.mu8.categories.CategoriesViewModel.UiModel -import com.architect.coders.mu8.characters.CharactersActivity -import com.architect.coders.mu8.comics.ComicsActivity -import com.architect.coders.mu8.data.categories.CategoriesRepository -import com.architect.coders.mu8.utils.getViewModel -import com.architect.coders.mu8.utils.startActivity -import com.architect.codes.mu8.utils.CHARACTERS -import com.architect.codes.mu8.utils.COMICS -import com.architect.codes.mu8.utils.EVENTS -import com.architect.codes.mu8.utils.NOT_FOUND - -class CategoriesActivity : AppCompatActivity() { - - private lateinit var toolbar: Toolbar - private lateinit var toolbarTitle: TextView - private lateinit var recycler: RecyclerView - - private lateinit var viewModel: CategoriesViewModel - private lateinit var adapter: CategoriesAdapter - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_categories) - - toolbar = findViewById(R.id.toolbar) - setSupportActionBar(toolbar) - supportActionBar?.setDisplayShowTitleEnabled(false) - - toolbarTitle = findViewById(R.id.toolbar_title) - toolbarTitle.text = getString(R.string.app_name) - - recycler = findViewById(R.id.marvel_list) - - viewModel = getViewModel { CategoriesViewModel(CategoriesRepository()) } - - adapter = CategoriesAdapter(viewModel::onCategoryClicked) - recycler.layoutManager = LinearLayoutManager(this) - recycler.adapter = adapter - - viewModel.model.observe(this, Observer(::updateUi)) - } - - private fun updateUi(model: UiModel) { - when (model) { - is UiModel.Content -> { - adapter.categories = model.categories - } - is UiModel.Navigation -> { - when (model.categoryName) { - CHARACTERS -> startActivity {} - COMICS -> startActivity {} - EVENTS -> Toast.makeText(this, EVENTS, Toast.LENGTH_SHORT).show() - else -> Toast.makeText(this, NOT_FOUND, Toast.LENGTH_SHORT).show() - } - } - } - } -} diff --git a/presentation/src/main/java/com/architect/coders/mu8/categories/CategoriesFragment.kt b/presentation/src/main/java/com/architect/coders/mu8/categories/CategoriesFragment.kt new file mode 100644 index 0000000..1934340 --- /dev/null +++ b/presentation/src/main/java/com/architect/coders/mu8/categories/CategoriesFragment.kt @@ -0,0 +1,68 @@ +package com.architect.coders.mu8.categories + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.navigation.NavController +import androidx.navigation.findNavController +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.architect.coders.mu8.R +import com.architect.coders.mu8.StartingNavHostActivity +import com.architect.coders.mu8.data.categories.CategoriesRepository +import com.architect.coders.mu8.utils.getViewModel +import com.architect.codes.mu8.utils.CHARACTERS +import com.architect.codes.mu8.utils.COMICS +import com.architect.codes.mu8.utils.EVENTS +import com.architect.codes.mu8.utils.NOT_FOUND + +class CategoriesFragment : Fragment() { + + private lateinit var recycler: RecyclerView + + private lateinit var viewModel: CategoriesViewModel + private lateinit var adapter: CategoriesAdapter + + private lateinit var navController: NavController + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return inflater.inflate(R.layout.fragment_list, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + val navHostActivity = activity as StartingNavHostActivity + navHostActivity.showToolbar() + navHostActivity.setToolbarTitle(getString(R.string.app_name)) + + navController = view.findNavController() + + viewModel = getViewModel { CategoriesViewModel(CategoriesRepository()) } + + adapter = CategoriesAdapter(viewModel::onCategoryClicked) + + recycler = view.findViewById(R.id.recycler) + recycler.layoutManager = LinearLayoutManager(navHostActivity) + recycler.adapter = adapter + + viewModel.model.observe(this, Observer(::updateUi)) + } + + private fun updateUi(model: CategoriesViewModel.UiModel) { + val context = this.context ?: return + when (model) { + is CategoriesViewModel.UiModel.Content -> adapter.categories = model.categories + is CategoriesViewModel.UiModel.Navigation -> { + when (model.categoryName) { + CHARACTERS -> navController.navigate(R.id.action_categoriesFragment_to_charactersFragment) + COMICS -> navController.navigate(R.id.action_categoriesFragment_to_comicsFragment) + EVENTS -> Toast.makeText(context, EVENTS, Toast.LENGTH_SHORT).show() + else -> Toast.makeText(context, NOT_FOUND, Toast.LENGTH_SHORT).show() + } + } + } + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/architect/coders/mu8/characters/CharactersActivity.kt b/presentation/src/main/java/com/architect/coders/mu8/characters/CharactersActivity.kt deleted file mode 100644 index f8704e5..0000000 --- a/presentation/src/main/java/com/architect/coders/mu8/characters/CharactersActivity.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.architect.coders.mu8.characters - -import android.os.Bundle -import android.view.View.GONE -import android.view.View.VISIBLE -import android.widget.ProgressBar -import android.widget.TextView -import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.Toolbar -import androidx.lifecycle.Observer -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.architect.coders.mu8.R -import com.architect.coders.mu8.characters.CharactersUiModel.Content -import com.architect.coders.mu8.characters.CharactersUiModel.Loading -import com.architect.coders.mu8.characters.CharactersUiModel.Navigation -import com.architect.coders.mu8.characters.detail.CharactersDetailActivity -import com.architect.coders.mu8.data.DataApp -import com.architect.coders.mu8.data.characters.CharactersMapper -import com.architect.coders.mu8.data.characters.CharactersRepositoryImpl -import com.architect.coders.mu8.data.mapper.common.UrlsMapper -import com.architect.coders.mu8.utils.getViewModel -import com.architect.coders.mu8.utils.startActivity -import com.architect.codes.mu8.characters.CharactersUseCaseImpl - -class CharactersActivity : AppCompatActivity() { - - private val toolbar: Toolbar by lazy { findViewById(R.id.toolbar) } - private val progress: ProgressBar by lazy { findViewById(R.id.progress) } - private val recycler: RecyclerView by lazy { findViewById(R.id.recycler) } - - private lateinit var viewModel: CharactersViewModel - private lateinit var adapter: CharactersAdapter - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_characters) - - setSupportActionBar(toolbar) - supportActionBar?.setDisplayShowTitleEnabled(false) - - val toolbarTitle = findViewById(R.id.toolbar_title) - toolbarTitle.text = getString(R.string.characters_name) - - viewModel = getViewModel { - CharactersViewModel( - CharactersUseCaseImpl( - CharactersRepositoryImpl(CharactersMapper(UrlsMapper()), application as DataApp) - ) - ) - } - - adapter = CharactersAdapter(viewModel::onCharacterClicked) - recycler.layoutManager = LinearLayoutManager(this) - recycler.adapter = adapter - - viewModel.model.observe(this, Observer(::updateUi)) - } - - private fun updateUi(model: CharactersUiModel) { - progress.visibility = if (model == Loading) VISIBLE else GONE - - when (model) { - is Content -> { - adapter.characters = model.characters - progress.visibility = GONE - } - is Navigation -> startActivity {} - } - } -} diff --git a/presentation/src/main/java/com/architect/coders/mu8/characters/CharactersFragment.kt b/presentation/src/main/java/com/architect/coders/mu8/characters/CharactersFragment.kt new file mode 100644 index 0000000..fc5a0cd --- /dev/null +++ b/presentation/src/main/java/com/architect/coders/mu8/characters/CharactersFragment.kt @@ -0,0 +1,78 @@ +package com.architect.coders.mu8.characters + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ProgressBar +import android.widget.Toast +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.navigation.NavController +import androidx.navigation.findNavController +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.architect.coders.mu8.R +import com.architect.coders.mu8.StartingNavHostActivity +import com.architect.coders.mu8.data.DataApp +import com.architect.coders.mu8.data.characters.CharactersMapper +import com.architect.coders.mu8.data.characters.CharactersRepositoryImpl +import com.architect.coders.mu8.data.mapper.common.UrlsMapper +import com.architect.coders.mu8.utils.getViewModel +import com.architect.codes.mu8.characters.CharactersUseCaseImpl +import com.architect.codes.mu8.utils.CHARACTERS + +class CharactersFragment : Fragment() { + + private lateinit var recycler: RecyclerView + private lateinit var progress: ProgressBar + + private lateinit var viewModel: CharactersViewModel + private lateinit var adapter: CharactersAdapter + private lateinit var navController: NavController + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return inflater.inflate(R.layout.fragment_loader_list, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + val navHostActivity = activity as StartingNavHostActivity + navHostActivity.setToolbarTitle(getString(R.string.characters_name)) + + navController = view.findNavController() + + viewModel = getViewModel { + CharactersViewModel( + CharactersUseCaseImpl( + CharactersRepositoryImpl(CharactersMapper(UrlsMapper()), navHostActivity.applicationContext as DataApp) + ) + ) + } + + adapter = CharactersAdapter(viewModel::onCharacterClicked) + + progress = view.findViewById(R.id.progress) + + recycler = view.findViewById(R.id.recycler) + recycler.layoutManager = LinearLayoutManager(context) + recycler.adapter = adapter + + viewModel.model.observe(this, Observer(::updateUi)) + } + + private fun updateUi(model: CharactersUiModel) { + val context = this.context ?: return + + progress.visibility = if (model == CharactersUiModel.Loading) View.VISIBLE else View.GONE + + when (model) { + is CharactersUiModel.Content -> { + adapter.characters = model.characters + progress.visibility = View.GONE + } + is CharactersUiModel.Navigation -> { + Toast.makeText(context, CHARACTERS, Toast.LENGTH_SHORT).show() + } + } + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/architect/coders/mu8/comics/ComicsActivity.kt b/presentation/src/main/java/com/architect/coders/mu8/comics/ComicsActivity.kt deleted file mode 100644 index 445f328..0000000 --- a/presentation/src/main/java/com/architect/coders/mu8/comics/ComicsActivity.kt +++ /dev/null @@ -1,88 +0,0 @@ -package com.architect.coders.mu8.comics - -import android.os.Bundle -import android.widget.ProgressBar -import android.widget.TextView -import android.widget.Toast -import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.Toolbar -import androidx.lifecycle.Observer -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.architect.coders.mu8.R -import com.architect.coders.mu8.comics.ComicsViewModel.UiModel.InternetError -import com.architect.coders.mu8.comics.ComicsViewModel.UiModel.LoadData -import com.architect.coders.mu8.comics.ComicsViewModel.UiModel.NavigateTo -import com.architect.coders.mu8.comics.ComicsViewModel.UiModel.ShowLoading -import com.architect.coders.mu8.data.comics.ComicRepositoryImpl -import com.architect.coders.mu8.data.comics.ComicsMapper -import com.architect.coders.mu8.utils.getViewModel -import com.architect.coders.mu8.utils.makeItGone -import com.architect.coders.mu8.utils.makeItVisible -import com.architect.codes.mu8.comics.ComicsUseCaseImpl -import com.google.android.material.snackbar.Snackbar - -class ComicsActivity : AppCompatActivity() { - - private val progress: ProgressBar by lazy { findViewById(R.id.comic_activity_progress) } - private val recycler: RecyclerView by lazy { findViewById(R.id.comic_activity_recycler) } - - private lateinit var toolbar: Toolbar - private lateinit var toolbarTitle: TextView - private lateinit var viewModel: ComicsViewModel - private lateinit var adapter: ComicsAdapter - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_comics) - - toolbar = findViewById(R.id.comic_activity_toolbar) - setSupportActionBar(toolbar) - supportActionBar?.setDisplayShowTitleEnabled(false) - - toolbarTitle = findViewById(R.id.toolbar_title) - toolbarTitle.text = getString(R.string.comics_name) - - viewModel = getViewModel { - ComicsViewModel( - ComicsUseCaseImpl( - ComicRepositoryImpl(ComicsMapper()) - ) - ) - } - - adapter = ComicsAdapter(viewModel::onComicClicked) - recycler.layoutManager = GridLayoutManager(this, GRID_COLUMS) - recycler.adapter = adapter - - viewModel.model.observe(this, Observer(::updateUi)) - } - - private fun updateUi(uiModel: ComicsViewModel.UiModel) { - return when (uiModel) { - is ShowLoading -> { - progress.makeItVisible() - recycler.makeItGone() - } - is LoadData -> { - adapter.comics = uiModel.comics - progress.makeItGone() - recycler.makeItVisible() - } - is InternetError -> { - progress.makeItGone() - recycler.makeItGone() - Snackbar.make( - recycler, - getString(R.string.error_internet_message), - Snackbar.LENGTH_LONG - ).show() - } - is NavigateTo -> Toast.makeText(this, uiModel.comic.title, Toast.LENGTH_LONG).show() - } - } - - companion object { - private const val GRID_COLUMS = 2 - } -} diff --git a/presentation/src/main/java/com/architect/coders/mu8/comics/ComicsFragment.kt b/presentation/src/main/java/com/architect/coders/mu8/comics/ComicsFragment.kt new file mode 100644 index 0000000..5817f19 --- /dev/null +++ b/presentation/src/main/java/com/architect/coders/mu8/comics/ComicsFragment.kt @@ -0,0 +1,89 @@ +package com.architect.coders.mu8.comics + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ProgressBar +import android.widget.Toast +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.navigation.NavController +import androidx.navigation.findNavController +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.architect.coders.mu8.R +import com.architect.coders.mu8.StartingNavHostActivity +import com.architect.coders.mu8.data.comics.ComicRepositoryImpl +import com.architect.coders.mu8.data.comics.ComicsMapper +import com.architect.coders.mu8.utils.getViewModel +import com.architect.coders.mu8.utils.makeItGone +import com.architect.coders.mu8.utils.makeItVisible +import com.architect.codes.mu8.comics.ComicsUseCaseImpl +import com.google.android.material.snackbar.Snackbar + +class ComicsFragment : Fragment() { + + private lateinit var recycler: RecyclerView + private lateinit var progress: ProgressBar + + private lateinit var viewModel: ComicsViewModel + private lateinit var adapter: ComicsAdapter + private lateinit var navController: NavController + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return inflater.inflate(R.layout.fragment_loader_list, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + val navHostActivity = activity as StartingNavHostActivity + navHostActivity.showToolbar() + navHostActivity.setToolbarTitle(getString(R.string.comics_name)) + + navController = view.findNavController() + + viewModel = getViewModel { + ComicsViewModel( + ComicsUseCaseImpl( + ComicRepositoryImpl(ComicsMapper()) + ) + ) + } + + adapter = ComicsAdapter(viewModel::onComicClicked) + + progress = view.findViewById(R.id.progress) + + recycler = view.findViewById(R.id.recycler) + recycler.layoutManager = GridLayoutManager(context, GRID_COLUMNS) + recycler.adapter = adapter + + viewModel.model.observe(this, Observer(::updateUi)) + } + + private fun updateUi(uiModel: ComicsViewModel.UiModel) { + val context = this.context ?: return + + return when (uiModel) { + is ComicsViewModel.UiModel.ShowLoading -> { + progress.makeItVisible() + recycler.makeItGone() + } + is ComicsViewModel.UiModel.LoadData -> { + adapter.comics = uiModel.comics + progress.makeItGone() + recycler.makeItVisible() + } + is ComicsViewModel.UiModel.InternetError -> { + progress.makeItGone() + recycler.makeItGone() + Snackbar.make(recycler, getString(R.string.error_internet_message), Snackbar.LENGTH_LONG).show() + } + is ComicsViewModel.UiModel.NavigateTo -> Toast.makeText(context, uiModel.comic.title, Toast.LENGTH_LONG).show() + } + } + + companion object { + private const val GRID_COLUMNS = 2 + } +} diff --git a/presentation/src/main/java/com/architect/coders/mu8/splash/SplashActivity.kt b/presentation/src/main/java/com/architect/coders/mu8/splash/SplashActivity.kt deleted file mode 100644 index 1a133af..0000000 --- a/presentation/src/main/java/com/architect/coders/mu8/splash/SplashActivity.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.architect.coders.mu8.splash - -import android.os.Bundle -import android.widget.TextView -import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.Observer -import com.architect.coders.mu8.R -import com.architect.coders.mu8.categories.CategoriesActivity -import com.architect.coders.mu8.splash.SplashViewModel.UiModel -import com.architect.coders.mu8.utils.getViewModel -import com.architect.coders.mu8.utils.startActivity - -class SplashActivity : AppCompatActivity() { - - private lateinit var viewModel: SplashViewModel - private lateinit var tvVersion: TextView - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_splash) - - tvVersion = findViewById(R.id.tv_version) - viewModel = getViewModel { SplashViewModel() } - - viewModel.model.observe(this, Observer(::initUi)) - } - - private fun initUi(model: UiModel) { - when (model) { - is UiModel.GetVersion -> tvVersion.text = getString(R.string.version_name, model.versionName) - is UiModel.Navigation -> { - startActivity {} - finish() - } - } - } -} diff --git a/presentation/src/main/java/com/architect/coders/mu8/splash/SplashFragment.kt b/presentation/src/main/java/com/architect/coders/mu8/splash/SplashFragment.kt new file mode 100644 index 0000000..9e02c84 --- /dev/null +++ b/presentation/src/main/java/com/architect/coders/mu8/splash/SplashFragment.kt @@ -0,0 +1,44 @@ +package com.architect.coders.mu8.splash + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.navigation.NavController +import androidx.navigation.findNavController +import com.architect.coders.mu8.R +import com.architect.coders.mu8.StartingNavHostActivity +import com.architect.coders.mu8.utils.getViewModel + +class SplashFragment : Fragment() { + + private lateinit var viewModel: SplashViewModel + private lateinit var appVersion: TextView + + private lateinit var navController: NavController + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return inflater.inflate(R.layout.fragment_splash, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + (activity as StartingNavHostActivity).hideToolbar() + + navController = view.findNavController() + + appVersion = view.findViewById(R.id.tv_version) + viewModel = getViewModel { SplashViewModel() } + + viewModel.model.observe(this, Observer(::initUi)) + } + + private fun initUi(model: SplashViewModel.UiModel) { + when (model) { + is SplashViewModel.UiModel.GetVersion -> appVersion.text = getString(R.string.version_name, model.versionName) + is SplashViewModel.UiModel.Navigation -> navController.navigate(R.id.action_splashFragment_to_categoriesFragment) + } + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/architect/coders/mu8/utils/PresentationExtensions.kt b/presentation/src/main/java/com/architect/coders/mu8/utils/PresentationExtensions.kt index 5f039e3..d231347 100644 --- a/presentation/src/main/java/com/architect/coders/mu8/utils/PresentationExtensions.kt +++ b/presentation/src/main/java/com/architect/coders/mu8/utils/PresentationExtensions.kt @@ -1,15 +1,16 @@ +@file:Suppress("UNCHECKED_CAST") + package com.architect.coders.mu8.utils import android.app.Activity import android.content.Context import android.content.Intent -import android.net.ConnectivityManager -import android.net.NetworkInfo import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView import androidx.annotation.LayoutRes +import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider @@ -64,3 +65,10 @@ inline fun FragmentActivity.getViewModel(crossinline fac } return ViewModelProviders.of(this, vmFactory)[T::class.java] } + +inline fun Fragment.getViewModel(crossinline factory: () -> T): T { + val vmFactory = object : ViewModelProvider.Factory { + override fun create(modelClass: Class): U = factory() as U + } + return ViewModelProviders.of(this, vmFactory)[T::class.java] +} diff --git a/presentation/src/main/res/layout/activity_categories.xml b/presentation/src/main/res/layout/activity_categories.xml deleted file mode 100644 index 183c5a8..0000000 --- a/presentation/src/main/res/layout/activity_categories.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/presentation/src/main/res/layout/activity_comics.xml b/presentation/src/main/res/layout/activity_comics.xml deleted file mode 100644 index 4f290ed..0000000 --- a/presentation/src/main/res/layout/activity_comics.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/presentation/src/main/res/layout/activity_nav_host.xml b/presentation/src/main/res/layout/activity_nav_host.xml new file mode 100644 index 0000000..fc066b9 --- /dev/null +++ b/presentation/src/main/res/layout/activity_nav_host.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/presentation/src/main/res/layout/fragment_list.xml b/presentation/src/main/res/layout/fragment_list.xml new file mode 100644 index 0000000..d110909 --- /dev/null +++ b/presentation/src/main/res/layout/fragment_list.xml @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/presentation/src/main/res/layout/activity_characters.xml b/presentation/src/main/res/layout/fragment_loader_list.xml similarity index 84% rename from presentation/src/main/res/layout/activity_characters.xml rename to presentation/src/main/res/layout/fragment_loader_list.xml index 640c9a6..efd83de 100644 --- a/presentation/src/main/res/layout/activity_characters.xml +++ b/presentation/src/main/res/layout/fragment_loader_list.xml @@ -6,10 +6,6 @@ android:layout_height="match_parent" tools:context=".categories.CategoriesActivity"> - - + app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent" /> \ No newline at end of file diff --git a/presentation/src/main/res/layout/activity_splash.xml b/presentation/src/main/res/layout/fragment_splash.xml similarity index 81% rename from presentation/src/main/res/layout/activity_splash.xml rename to presentation/src/main/res/layout/fragment_splash.xml index da492a5..18b1e61 100644 --- a/presentation/src/main/res/layout/activity_splash.xml +++ b/presentation/src/main/res/layout/fragment_splash.xml @@ -1,11 +1,9 @@ + android:background="@color/colorPrimary"> + app:layout_constraintStart_toStartOf="parent" /> + app:layout_constraintTop_toTopOf="parent" /> + + + + + + + + + + + + + \ No newline at end of file diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index c7de24d..e01e04e 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -6,4 +6,6 @@ Characters Comics + + Hello blank fragment From fc73e30376e969f63106f5aba05b69d94d4b22e1 Mon Sep 17 00:00:00 2001 From: Diego Recalde Date: Sun, 26 Jan 2020 15:51:22 -0500 Subject: [PATCH 2/2] Issue #48: Use Navigation Component to go from the Splash Screen to the Categories Screen. - Added Navigation Component for Event Activity. - Created approach for back navigation. Signed-off-by: Diego Recalde --- presentation/build.gradle | 9 +++ presentation/src/main/AndroidManifest.xml | 3 +- .../mu8/categories/CategoriesFragment.kt | 18 ++--- .../mu8/characters/CharactersFragment.kt | 24 +++---- .../mu8/characters/CharactersViewModel.kt | 6 +- .../coders/mu8/comics/ComicsFragment.kt | 11 +-- .../coders/mu8/comics/ComicsViewModel.kt | 2 +- .../coders/mu8/common/NavigationFragment.kt | 34 +++++++++ .../mu8/{utils => common}/ScopedViewModel.kt | 2 +- .../{ => common}/StartingNavHostActivity.kt | 3 +- .../coders/mu8/events/EventsActivity.kt | 56 --------------- .../coders/mu8/events/EventsFragment.kt | 70 +++++++++++++++++++ .../coders/mu8/events/EventsViewModel.kt | 2 +- .../coders/mu8/splash/SplashFragment.kt | 2 +- .../coders/mu8/splash/SplashViewModel.kt | 2 +- .../src/main/res/layout/activity_events.xml | 33 --------- .../src/main/res/layout/activity_nav_host.xml | 2 +- .../src/main/res/navigation/nav_graph.xml | 56 ++++++++++++--- 18 files changed, 197 insertions(+), 138 deletions(-) create mode 100644 presentation/src/main/java/com/architect/coders/mu8/common/NavigationFragment.kt rename presentation/src/main/java/com/architect/coders/mu8/{utils => common}/ScopedViewModel.kt (89%) rename presentation/src/main/java/com/architect/coders/mu8/{ => common}/StartingNavHostActivity.kt (93%) delete mode 100644 presentation/src/main/java/com/architect/coders/mu8/events/EventsActivity.kt create mode 100644 presentation/src/main/java/com/architect/coders/mu8/events/EventsFragment.kt delete mode 100644 presentation/src/main/res/layout/activity_events.xml diff --git a/presentation/build.gradle b/presentation/build.gradle index 2fc0e32..1dc51f7 100644 --- a/presentation/build.gradle +++ b/presentation/build.gradle @@ -24,6 +24,15 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8.toString() + } } dependencies { diff --git a/presentation/src/main/AndroidManifest.xml b/presentation/src/main/AndroidManifest.xml index 61d5fb2..b0149ce 100644 --- a/presentation/src/main/AndroidManifest.xml +++ b/presentation/src/main/AndroidManifest.xml @@ -15,7 +15,7 @@ android:theme="@style/AppTheme" tools:ignore="AllowBackup,GoogleAppIndexingWarning"> - + @@ -23,6 +23,5 @@ - \ No newline at end of file diff --git a/presentation/src/main/java/com/architect/coders/mu8/categories/CategoriesFragment.kt b/presentation/src/main/java/com/architect/coders/mu8/categories/CategoriesFragment.kt index 1934340..72a6144 100644 --- a/presentation/src/main/java/com/architect/coders/mu8/categories/CategoriesFragment.kt +++ b/presentation/src/main/java/com/architect/coders/mu8/categories/CategoriesFragment.kt @@ -5,14 +5,15 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast -import androidx.fragment.app.Fragment +import androidx.activity.OnBackPressedCallback import androidx.lifecycle.Observer import androidx.navigation.NavController import androidx.navigation.findNavController import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.architect.coders.mu8.R -import com.architect.coders.mu8.StartingNavHostActivity +import com.architect.coders.mu8.common.NavigationFragment +import com.architect.coders.mu8.common.StartingNavHostActivity import com.architect.coders.mu8.data.categories.CategoriesRepository import com.architect.coders.mu8.utils.getViewModel import com.architect.codes.mu8.utils.CHARACTERS @@ -20,14 +21,15 @@ import com.architect.codes.mu8.utils.COMICS import com.architect.codes.mu8.utils.EVENTS import com.architect.codes.mu8.utils.NOT_FOUND -class CategoriesFragment : Fragment() { +class CategoriesFragment : NavigationFragment() { private lateinit var recycler: RecyclerView private lateinit var viewModel: CategoriesViewModel private lateinit var adapter: CategoriesAdapter - private lateinit var navController: NavController + private lateinit var navigationController: NavController + private lateinit var callback: OnBackPressedCallback override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return inflater.inflate(R.layout.fragment_list, container, false) @@ -38,7 +40,7 @@ class CategoriesFragment : Fragment() { navHostActivity.showToolbar() navHostActivity.setToolbarTitle(getString(R.string.app_name)) - navController = view.findNavController() + navigationController = view.findNavController() viewModel = getViewModel { CategoriesViewModel(CategoriesRepository()) } @@ -57,9 +59,9 @@ class CategoriesFragment : Fragment() { is CategoriesViewModel.UiModel.Content -> adapter.categories = model.categories is CategoriesViewModel.UiModel.Navigation -> { when (model.categoryName) { - CHARACTERS -> navController.navigate(R.id.action_categoriesFragment_to_charactersFragment) - COMICS -> navController.navigate(R.id.action_categoriesFragment_to_comicsFragment) - EVENTS -> Toast.makeText(context, EVENTS, Toast.LENGTH_SHORT).show() + CHARACTERS -> navigationController.navigate(R.id.action_categoriesFragment_to_charactersFragment) + COMICS -> navigationController.navigate(R.id.action_categoriesFragment_to_comicsFragment) + EVENTS -> navigationController.navigate(R.id.action_categoriesFragment_to_eventsFragment) else -> Toast.makeText(context, NOT_FOUND, Toast.LENGTH_SHORT).show() } } diff --git a/presentation/src/main/java/com/architect/coders/mu8/characters/CharactersFragment.kt b/presentation/src/main/java/com/architect/coders/mu8/characters/CharactersFragment.kt index fc5a0cd..285e81e 100644 --- a/presentation/src/main/java/com/architect/coders/mu8/characters/CharactersFragment.kt +++ b/presentation/src/main/java/com/architect/coders/mu8/characters/CharactersFragment.kt @@ -6,30 +6,28 @@ import android.view.View import android.view.ViewGroup import android.widget.ProgressBar import android.widget.Toast -import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import androidx.navigation.NavController import androidx.navigation.findNavController import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.architect.coders.mu8.R -import com.architect.coders.mu8.StartingNavHostActivity +import com.architect.coders.mu8.common.NavigationFragment +import com.architect.coders.mu8.common.StartingNavHostActivity import com.architect.coders.mu8.data.DataApp -import com.architect.coders.mu8.data.characters.CharactersMapper import com.architect.coders.mu8.data.characters.CharactersRepositoryImpl -import com.architect.coders.mu8.data.mapper.common.UrlsMapper import com.architect.coders.mu8.utils.getViewModel import com.architect.codes.mu8.characters.CharactersUseCaseImpl -import com.architect.codes.mu8.utils.CHARACTERS -class CharactersFragment : Fragment() { +class CharactersFragment : NavigationFragment(R.id.action_charactersFragment_to_categoriesFragment) { private lateinit var recycler: RecyclerView private lateinit var progress: ProgressBar private lateinit var viewModel: CharactersViewModel private lateinit var adapter: CharactersAdapter - private lateinit var navController: NavController + + private lateinit var navigationController: NavController override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return inflater.inflate(R.layout.fragment_loader_list, container, false) @@ -39,14 +37,10 @@ class CharactersFragment : Fragment() { val navHostActivity = activity as StartingNavHostActivity navHostActivity.setToolbarTitle(getString(R.string.characters_name)) - navController = view.findNavController() + navigationController = view.findNavController() viewModel = getViewModel { - CharactersViewModel( - CharactersUseCaseImpl( - CharactersRepositoryImpl(CharactersMapper(UrlsMapper()), navHostActivity.applicationContext as DataApp) - ) - ) + CharactersViewModel(CharactersUseCaseImpl(CharactersRepositoryImpl(navHostActivity.application as DataApp))) } adapter = CharactersAdapter(viewModel::onCharacterClicked) @@ -70,9 +64,7 @@ class CharactersFragment : Fragment() { adapter.characters = model.characters progress.visibility = View.GONE } - is CharactersUiModel.Navigation -> { - Toast.makeText(context, CHARACTERS, Toast.LENGTH_SHORT).show() - } + is CharactersUiModel.Navigation -> Toast.makeText(context, model.character.name, Toast.LENGTH_LONG).show() } } } \ No newline at end of file diff --git a/presentation/src/main/java/com/architect/coders/mu8/characters/CharactersViewModel.kt b/presentation/src/main/java/com/architect/coders/mu8/characters/CharactersViewModel.kt index 82adfde..8f5b9bb 100644 --- a/presentation/src/main/java/com/architect/coders/mu8/characters/CharactersViewModel.kt +++ b/presentation/src/main/java/com/architect/coders/mu8/characters/CharactersViewModel.kt @@ -2,7 +2,7 @@ package com.architect.coders.mu8.characters import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.architect.coders.mu8.utils.ScopedViewModel +import com.architect.coders.mu8.common.ScopedViewModel import com.architect.codes.mu8.characters.Character import com.architect.codes.mu8.characters.CharactersUseCase import kotlinx.coroutines.launch @@ -23,5 +23,7 @@ class CharactersViewModel(private val charactersUseCase: CharactersUseCase) : Sc } } - fun onCharacterClicked(character: Character) = Unit + fun onCharacterClicked(character: Character) { + _model.value = CharactersUiModel.Navigation(character) + } } diff --git a/presentation/src/main/java/com/architect/coders/mu8/comics/ComicsFragment.kt b/presentation/src/main/java/com/architect/coders/mu8/comics/ComicsFragment.kt index 5817f19..baae9e1 100644 --- a/presentation/src/main/java/com/architect/coders/mu8/comics/ComicsFragment.kt +++ b/presentation/src/main/java/com/architect/coders/mu8/comics/ComicsFragment.kt @@ -6,14 +6,14 @@ import android.view.View import android.view.ViewGroup import android.widget.ProgressBar import android.widget.Toast -import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import androidx.navigation.NavController import androidx.navigation.findNavController import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import com.architect.coders.mu8.R -import com.architect.coders.mu8.StartingNavHostActivity +import com.architect.coders.mu8.common.NavigationFragment +import com.architect.coders.mu8.common.StartingNavHostActivity import com.architect.coders.mu8.data.comics.ComicRepositoryImpl import com.architect.coders.mu8.data.comics.ComicsMapper import com.architect.coders.mu8.utils.getViewModel @@ -22,14 +22,15 @@ import com.architect.coders.mu8.utils.makeItVisible import com.architect.codes.mu8.comics.ComicsUseCaseImpl import com.google.android.material.snackbar.Snackbar -class ComicsFragment : Fragment() { +class ComicsFragment : NavigationFragment(R.id.action_comicsFragment_to_categoriesFragment) { private lateinit var recycler: RecyclerView private lateinit var progress: ProgressBar private lateinit var viewModel: ComicsViewModel private lateinit var adapter: ComicsAdapter - private lateinit var navController: NavController + + private lateinit var navigationController: NavController override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return inflater.inflate(R.layout.fragment_loader_list, container, false) @@ -40,7 +41,7 @@ class ComicsFragment : Fragment() { navHostActivity.showToolbar() navHostActivity.setToolbarTitle(getString(R.string.comics_name)) - navController = view.findNavController() + navigationController = view.findNavController() viewModel = getViewModel { ComicsViewModel( diff --git a/presentation/src/main/java/com/architect/coders/mu8/comics/ComicsViewModel.kt b/presentation/src/main/java/com/architect/coders/mu8/comics/ComicsViewModel.kt index e076b76..45a2ef1 100644 --- a/presentation/src/main/java/com/architect/coders/mu8/comics/ComicsViewModel.kt +++ b/presentation/src/main/java/com/architect/coders/mu8/comics/ComicsViewModel.kt @@ -3,7 +3,7 @@ package com.architect.coders.mu8.comics import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.architect.coders.mu8.comics.ComicsViewModel.UiModel.* -import com.architect.coders.mu8.utils.ScopedViewModel +import com.architect.coders.mu8.common.ScopedViewModel import com.architect.codes.mu8.comics.ComicUseCase import com.architect.codes.mu8.comics.Comic import kotlinx.coroutines.launch diff --git a/presentation/src/main/java/com/architect/coders/mu8/common/NavigationFragment.kt b/presentation/src/main/java/com/architect/coders/mu8/common/NavigationFragment.kt new file mode 100644 index 0000000..ef77372 --- /dev/null +++ b/presentation/src/main/java/com/architect/coders/mu8/common/NavigationFragment.kt @@ -0,0 +1,34 @@ +package com.architect.coders.mu8.common + +import android.os.Bundle +import androidx.activity.OnBackPressedCallback +import androidx.activity.addCallback +import androidx.annotation.CallSuper +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.NavHostFragment +import com.architect.codes.mu8.common.Scope + +abstract class NavigationFragment(private val action: Int? = null) : Fragment(), Scope by Scope.Implementation() { + + private lateinit var callback: OnBackPressedCallback + + @CallSuper + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + callback = requireActivity().onBackPressedDispatcher.addCallback(this, true) { onNavigateBack() } + } + + private fun onNavigateBack() { + if (action == null) { + activity?.finish() + return + } + NavHostFragment.findNavController(this).navigate(action) + } + + @CallSuper + override fun onDestroyView() { + super.onDestroyView() + callback.remove() + } +} diff --git a/presentation/src/main/java/com/architect/coders/mu8/utils/ScopedViewModel.kt b/presentation/src/main/java/com/architect/coders/mu8/common/ScopedViewModel.kt similarity index 89% rename from presentation/src/main/java/com/architect/coders/mu8/utils/ScopedViewModel.kt rename to presentation/src/main/java/com/architect/coders/mu8/common/ScopedViewModel.kt index 2f3b10d..c55f978 100644 --- a/presentation/src/main/java/com/architect/coders/mu8/utils/ScopedViewModel.kt +++ b/presentation/src/main/java/com/architect/coders/mu8/common/ScopedViewModel.kt @@ -1,4 +1,4 @@ -package com.architect.coders.mu8.utils +package com.architect.coders.mu8.common import androidx.annotation.CallSuper import androidx.lifecycle.ViewModel diff --git a/presentation/src/main/java/com/architect/coders/mu8/StartingNavHostActivity.kt b/presentation/src/main/java/com/architect/coders/mu8/common/StartingNavHostActivity.kt similarity index 93% rename from presentation/src/main/java/com/architect/coders/mu8/StartingNavHostActivity.kt rename to presentation/src/main/java/com/architect/coders/mu8/common/StartingNavHostActivity.kt index 0ccbdcb..b16dbbe 100644 --- a/presentation/src/main/java/com/architect/coders/mu8/StartingNavHostActivity.kt +++ b/presentation/src/main/java/com/architect/coders/mu8/common/StartingNavHostActivity.kt @@ -1,4 +1,4 @@ -package com.architect.coders.mu8 +package com.architect.coders.mu8.common import android.os.Bundle import android.view.View.GONE @@ -6,6 +6,7 @@ import android.view.View.VISIBLE import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar +import com.architect.coders.mu8.R class StartingNavHostActivity : AppCompatActivity() { diff --git a/presentation/src/main/java/com/architect/coders/mu8/events/EventsActivity.kt b/presentation/src/main/java/com/architect/coders/mu8/events/EventsActivity.kt deleted file mode 100644 index c9d8fb1..0000000 --- a/presentation/src/main/java/com/architect/coders/mu8/events/EventsActivity.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.architect.coders.mu8.events - -import androidx.appcompat.app.AppCompatActivity -import android.os.Bundle -import android.view.View.GONE -import android.view.View.VISIBLE -import android.widget.ProgressBar -import android.widget.TextView -import android.widget.Toast -import androidx.appcompat.widget.Toolbar -import androidx.lifecycle.Observer -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.architect.coders.mu8.R -import com.architect.coders.mu8.data.events.EventsMapper -import com.architect.coders.mu8.data.events.EventsRepositoryImpl -import com.architect.coders.mu8.events.EventsUiModel.* -import com.architect.coders.mu8.utils.getViewModel -import com.architect.codes.mu8.events.EventsUserCaseImpl - -class EventsActivity : AppCompatActivity() { - - private val recyclerView: RecyclerView by lazy { findViewById(R.id.recycler) } - private val progress: ProgressBar by lazy { findViewById(R.id.progress) } - private val toolbar: Toolbar by lazy { findViewById(R.id.toolbar) } - - private lateinit var viewModel: EventsViewModel - private lateinit var adapter: EventsAdapter - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_events) - - setSupportActionBar(toolbar) - - val toolbarTitle = findViewById(R.id.toolbar_title) - toolbarTitle.text = getString(R.string.events_name) - - viewModel = getViewModel { EventsViewModel(EventsUserCaseImpl(EventsRepositoryImpl(EventsMapper()))) } - - adapter = EventsAdapter(viewModel::onEventClick) - recyclerView.layoutManager = LinearLayoutManager(this) - recyclerView.adapter = adapter - - viewModel.model.observe(this, Observer(::updateUi)) - } - - private fun updateUi(model: EventsUiModel) { - progress.visibility = if (model == Loading) VISIBLE else GONE - - when (model) { - is Contect -> adapter.events = model.events - is Navegation -> Toast.makeText(this, model.event.title, Toast.LENGTH_LONG).show() - } - } -} diff --git a/presentation/src/main/java/com/architect/coders/mu8/events/EventsFragment.kt b/presentation/src/main/java/com/architect/coders/mu8/events/EventsFragment.kt new file mode 100644 index 0000000..39403aa --- /dev/null +++ b/presentation/src/main/java/com/architect/coders/mu8/events/EventsFragment.kt @@ -0,0 +1,70 @@ +package com.architect.coders.mu8.events + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.View.GONE +import android.view.View.VISIBLE +import android.view.ViewGroup +import android.widget.ProgressBar +import android.widget.Toast +import androidx.lifecycle.Observer +import androidx.navigation.NavController +import androidx.navigation.findNavController +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.architect.coders.mu8.R +import com.architect.coders.mu8.common.NavigationFragment +import com.architect.coders.mu8.common.StartingNavHostActivity +import com.architect.coders.mu8.data.events.EventsMapper +import com.architect.coders.mu8.data.events.EventsRepositoryImpl +import com.architect.coders.mu8.events.EventsUiModel.Contect +import com.architect.coders.mu8.events.EventsUiModel.Loading +import com.architect.coders.mu8.events.EventsUiModel.Navegation +import com.architect.coders.mu8.utils.getViewModel +import com.architect.codes.mu8.events.EventsUserCaseImpl + +class EventsFragment : NavigationFragment(R.id.action_eventsFragment_to_categoriesFragment) { + + private lateinit var recycler: RecyclerView + private lateinit var progress: ProgressBar + + private lateinit var viewModel: EventsViewModel + private lateinit var adapter: EventsAdapter + + private lateinit var navigationController: NavController + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return inflater.inflate(R.layout.fragment_loader_list, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + val navHostActivity = activity as StartingNavHostActivity + navHostActivity.setToolbarTitle(getString(R.string.events_name)) + + navigationController = view.findNavController() + + viewModel = getViewModel { EventsViewModel(EventsUserCaseImpl(EventsRepositoryImpl(EventsMapper()))) } + + adapter = EventsAdapter(viewModel::onEventClick) + + progress = view.findViewById(R.id.progress) + + recycler = view.findViewById(R.id.recycler) + recycler.layoutManager = LinearLayoutManager(context) + recycler.adapter = adapter + + viewModel.model.observe(this, Observer(::updateUi)) + } + + private fun updateUi(model: EventsUiModel) { + val context = this.context ?: return + + progress.visibility = if (model == Loading) VISIBLE else GONE + + when (model) { + is Contect -> adapter.events = model.events + is Navegation -> Toast.makeText(context, model.event.title, Toast.LENGTH_LONG).show() + } + } +} diff --git a/presentation/src/main/java/com/architect/coders/mu8/events/EventsViewModel.kt b/presentation/src/main/java/com/architect/coders/mu8/events/EventsViewModel.kt index 8b0af77..677d577 100644 --- a/presentation/src/main/java/com/architect/coders/mu8/events/EventsViewModel.kt +++ b/presentation/src/main/java/com/architect/coders/mu8/events/EventsViewModel.kt @@ -3,7 +3,7 @@ package com.architect.coders.mu8.events import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.architect.coders.mu8.events.EventsUiModel.Navegation -import com.architect.coders.mu8.utils.ScopedViewModel +import com.architect.coders.mu8.common.ScopedViewModel import com.architect.codes.mu8.events.Event import com.architect.codes.mu8.events.EventsUseCase import kotlinx.coroutines.launch diff --git a/presentation/src/main/java/com/architect/coders/mu8/splash/SplashFragment.kt b/presentation/src/main/java/com/architect/coders/mu8/splash/SplashFragment.kt index 9e02c84..94c9f7f 100644 --- a/presentation/src/main/java/com/architect/coders/mu8/splash/SplashFragment.kt +++ b/presentation/src/main/java/com/architect/coders/mu8/splash/SplashFragment.kt @@ -10,7 +10,7 @@ import androidx.lifecycle.Observer import androidx.navigation.NavController import androidx.navigation.findNavController import com.architect.coders.mu8.R -import com.architect.coders.mu8.StartingNavHostActivity +import com.architect.coders.mu8.common.StartingNavHostActivity import com.architect.coders.mu8.utils.getViewModel class SplashFragment : Fragment() { diff --git a/presentation/src/main/java/com/architect/coders/mu8/splash/SplashViewModel.kt b/presentation/src/main/java/com/architect/coders/mu8/splash/SplashViewModel.kt index 7f4c4d0..e29e8f4 100644 --- a/presentation/src/main/java/com/architect/coders/mu8/splash/SplashViewModel.kt +++ b/presentation/src/main/java/com/architect/coders/mu8/splash/SplashViewModel.kt @@ -3,7 +3,7 @@ package com.architect.coders.mu8.splash import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.architect.coders.mu8.BuildConfig -import com.architect.coders.mu8.utils.ScopedViewModel +import com.architect.coders.mu8.common.ScopedViewModel import kotlinx.coroutines.delay import kotlinx.coroutines.launch diff --git a/presentation/src/main/res/layout/activity_events.xml b/presentation/src/main/res/layout/activity_events.xml deleted file mode 100644 index 684e0a2..0000000 --- a/presentation/src/main/res/layout/activity_events.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/presentation/src/main/res/layout/activity_nav_host.xml b/presentation/src/main/res/layout/activity_nav_host.xml index fc066b9..11c9ce8 100644 --- a/presentation/src/main/res/layout/activity_nav_host.xml +++ b/presentation/src/main/res/layout/activity_nav_host.xml @@ -10,7 +10,7 @@ layout="@layout/toolbar" /> + app:destination="@id/categoriesFragment" + app:popUpTo="@id/categoriesFragment" + app:popUpToInclusive="true" /> + android:label="CategoriesFragment"> + app:enterAnim="@android:anim/slide_in_left" + app:exitAnim="@android:anim/fade_out" + app:popEnterAnim="@android:anim/fade_in" + app:popExitAnim="@android:anim/slide_out_right" /> + app:destination="@id/comicsFragment" + app:enterAnim="@android:anim/slide_in_left" + app:exitAnim="@android:anim/fade_out" + app:popEnterAnim="@android:anim/fade_in" + app:popExitAnim="@android:anim/slide_out_right"/> + + + android:label="CharactersFragment"> + + + + android:label="ComicsFragment" > + + + + + + \ No newline at end of file