mirror of
https://github.com/melihaksoy/Android-Kotlin-Modulerized-CleanArchitecture.git
synced 2026-03-26 19:31:31 +01:00
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:
@@ -14,7 +14,5 @@ android {
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
implementation project(':repository')
|
||||
|
||||
testImplementation testLibraries.coroutinesTest
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.melih.launches.data
|
||||
|
||||
import com.melih.abstractions.data.ViewEntity
|
||||
|
||||
data class LaunchDetailItem(
|
||||
val id: Long,
|
||||
val imageUrl: String,
|
||||
val rocketName: String,
|
||||
val missionDescription: String
|
||||
) : ViewEntity
|
||||
@@ -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 LaunchDetailMapper @Inject constructor() : Mapper<LaunchEntity, LaunchDetailItem>() {
|
||||
|
||||
override fun convert(launchEntity: LaunchEntity) =
|
||||
with(launchEntity) {
|
||||
LaunchDetailItem(
|
||||
id,
|
||||
rocket.imageURL,
|
||||
rocket.name,
|
||||
if (!missions.isNullOrEmpty()) missions[0].description else ""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,15 @@ package com.melih.detail.di.modules
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import com.melih.abstractions.mapper.Mapper
|
||||
import com.melih.core.di.keys.ViewModelKey
|
||||
import com.melih.definitions.entities.LaunchEntity
|
||||
import com.melih.detail.ui.DetailFragment
|
||||
import com.melih.detail.ui.DetailFragmentArgs
|
||||
import com.melih.detail.ui.DetailViewModel
|
||||
import com.melih.repository.interactors.GetLaunchDetails
|
||||
import com.melih.interactors.GetLaunchDetails
|
||||
import com.melih.launches.data.LaunchDetailItem
|
||||
import com.melih.launches.data.LaunchDetailMapper
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
@@ -21,6 +25,9 @@ abstract class DetailFragmentModule {
|
||||
@IntoMap
|
||||
@ViewModelKey(DetailViewModel::class)
|
||||
abstract fun detailViewModel(detailViewModel: DetailViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
abstract fun detailMapper(mapper: LaunchDetailMapper): Mapper<LaunchEntity, LaunchDetailItem>
|
||||
//endregion
|
||||
|
||||
@Module
|
||||
|
||||
@@ -1,34 +1,31 @@
|
||||
package com.melih.detail.ui
|
||||
|
||||
import androidx.lifecycle.Transformations.map
|
||||
import com.melih.abstractions.deliverable.handle
|
||||
import com.melih.core.base.viewmodel.BaseViewModel
|
||||
import com.melih.repository.entities.LaunchEntity
|
||||
import com.melih.repository.interactors.GetLaunchDetails
|
||||
import com.melih.repository.interactors.base.handle
|
||||
import com.melih.interactors.GetLaunchDetails
|
||||
import com.melih.launches.data.LaunchDetailItem
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import javax.inject.Inject
|
||||
|
||||
class DetailViewModel @Inject constructor(
|
||||
private val getLaunchDetails: GetLaunchDetails,
|
||||
private val getLaunchDetails: GetLaunchDetails<LaunchDetailItem>,
|
||||
private val getLaunchDetailsParams: GetLaunchDetails.Params
|
||||
) : BaseViewModel<LaunchEntity>() {
|
||||
) : BaseViewModel<LaunchDetailItem>() {
|
||||
|
||||
//region Properties
|
||||
|
||||
val rocketName = map(successData) {
|
||||
it.rocket.name
|
||||
it.rocketName
|
||||
}
|
||||
|
||||
val description = map(successData) {
|
||||
if (it.missions.isEmpty()) {
|
||||
""
|
||||
} else {
|
||||
it.missions[0].description
|
||||
}
|
||||
it.missionDescription
|
||||
}
|
||||
|
||||
val imageUrl = map(successData) {
|
||||
it.rocket.imageURL
|
||||
it.imageUrl
|
||||
}
|
||||
//endregion
|
||||
|
||||
|
||||
@@ -1,69 +1,69 @@
|
||||
<?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="DetailBinding">
|
||||
<data class="DetailBinding">
|
||||
|
||||
<variable
|
||||
name="viewModel"
|
||||
type="com.melih.detail.ui.DetailViewModel" />
|
||||
</data>
|
||||
<variable
|
||||
name="viewModel"
|
||||
type="com.melih.detail.ui.DetailViewModel" />
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imgRocket"
|
||||
imageUrl="@{viewModel.imageUrl}"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="220dp"
|
||||
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:contentDescription="@string/cd_rocket_image"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:srcCompat="@tools:sample/avatars[14]" />
|
||||
<ImageView
|
||||
android:id="@+id/imgRocket"
|
||||
imageUrl="@{viewModel.imageUrl}"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="220dp"
|
||||
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:contentDescription="@string/cd_rocket_image"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintEnd_toEndOf="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_marginLeft="@dimen/padding_standard"
|
||||
android:layout_marginTop="@dimen/padding_standard"
|
||||
android:layout_marginEnd="@dimen/padding_standard"
|
||||
android:layout_marginRight="@dimen/padding_standard"
|
||||
android:text="@{viewModel.rocketName}"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+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_marginLeft="@dimen/padding_standard"
|
||||
android:layout_marginTop="@dimen/padding_standard"
|
||||
android:layout_marginEnd="@dimen/padding_standard"
|
||||
android:layout_marginRight="@dimen/padding_standard"
|
||||
android:text="@{viewModel.rocketName}"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/imgRocket"
|
||||
tools:text="@sample/launches.json/launches/name" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/tvDescription"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
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:layout_marginBottom="@dimen/padding_standard"
|
||||
android:text="@{viewModel.description}"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvTitle"
|
||||
tools:text="@sample/launches.json/launches/missions/description" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/tvDescription"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
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:layout_marginBottom="@dimen/padding_standard"
|
||||
android:text="@{viewModel.description}"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvTitle"
|
||||
tools:text="@sample/launches.json/launches/missions/description" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package com.melih.detail
|
||||
|
||||
import com.melih.detail.ui.DetailViewModel
|
||||
import com.melih.repository.interactors.GetLaunchDetails
|
||||
import com.melih.interactors.GetLaunchDetails
|
||||
import com.melih.launches.data.LaunchDetailItem
|
||||
import io.mockk.mockk
|
||||
import io.mockk.slot
|
||||
import io.mockk.spyk
|
||||
@@ -19,7 +20,7 @@ import org.junit.jupiter.api.Test
|
||||
@UseExperimental(ExperimentalCoroutinesApi::class)
|
||||
class DetailViewModelTest : BaseTestWithMainThread() {
|
||||
|
||||
private val getLaunchDetails: GetLaunchDetails = mockk(relaxed = true)
|
||||
private val getLaunchDetails: GetLaunchDetails<LaunchDetailItem> = mockk(relaxed = true)
|
||||
private val getLaunchDetailsParams = GetLaunchDetails.Params(1013)
|
||||
|
||||
private val viewModel = spyk(DetailViewModel(getLaunchDetails, getLaunchDetailsParams))
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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 ""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user