diff --git a/app/build.gradle b/app/build.gradle index 47bbde7..4c51e2e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,6 +55,9 @@ dependencies { //SwipeRefreshLayout implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" + //Coil + implementation "io.coil-kt:coil:1.1.1" + def navigation = "2.4.2" implementation "androidx.navigation:navigation-fragment-ktx:$navigation" implementation "androidx.navigation:navigation-ui-ktx:$navigation" @@ -70,20 +73,29 @@ dependencies { def retrofit = "2.9.0" implementation "com.squareup.retrofit2:retrofit:$retrofit" implementation "com.squareup.retrofit2:converter-gson:$retrofit" - implementation "com.squareup.retrofit2:adapter-rxjava3:${retrofit}" + implementation "com.squareup.retrofit2:adapter-rxjava3:$retrofit" - def okhttp = "5.0.0-alpha.3" + def okhttp = "5.0.0-alpha.6" implementation "com.squareup.okhttp3:okhttp:$okhttp" debugImplementation "com.squareup.okhttp3:logging-interceptor:$okhttp" // endregion + // region Hilt def hilt_version = "2.40.5" implementation "com.google.dagger:hilt-android:$hilt_version" kapt "com.google.dagger:hilt-compiler:$hilt_version" - def hiltExt = "1.3.0-RC1" - implementation "it.czerwinski.android.hilt:hilt-extensions:${hiltExt}" - kapt "it.czerwinski.android.hilt:hilt-processor:${hiltExt}" + def hiltExt = "1.3.0" + implementation "it.czerwinski.android.hilt:hilt-extensions:$hiltExt" + kapt "it.czerwinski.android.hilt:hilt-processor:$hiltExt" + // endregion + + def moxy = "2.2.2" + implementation "com.github.moxy-community:moxy:$moxy" + implementation "com.github.moxy-community:moxy-androidx:$moxy" + implementation "com.github.moxy-community:moxy-material:$moxy" + implementation "com.github.moxy-community:moxy-ktx:$moxy" + kapt "com.github.moxy-community:moxy-compiler:$moxy" testImplementation 'junit:junit:4.13.2' diff --git a/app/src/main/java/ru/itis/karakurik/spacexapp/di/module/NetModule.kt b/app/src/main/java/ru/itis/karakurik/spacexapp/di/module/NetModule.kt index 44d4405..4844c9e 100644 --- a/app/src/main/java/ru/itis/karakurik/spacexapp/di/module/NetModule.kt +++ b/app/src/main/java/ru/itis/karakurik/spacexapp/di/module/NetModule.kt @@ -15,6 +15,7 @@ import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory import retrofit2.converter.gson.GsonConverterFactory import ru.itis.karakurik.spacexapp.data.network.SpaceXApi import ru.itis.karakurik.spacexapp.di.qualifier.BaseUrl +import ru.itis.karakurik.spacexapp.di.qualifier.CacheMaxSize import ru.itis.karakurik.spacexapp.di.qualifier.LoggingInterceptor import java.io.File import javax.inject.Qualifier @@ -61,25 +62,22 @@ class NetModule { @Provides fun provideCallAdapterFactory(): CallAdapter.Factory = RxJava3CallAdapterFactory.create() + @Provides @BaseUrl fun provideBaseUrl(): String = BASE_URL @Provides @LoggingInterceptor - fun provideLoggingInterceptor(): Interceptor { - return HttpLoggingInterceptor() + fun provideLoggingInterceptor(): Interceptor = + HttpLoggingInterceptor() .setLevel(HttpLoggingInterceptor.Level.BODY) - } @Provides fun provideCacheDirectory(): File { return File("cache"); } - @Qualifier - annotation class CacheMaxSize - @CacheMaxSize @Provides fun provideCacheMaxSize(): Long { diff --git a/app/src/main/java/ru/itis/karakurik/spacexapp/di/qualifier/CacheMaxSize.kt b/app/src/main/java/ru/itis/karakurik/spacexapp/di/qualifier/CacheMaxSize.kt new file mode 100644 index 0000000..1ba791f --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/spacexapp/di/qualifier/CacheMaxSize.kt @@ -0,0 +1,7 @@ +package ru.itis.karakurik.spacexapp.di.qualifier + +import javax.inject.Qualifier + +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +annotation class CacheMaxSize diff --git a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/extentions/ActivityExt.kt b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/common/extentions/ActivityExt.kt similarity index 51% rename from app/src/main/java/ru/itis/karakurik/spacexapp/presentation/extentions/ActivityExt.kt rename to app/src/main/java/ru/itis/karakurik/spacexapp/presentation/common/extentions/ActivityExt.kt index 35aaf46..14f0ad6 100644 --- a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/extentions/ActivityExt.kt +++ b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/common/extentions/ActivityExt.kt @@ -1,12 +1,9 @@ -package ru.itis.karakurik.androidLab2.extentions +package ru.itis.karakurik.spacexapp.presentation.common.extentions import androidx.appcompat.app.AppCompatActivity import androidx.navigation.NavController import androidx.navigation.fragment.NavHostFragment -import androidx.recyclerview.widget.LinearSmoothScroller -import androidx.recyclerview.widget.RecyclerView - -fun AppCompatActivity.findController (id: Int) : NavController { +internal fun AppCompatActivity.findController (id: Int) : NavController { return (supportFragmentManager.findFragmentById(id) as NavHostFragment).navController } diff --git a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/common/extentions/Utils.kt b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/common/extentions/Utils.kt new file mode 100644 index 0000000..76df850 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/common/extentions/Utils.kt @@ -0,0 +1,22 @@ +package ru.itis.karakurik.spacexapp.presentation.common.extentions + +import android.content.Context +import android.widget.Toast + +internal fun Context.toastLong(message: String?) = + message?.let { + Toast.makeText( + this, + message, + Toast.LENGTH_LONG + ).show() + } + +internal fun Context.toastShort(message: String?) = + message?.let { + Toast.makeText( + this, + message, + Toast.LENGTH_SHORT + ).show() + } diff --git a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/common/extentions/ViewExt.kt b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/common/extentions/ViewExt.kt new file mode 100644 index 0000000..8d58234 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/common/extentions/ViewExt.kt @@ -0,0 +1,15 @@ +package ru.itis.karakurik.spacexapp.presentation.common.extentions + +import android.view.View + +internal fun View.toGone() { + this.visibility = View.GONE +} + +internal fun View.toVisible() { + this.visibility = View.VISIBLE +} + +internal fun View.toInvisible() { + this.visibility = View.INVISIBLE +} diff --git a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchDetails/LaunchDetailsFragment.kt b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchDetails/LaunchDetailsFragment.kt index 0c3e03a..d64b9a9 100644 --- a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchDetails/LaunchDetailsFragment.kt +++ b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchDetails/LaunchDetailsFragment.kt @@ -1,5 +1,7 @@ package ru.itis.karakurik.spacexapp.presentation.launchDetails +import android.content.Intent +import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -7,21 +9,40 @@ import android.view.ViewGroup import android.widget.Toast import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs +import coil.load import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.Dispatchers +import moxy.MvpAppCompatFragment +import moxy.MvpPresenter +import moxy.ktx.moxyPresenter +import moxy.presenter.InjectPresenter +import moxy.presenter.ProvidePresenter import ru.itis.karakurik.spacexapp.R import ru.itis.karakurik.spacexapp.databinding.FragmentLaunchDetailsBinding import ru.itis.karakurik.spacexapp.domain.entity.Launch import ru.itis.karakurik.spacexapp.domain.utils.DateHelper +import ru.itis.karakurik.spacexapp.presentation.common.extentions.toGone +import ru.itis.karakurik.spacexapp.presentation.common.extentions.toVisible +import ru.itis.karakurik.spacexapp.presentation.common.extentions.toastLong +import javax.inject.Inject +import javax.inject.Provider @AndroidEntryPoint -class LaunchDetailsFragment : Fragment() { +class LaunchDetailsFragment : MvpAppCompatFragment(), LaunchDetailsView { private var _binding: FragmentLaunchDetailsBinding? = null private val binding get() = _binding!! private val args: LaunchDetailsFragmentArgs by navArgs() - private val viewModel: LaunchDetailsViewModel by viewModels() + + @Inject + lateinit var presenterProvider: Provider + + private val presenter by moxyPresenter { + presenterProvider.get() + } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -34,37 +55,42 @@ class LaunchDetailsFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - initObservers() + presenter.onGetLaunch(args.launchId) + } - viewModel.onGetLaunch(args.launchId) + override fun onDestroy() { + super.onDestroy() + _binding = null } - private fun initObservers() { - with(viewModel) { - launch.observe(viewLifecycleOwner) { result -> - result.fold( - onSuccess = { - setLaunchData(it) - }, onFailure = { - Toast.makeText( - requireContext(), - "Не удалось получить информацию о полете", - Toast.LENGTH_LONG - ).show() - } - ) - } - } + override fun showLoading() { + binding.progress.toVisible() } - private fun setLaunchData(launch: Launch) { - with(binding) { - tvHello.text = DateHelper.convertTimeStampToString(launch.dateUnix) - } + override fun hideLoading() { + binding.progress.toGone() } - override fun onDestroy() { - super.onDestroy() - _binding = null + override fun consumerError(throwable: Throwable) { + requireContext().toastLong("Не удалось получить информацию о полете") + } + + override fun showLaunchData(launch: Launch) { + with(binding) { + tvLaunchName.text = launch.name + ivLaunchIcon.load(launch.largeImageUrl) { + placeholder(R.drawable.launch_icon_large) + crossfade(true) + } + tvLaunchDescription.text = launch.details + ivLaunchIcon.setOnClickListener { + startActivity( + Intent( + Intent.ACTION_VIEW, + Uri.parse(launch.webCastUrl) + ) + ) + } + } } } diff --git a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchDetails/LaunchDetailsViewModel.kt b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchDetails/LaunchDetailsPresenter.kt similarity index 51% rename from app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchDetails/LaunchDetailsViewModel.kt rename to app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchDetails/LaunchDetailsPresenter.kt index 0957899..8b28b11 100644 --- a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchDetails/LaunchDetailsViewModel.kt +++ b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchDetails/LaunchDetailsPresenter.kt @@ -1,44 +1,37 @@ package ru.itis.karakurik.spacexapp.presentation.launchDetails -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import dagger.hilt.android.lifecycle.HiltViewModel import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.addTo import io.reactivex.rxjava3.kotlin.subscribeBy -import ru.itis.karakurik.spacexapp.domain.entity.Launch +import moxy.MvpPresenter import ru.itis.karakurik.spacexapp.domain.usecases.GetLaunchUseCase import javax.inject.Inject -@HiltViewModel -class LaunchDetailsViewModel @Inject constructor( +class LaunchDetailsPresenter @Inject constructor( private val getLaunchUseCase: GetLaunchUseCase -) : ViewModel() { +) : MvpPresenter() { private val disposables = CompositeDisposable() - private var _launch: MutableLiveData> = MutableLiveData() - val launch get() = _launch - fun onGetLaunch(launchId: String) { getLaunchUseCase(launchId) .observeOn(AndroidSchedulers.mainThread()) .doOnSubscribe { - // showLoading() + viewState.showLoading() } - .doAfterSuccess { - // hideLoading + .doFinally { + viewState.hideLoading() } .subscribeBy(onSuccess = { - _launch.value = Result.success(it) - }, onError = { error -> - _launch.value = Result.failure(error) + viewState.showLaunchData(it) + }, onError = { + viewState.consumerError(it) }).addTo(disposables) } - override fun onCleared() { - super.onCleared() - disposables.clear() + override fun onDestroy() { + super.onDestroy() + disposables.dispose() } } diff --git a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchDetails/LaunchDetailsView.kt b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchDetails/LaunchDetailsView.kt new file mode 100644 index 0000000..5ff2d7a --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchDetails/LaunchDetailsView.kt @@ -0,0 +1,20 @@ +package ru.itis.karakurik.spacexapp.presentation.launchDetails + +import moxy.MvpView +import moxy.viewstate.strategy.alias.AddToEnd +import moxy.viewstate.strategy.alias.AddToEndSingle +import moxy.viewstate.strategy.alias.SingleState +import moxy.viewstate.strategy.alias.Skip +import ru.itis.karakurik.spacexapp.domain.entity.Launch + +@AddToEnd +interface LaunchDetailsView : MvpView { + fun showLoading() + + fun hideLoading() + + @Skip + fun consumerError(throwable: Throwable) + + fun showLaunchData(launch: Launch) +} diff --git a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/LaunchListViewModel.kt b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/LaunchListViewModel.kt deleted file mode 100644 index 404ca69..0000000 --- a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/LaunchListViewModel.kt +++ /dev/null @@ -1,44 +0,0 @@ -package ru.itis.karakurik.spacexapp.presentation.launchesList - -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import dagger.hilt.android.lifecycle.HiltViewModel -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers -import io.reactivex.rxjava3.disposables.CompositeDisposable -import io.reactivex.rxjava3.kotlin.addTo -import io.reactivex.rxjava3.kotlin.subscribeBy -import ru.itis.karakurik.spacexapp.domain.entity.Launch -import ru.itis.karakurik.spacexapp.domain.usecases.GetLaunchesUseCase -import javax.inject.Inject - -@HiltViewModel -class LaunchListViewModel @Inject constructor( - private val getLaunchesUseCase: GetLaunchesUseCase, -) : ViewModel() { - - private val disposables = CompositeDisposable() - - private var _launchesList: MutableLiveData>> = MutableLiveData() - val launchesList get() = _launchesList - - fun onGetLaunchesList() { - getLaunchesUseCase() - .observeOn(AndroidSchedulers.mainThread()) - .doOnSubscribe { - // showLoading() - } - .doAfterSuccess { - // hideLoading - } - .subscribeBy(onSuccess = { - _launchesList.value = Result.success(it) - }, onError = { error -> - _launchesList.value = Result.failure(error) - }).addTo(disposables) - } - - override fun onCleared() { - super.onCleared() - disposables.clear() - } -} diff --git a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/LaunchesListFragment.kt b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/LaunchesListFragment.kt index 683badb..3c5b748 100644 --- a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/LaunchesListFragment.kt +++ b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/LaunchesListFragment.kt @@ -4,22 +4,33 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import dagger.hilt.android.AndroidEntryPoint +import moxy.MvpAppCompatFragment +import moxy.ktx.moxyPresenter import ru.itis.karakurik.spacexapp.databinding.FragmentLaunchesListBinding +import ru.itis.karakurik.spacexapp.domain.entity.Launch +import ru.itis.karakurik.spacexapp.presentation.common.extentions.toInvisible +import ru.itis.karakurik.spacexapp.presentation.common.extentions.toVisible +import ru.itis.karakurik.spacexapp.presentation.common.extentions.toastLong import ru.itis.karakurik.spacexapp.presentation.launchesList.recycler.LaunchesListRecyclerAdapter +import javax.inject.Inject +import javax.inject.Provider @AndroidEntryPoint -class LaunchesListFragment : Fragment() { +class LaunchesListFragment : MvpAppCompatFragment(), LaunchesListView { private var _binding: FragmentLaunchesListBinding? = null private val binding get() = _binding!! private var listRecyclerAdapter: LaunchesListRecyclerAdapter? = null - private val viewModel: LaunchListViewModel by viewModels() + @Inject + lateinit var presenterProvider: Provider + + private val presenter by moxyPresenter { + presenterProvider.get() + } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -35,53 +46,55 @@ class LaunchesListFragment : Fragment() { ) { super.onViewCreated(view, savedInstanceState) - initObservers() initSwipeRefreshLayout() initRecyclerView() } - private fun initObservers() { - viewModel.launchesList.observe(viewLifecycleOwner) { result -> - result.fold( - onSuccess = { - listRecyclerAdapter?.submitList(it) - }, onFailure = { - - } - ) - } - } - private fun initRecyclerView() { binding.rvLaunchesList.run { listRecyclerAdapter = LaunchesListRecyclerAdapter { id -> - showDetailsFragment(id) + openLaunchDetailsScreen(id) } adapter = listRecyclerAdapter } - viewModel.onGetLaunchesList() + presenter.onGetLaunchesList() } private fun initSwipeRefreshLayout() { binding.swipeRefreshLayout.let { it.setOnRefreshListener { - viewModel.onGetLaunchesList() - it.isRefreshing = false + presenter.onGetLaunchesList() } } } - private fun showDetailsFragment(launchId: String) { - findNavController().navigate( - LaunchesListFragmentDirections - .actionLaunchesListFragmentToLaunchDetailsFragment( - launchId - ) - ) - } - override fun onDestroy() { super.onDestroy() _binding = null } + + override fun showLoading() { + binding.progress.toVisible() + } + + override fun hideLoading() { + binding.progress.toInvisible() + } + + override fun consumerError(throwable: Throwable) { + requireContext().toastLong("Не удалось загрузить") + } + + override fun showLaunchesListData(launchesList: List) { + listRecyclerAdapter?.submitList(launchesList) + binding.swipeRefreshLayout.isRefreshing = false + } + + override fun openLaunchDetailsScreen(launchId: String) { + findNavController().navigate( + LaunchesListFragmentDirections.actionLaunchesListFragmentToLaunchDetailsFragment( + launchId + ) + ) + } } diff --git a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/LaunchesListPresenter.kt b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/LaunchesListPresenter.kt new file mode 100644 index 0000000..ceeb75e --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/LaunchesListPresenter.kt @@ -0,0 +1,37 @@ +package ru.itis.karakurik.spacexapp.presentation.launchesList + +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.disposables.CompositeDisposable +import io.reactivex.rxjava3.kotlin.addTo +import io.reactivex.rxjava3.kotlin.subscribeBy +import moxy.MvpPresenter +import ru.itis.karakurik.spacexapp.domain.usecases.GetLaunchesUseCase +import javax.inject.Inject + +class LaunchesListPresenter @Inject constructor( + private val getLaunchesUseCase: GetLaunchesUseCase +) : MvpPresenter() { + + private var disposables = CompositeDisposable() + + fun onGetLaunchesList() { + getLaunchesUseCase() + .observeOn(AndroidSchedulers.mainThread()) + .doOnSubscribe { + viewState.showLoading() + } + .doAfterTerminate { + viewState.hideLoading() + } + .subscribeBy(onSuccess = { + viewState.showLaunchesListData(it) + }, onError = { error -> + viewState.consumerError(error) + }).addTo(disposables) + } + + override fun onDestroy() { + super.onDestroy() + disposables.dispose() + } +} diff --git a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/LaunchesListView.kt b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/LaunchesListView.kt new file mode 100644 index 0000000..a13b246 --- /dev/null +++ b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/LaunchesListView.kt @@ -0,0 +1,22 @@ +package ru.itis.karakurik.spacexapp.presentation.launchesList + +import moxy.MvpView +import moxy.viewstate.strategy.alias.AddToEndSingle +import moxy.viewstate.strategy.alias.OneExecution +import moxy.viewstate.strategy.alias.Skip +import ru.itis.karakurik.spacexapp.domain.entity.Launch + +@AddToEndSingle +interface LaunchesListView : MvpView { + fun showLoading() + + fun hideLoading() + + @Skip + fun consumerError(throwable: Throwable) + + fun showLaunchesListData(launchesList: List) + + @OneExecution + fun openLaunchDetailsScreen(launchId: String) +} diff --git a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/recycler/LaunchListViewHolder.kt b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/recycler/LaunchListViewHolder.kt index 86a3dfb..acf0338 100644 --- a/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/recycler/LaunchListViewHolder.kt +++ b/app/src/main/java/ru/itis/karakurik/spacexapp/presentation/launchesList/recycler/LaunchListViewHolder.kt @@ -3,6 +3,8 @@ package ru.itis.karakurik.spacexapp.presentation.launchesList.recycler import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView +import coil.load +import ru.itis.karakurik.spacexapp.R import ru.itis.karakurik.spacexapp.databinding.ItemLaunchBinding import ru.itis.karakurik.spacexapp.domain.entity.Launch @@ -13,7 +15,12 @@ class LaunchListViewHolder( fun bind(launch: Launch) { with(binding) { - tvText.text = launch.name + tvLaunchName.text = launch.name + + ivLaunchItem.load(launch.smallImageUrl) { + crossfade(true) + placeholder(R.drawable.launch_icon_small) + } root.setOnClickListener { onItemClick(launch.id) diff --git a/app/src/main/res/drawable-v24/launch_icon_large.png b/app/src/main/res/drawable-v24/launch_icon_large.png new file mode 100644 index 0000000..fd3295a Binary files /dev/null and b/app/src/main/res/drawable-v24/launch_icon_large.png differ diff --git a/app/src/main/res/drawable-v24/launch_icon_small.png b/app/src/main/res/drawable-v24/launch_icon_small.png new file mode 100644 index 0000000..63604f0 Binary files /dev/null and b/app/src/main/res/drawable-v24/launch_icon_small.png differ diff --git a/app/src/main/res/drawable-v24/youtube_icon.png b/app/src/main/res/drawable-v24/youtube_icon.png new file mode 100644 index 0000000..5aeeb16 Binary files /dev/null and b/app/src/main/res/drawable-v24/youtube_icon.png differ diff --git a/app/src/main/res/font/font_black.otf b/app/src/main/res/font/font_black.otf new file mode 100644 index 0000000..298fe13 Binary files /dev/null and b/app/src/main/res/font/font_black.otf differ diff --git a/app/src/main/res/font/font_bold.otf b/app/src/main/res/font/font_bold.otf new file mode 100644 index 0000000..fc9fc62 Binary files /dev/null and b/app/src/main/res/font/font_bold.otf differ diff --git a/app/src/main/res/font/font_book.otf b/app/src/main/res/font/font_book.otf new file mode 100644 index 0000000..1d30d9d Binary files /dev/null and b/app/src/main/res/font/font_book.otf differ diff --git a/app/src/main/res/font/font_light.otf b/app/src/main/res/font/font_light.otf new file mode 100644 index 0000000..4f078f9 Binary files /dev/null and b/app/src/main/res/font/font_light.otf differ diff --git a/app/src/main/res/layout/fragment_launch_details.xml b/app/src/main/res/layout/fragment_launch_details.xml index 01539a2..a712dc3 100644 --- a/app/src/main/res/layout/fragment_launch_details.xml +++ b/app/src/main/res/layout/fragment_launch_details.xml @@ -1,20 +1,76 @@ - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_launches_list.xml b/app/src/main/res/layout/fragment_launches_list.xml index 95d8ed4..1369679 100644 --- a/app/src/main/res/layout/fragment_launches_list.xml +++ b/app/src/main/res/layout/fragment_launches_list.xml @@ -1,9 +1,9 @@ - - + + + diff --git a/app/src/main/res/layout/item_launch.xml b/app/src/main/res/layout/item_launch.xml index 61427ad..c9e3545 100644 --- a/app/src/main/res/layout/item_launch.xml +++ b/app/src/main/res/layout/item_launch.xml @@ -1,14 +1,44 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:backgroundTint="@color/cardview_shadow_end_color" + android:translationZ="2dp" + android:padding="8dp" + app:cardCornerRadius="32dp"> - + android:paddingVertical="12dp" + android:orientation="vertical"> + + + +