WIP: feature/abstractions (#45)

* Abstraction layer backup

* Removed DataEntity, was unnecessary for now

* Separated network, persistence, entities and interaction, closes #29

* Renamed binding

* Removed build files, example tests

Removed build files, example tests

* Fixed build files were not being ignored all around app

* Updated CI ymls

* Small changes

* Fixed legacy repository package names

* Fixed CQ findings

* Updated Fastlane

* Packaging changes and version upgrades

* Removed core from interactors

* Version bumps

* Added new module graph
This commit is contained in:
Melih Aksoy
2019-10-30 17:27:53 +01:00
committed by GitHub
parent 83e39400a9
commit 88022629e1
103 changed files with 1098 additions and 921 deletions

View File

@@ -7,8 +7,6 @@ apply from: "$rootProject.projectDir/scripts/feature_module.gradle"
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':repository')
implementation libraries.paging
implementation libraries.swipeRefreshLayout

View File

@@ -0,0 +1,10 @@
package com.melih.launches.data
import com.melih.abstractions.data.ViewEntity
data class LaunchItem(
val id: Long,
val imageUrl: String,
val rocketName: String,
val missionDescription: String
) : ViewEntity

View File

@@ -0,0 +1,18 @@
package com.melih.launches.data
import com.melih.abstractions.mapper.Mapper
import com.melih.definitions.entities.LaunchEntity
import javax.inject.Inject
class LaunchMapper @Inject constructor() : Mapper<LaunchEntity, LaunchItem>() {
override fun convert(launchEntity: LaunchEntity) =
with(launchEntity) {
LaunchItem(
id,
rocket.imageURL,
rocket.name,
if (!missions.isNullOrEmpty()) missions[0].description else ""
)
}
}

View File

@@ -2,10 +2,14 @@ package com.melih.launches.di.modules
import androidx.lifecycle.ViewModel
import androidx.paging.Config
import com.melih.abstractions.mapper.Mapper
import com.melih.core.di.keys.ViewModelKey
import com.melih.definitions.entities.LaunchEntity
import com.melih.interactors.DEFAULT_LAUNCHES_AMOUNT
import com.melih.interactors.GetLaunches
import com.melih.launches.data.LaunchItem
import com.melih.launches.data.LaunchMapper
import com.melih.launches.ui.vm.LaunchesViewModel
import com.melih.repository.interactors.DEFAULT_LAUNCHES_AMOUNT
import com.melih.repository.interactors.GetLaunches
import dagger.Binds
import dagger.Module
import dagger.Provides
@@ -14,12 +18,15 @@ import dagger.multibindings.IntoMap
@Module
abstract class LaunchesFragmentModule {
//region ViewModels
//region Binds
@Binds
@IntoMap
@ViewModelKey(LaunchesViewModel::class)
abstract fun listViewModel(listViewModel: LaunchesViewModel): ViewModel
abstract fun launchesViewModel(listViewModel: LaunchesViewModel): ViewModel
@Binds
abstract fun launchMapper(mapper: LaunchMapper): Mapper<LaunchEntity, LaunchItem>
//endregion
@Module

View File

@@ -4,18 +4,18 @@ import android.os.Bundle
import android.view.View
import androidx.fragment.app.viewModels
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.melih.abstractions.deliverable.State
import com.melih.core.actions.openDetail
import com.melih.core.base.lifecycle.BaseDaggerFragment
import com.melih.core.extensions.observe
import com.melih.interactors.error.PersistenceEmptyError
import com.melih.launches.R
import com.melih.launches.databinding.ListBinding
import com.melih.launches.data.LaunchItem
import com.melih.launches.databinding.LaunchesBinding
import com.melih.launches.ui.adapters.LaunchesAdapter
import com.melih.launches.ui.vm.LaunchesViewModel
import com.melih.repository.entities.LaunchEntity
import com.melih.repository.interactors.base.PersistenceEmpty
import com.melih.repository.interactors.base.State
class LaunchesFragment : BaseDaggerFragment<ListBinding>(), SwipeRefreshLayout.OnRefreshListener {
class LaunchesFragment : BaseDaggerFragment<LaunchesBinding>(), SwipeRefreshLayout.OnRefreshListener {
//region Properties
@@ -67,7 +67,7 @@ class LaunchesFragment : BaseDaggerFragment<ListBinding>(), SwipeRefreshLayout.O
// Observing error to show toast with retry action
observe(viewModel.errorData) {
if (it !is PersistenceEmpty) {
if (it !is PersistenceEmptyError) {
showSnackbarWithAction(it) {
viewModel.retry()
}
@@ -79,7 +79,7 @@ class LaunchesFragment : BaseDaggerFragment<ListBinding>(), SwipeRefreshLayout.O
}
}
private fun onItemSelected(item: LaunchEntity) {
private fun onItemSelected(item: LaunchItem) {
openDetail(item.id)
}

View File

@@ -5,10 +5,10 @@ import android.view.ViewGroup
import com.melih.core.base.recycler.BasePagingListAdapter
import com.melih.core.base.recycler.BaseViewHolder
import com.melih.core.extensions.createDiffCallback
import com.melih.launches.data.LaunchItem
import com.melih.launches.databinding.LaunchRowBinding
import com.melih.repository.entities.LaunchEntity
class LaunchesAdapter(itemClickListener: (LaunchEntity) -> Unit) : BasePagingListAdapter<LaunchEntity>(
class LaunchesAdapter(itemClickListener: (LaunchItem) -> Unit) : BasePagingListAdapter<LaunchItem>(
createDiffCallback { oldItem, newItem -> oldItem.id == newItem.id },
itemClickListener
) {
@@ -19,21 +19,18 @@ class LaunchesAdapter(itemClickListener: (LaunchEntity) -> Unit) : BasePagingLis
inflater: LayoutInflater,
parent: ViewGroup,
viewType: Int
): BaseViewHolder<LaunchEntity> =
): BaseViewHolder<LaunchItem> =
LaunchesViewHolder(LaunchRowBinding.inflate(inflater, parent, false))
//endregion
}
class LaunchesViewHolder(private val binding: LaunchRowBinding) : BaseViewHolder<LaunchEntity>(binding) {
class LaunchesViewHolder(private val binding: LaunchRowBinding) :
BaseViewHolder<LaunchItem>(binding) {
//region Functions
override fun bind(item: LaunchEntity) {
override fun bind(item: LaunchItem) {
binding.entity = item
val missions = item.missions
binding.tvDescription.text = if (!missions.isNullOrEmpty()) missions[0].description else ""
binding.executePendingBindings()
}
//endregion

View File

@@ -1,25 +1,23 @@
package com.melih.launches.ui.paging
import com.melih.core.base.paging.BasePagingDataSource
import com.melih.repository.entities.LaunchEntity
import com.melih.repository.interactors.GetLaunches
import com.melih.repository.interactors.base.Result
import com.melih.interactors.GetLaunches
import com.melih.launches.data.LaunchItem
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
/**
* Uses [GetLaunches] to get data for pagination
*/
class LaunchesPagingSource @Inject constructor(
private val getLaunches: GetLaunches,
private val getLaunches: GetLaunches<LaunchItem>,
private val getLaunchesParams: GetLaunches.Params
) : BasePagingDataSource<LaunchEntity>() {
) : BasePagingDataSource<LaunchItem>() {
//region Functions
@UseExperimental(ExperimentalCoroutinesApi::class)
override fun loadDataForPage(page: Int): Flow<Result<List<LaunchEntity>>> =
override fun loadDataForPage(page: Int) =
getLaunches(
getLaunchesParams.copy(
page = page

View File

@@ -2,16 +2,16 @@ package com.melih.launches.ui.paging
import com.melih.core.base.paging.BasePagingDataSource
import com.melih.core.base.paging.BasePagingFactory
import com.melih.repository.entities.LaunchEntity
import com.melih.launches.data.LaunchItem
import javax.inject.Inject
import javax.inject.Provider
class LaunchesPagingSourceFactory @Inject constructor(
private val sourceProvider: Provider<LaunchesPagingSource>
) : BasePagingFactory<LaunchEntity>() {
) : BasePagingFactory<LaunchItem>() {
//region Functions
override fun createSource(): BasePagingDataSource<LaunchEntity> = sourceProvider.get()
override fun createSource(): BasePagingDataSource<LaunchItem> = sourceProvider.get()
//endregion
}

View File

@@ -3,18 +3,18 @@ package com.melih.launches.ui.vm
import androidx.paging.PagedList
import com.melih.core.base.paging.BasePagingFactory
import com.melih.core.base.viewmodel.BasePagingViewModel
import com.melih.launches.data.LaunchItem
import com.melih.launches.ui.paging.LaunchesPagingSourceFactory
import com.melih.repository.entities.LaunchEntity
import javax.inject.Inject
class LaunchesViewModel @Inject constructor(
private val launchesPagingSourceFactory: LaunchesPagingSourceFactory,
private val launchesPagingConfig: PagedList.Config
) : BasePagingViewModel<LaunchEntity>() {
) : BasePagingViewModel<LaunchItem>() {
//region Properties
override val factory: BasePagingFactory<LaunchEntity>
override val factory: BasePagingFactory<LaunchItem>
get() = launchesPagingSourceFactory
override val config: PagedList.Config

View File

@@ -4,7 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data class="ListBinding">
<data class="LaunchesBinding">
<variable
name="viewModel"

View File

@@ -1,69 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data class="LaunchRowBinding">
<data class="LaunchRowBinding">
<variable
name="entity"
type="com.melih.repository.entities.LaunchEntity" />
</data>
<variable
name="entity"
type="com.melih.launches.data.LaunchItem" />
</data>
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/padding_standard"
android:layout_marginLeft="@dimen/padding_standard"
android:layout_marginTop="@dimen/padding_standard"
android:layout_marginEnd="@dimen/padding_standard"
android:layout_marginRight="@dimen/padding_standard"
android:background="@null"
app:cardElevation="10dp">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/padding_standard"
android:layout_marginLeft="@dimen/padding_standard"
android:layout_marginTop="@dimen/padding_standard"
android:layout_marginEnd="@dimen/padding_standard"
android:layout_marginRight="@dimen/padding_standard"
android:background="@null"
app:cardElevation="10dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="160dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="160dp">
<ImageView
android:id="@+id/imgRocket"
imageUrl="@{entity.rocket.imageURL}"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_marginStart="@dimen/padding_large"
android:contentDescription="@string/cd_rocket_image"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="@tools:sample/avatars[14]" />
<ImageView
android:id="@+id/imgRocket"
imageUrl="@{entity.imageUrl}"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_marginStart="@dimen/padding_large"
android:contentDescription="@string/cd_rocket_image"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="@tools:sample/avatars[14]" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tvTitle"
style="@style/AppTheme.TextViewStyle.Title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/padding_standard"
android:layout_marginEnd="@dimen/padding_large"
android:text="@{entity.name}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/imgRocket"
app:layout_constraintTop_toTopOf="@+id/imgRocket"
tools:text="@sample/launches.json/launches/name" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tvTitle"
style="@style/AppTheme.TextViewStyle.Title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/padding_standard"
android:layout_marginEnd="@dimen/padding_large"
android:text="@{entity.rocketName}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/imgRocket"
app:layout_constraintTop_toTopOf="@+id/imgRocket"
tools:text="@sample/launches.json/launches/name" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tvDescription"
style="@style/AppTheme.TextViewStyle.Description"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="@dimen/padding_standard"
android:layout_marginEnd="@dimen/padding_large"
app:layout_constraintBottom_toBottomOf="@+id/imgRocket"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/imgRocket"
app:layout_constraintTop_toBottomOf="@+id/tvTitle"
tools:text="@sample/launches.json/launches/missions/description" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/tvDescription"
style="@style/AppTheme.TextViewStyle.Description"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="@dimen/padding_standard"
android:layout_marginEnd="@dimen/padding_large"
android:text="@{entity.missionDescription}"
app:layout_constraintBottom_toBottomOf="@+id/imgRocket"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/imgRocket"
app:layout_constraintTop_toBottomOf="@+id/tvTitle"
tools:text="@sample/launches.json/launches/missions/description" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</layout>