Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/src/main/java/com/android/tvflix/TvFlixApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.android.tvflix

import android.app.Application
import com.android.tvflix.config.AppConfig
import com.google.firebase.FirebaseApp
import dagger.hilt.android.HiltAndroidApp
import timber.log.Timber
import javax.inject.Inject
Expand All @@ -13,6 +14,7 @@ class TvFlixApplication : Application() {

override fun onCreate() {
super.onCreate()
FirebaseApp.initializeApp(this)
if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
}
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/android/tvflix/db/TvFlixDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import androidx.room.RoomDatabase
import com.android.tvflix.db.favouriteshow.FavoriteShow
import com.android.tvflix.db.favouriteshow.ShowDao

@Database(entities = [FavoriteShow::class], version = 2, exportSchema = false)
@Database(entities = [FavoriteShow::class], version = 3, exportSchema = false)
abstract class TvFlixDatabase : RoomDatabase() {

abstract fun showDao(): ShowDao
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ data class FavoriteShow(
val imageUrl: String?,
var summary: String?,
var rating: String?,
var runtime: Int?,
val isFavorite: Boolean
var runtime: Int?
)

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.android.tvflix.domain

import com.android.tvflix.db.favouriteshow.FavoriteShow
import com.android.tvflix.di.IoDispatcher
import com.android.tvflix.favorite.FavoriteShowsRepository
import kotlinx.coroutines.CoroutineDispatcher
import javax.inject.Inject

class AddToFavoritesUseCase @Inject
constructor(
private val favoriteShowsRepository: FavoriteShowsRepository,
@IoDispatcher ioDispatcher: CoroutineDispatcher
) : SuspendUseCase<FavoriteShow, Unit>(ioDispatcher) {
override suspend fun execute(parameters: FavoriteShow) {
favoriteShowsRepository.insertIntoFavorites(parameters)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.android.tvflix.domain

import com.android.tvflix.db.favouriteshow.FavoriteShow
import com.android.tvflix.di.IoDispatcher
import com.android.tvflix.favorite.FavoriteShowsRepository
import com.android.tvflix.home.HomeViewModel
import kotlinx.coroutines.CoroutineDispatcher
import java.text.SimpleDateFormat
import java.util.*
import javax.inject.Inject

class GetFavoriteShowsUseCase
@Inject
constructor(
private val favoriteShowsRepository: FavoriteShowsRepository,
@IoDispatcher ioDispatcher: CoroutineDispatcher
) : SuspendUseCase<Unit, List<Long>>(ioDispatcher) {
override suspend fun execute(parameters: Unit): List<Long> {
return favoriteShowsRepository.allFavoriteShowIds()
}
}
34 changes: 34 additions & 0 deletions app/src/main/java/com/android/tvflix/domain/GetSchedulesUseCase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.android.tvflix.domain

import com.android.tvflix.di.IoDispatcher
import com.android.tvflix.model.respositores.SchedulesRepository
import com.android.tvflix.network.home.Episode
import kotlinx.coroutines.CoroutineDispatcher
import java.text.SimpleDateFormat
import java.util.*
import javax.inject.Inject


class GetSchedulesUseCase
@Inject
constructor(
private val schedulesRepository: SchedulesRepository,
@IoDispatcher ioDispatcher: CoroutineDispatcher
) :
SuspendUseCase<Unit, List<Episode>>(ioDispatcher) {
override suspend fun execute(parameters: Unit): List<Episode> {
return schedulesRepository.getSchedule(country = COUNTRY, currentDate = currentDate)
}

companion object {
private const val QUERY_DATE_FORMAT = "yyyy-MM-dd"
const val COUNTRY = "US"
private val currentDate: String
get() {
val simpleDateFormat = SimpleDateFormat(QUERY_DATE_FORMAT, Locale.US)
val calendar = Calendar.getInstance()
return simpleDateFormat.format(calendar.time)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.android.tvflix.domain

import com.android.tvflix.db.favouriteshow.FavoriteShow
import com.android.tvflix.di.IoDispatcher
import com.android.tvflix.favorite.FavoriteShowsRepository
import com.android.tvflix.network.home.Show
import kotlinx.coroutines.CoroutineDispatcher
import javax.inject.Inject

class RemoveFromFavoritesUseCase
@Inject
constructor(
private val favoriteShowsRepository: FavoriteShowsRepository,
@IoDispatcher ioDispatcher: CoroutineDispatcher
) : SuspendUseCase<FavoriteShow, Unit>(ioDispatcher) {
override suspend fun execute(parameters: FavoriteShow) {
favoriteShowsRepository.removeFromFavorites(parameters)
}
}
35 changes: 35 additions & 0 deletions app/src/main/java/com/android/tvflix/domain/SuspendUseCase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.android.tvflix.domain

import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext

/**
* Executes business logic synchronously or asynchronously using Coroutines.
*
* The [execute] method of [SuspendUseCase] is a suspend function
*/
abstract class SuspendUseCase<in P, R>(private val coroutineDispatcher: CoroutineDispatcher) {

/** Executes the use case asynchronously and returns a [Result].
*
* @return a [Result].
*
* @param parameters the input parameters to run the use case with
*/
val tag: String = this.javaClass.simpleName

suspend operator fun invoke(parameters: P): R {
// Moving all use case's executions to the injected dispatcher
// In production code, this is usually the Default dispatcher (background thread)
// In tests, this becomes a TestCoroutineDispatcher
return withContext(coroutineDispatcher) {
execute(parameters)
}
}

/**
* Override this to set the code to be executed.
*/
@Throws(RuntimeException::class)
protected abstract suspend fun execute(parameters: P): R
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect

@AndroidEntryPoint
class FavoriteShowsActivity : AppCompatActivity(), FavoriteShowsAdapter.Callback {
class FavoriteShowsActivity : AppCompatActivity() {
private val favoriteShowsViewModel: FavoriteShowsViewModel by viewModels()
private val binding by lazy { ActivityFavoriteShowsBinding.inflate(layoutInflater) }

Expand Down Expand Up @@ -62,7 +62,7 @@ class FavoriteShowsActivity : AppCompatActivity(), FavoriteShowsAdapter.Callback
binding.progress.isVisible = false
val layoutManager = GridLayoutManager(this, COLUMNS_COUNT)
binding.shows.layoutManager = layoutManager
val favoriteShowsAdapter = FavoriteShowsAdapter(favoriteShows.toMutableList(), this)
val favoriteShowsAdapter = FavoriteShowsAdapter(favoriteShows.toMutableList())
binding.shows.adapter = favoriteShowsAdapter
val spacing = resources.getDimensionPixelSize(R.dimen.show_grid_spacing)
binding.shows.addItemDecoration(GridItemDecoration(spacing, COLUMNS_COUNT))
Expand All @@ -81,10 +81,6 @@ class FavoriteShowsActivity : AppCompatActivity(), FavoriteShowsAdapter.Callback
binding.favoriteHint.isVisible = true
}

override fun onFavoriteClicked(show: FavoriteShow) {
favoriteShowsViewModel.onFavoriteClick(show)
}

companion object {
private const val FAVORITE_ICON_START_OFFSET = 13
private const val FAVORITE_ICON_END_OFFSET = 14
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,48 +13,23 @@ import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.RequestOptions

class FavoriteShowsAdapter(
private val favoriteShows: MutableList<FavoriteShow>,
private val callback: Callback
private val favoriteShows: MutableList<FavoriteShow>
) : RecyclerView.Adapter<FavoriteShowsAdapter.FavoriteShowHolder>() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FavoriteShowHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val showListItemBinding = ShowListItemBinding.inflate(layoutInflater, parent, false)
val holder = FavoriteShowHolder(showListItemBinding)
holder.binding.favorite.setOnClickListener { onFavouriteIconClicked(holder.absoluteAdapterPosition) }
holder.binding.showFavoriteIcon = false
return holder
}

private fun onFavouriteIconClicked(position: Int) {
if (position != RecyclerView.NO_POSITION) {
val show = favoriteShows[position]
val updatedShow = show.copy(isFavorite = !show.isFavorite)
favoriteShows[position] = updatedShow
notifyItemChanged(position)
callback.onFavoriteClicked(show)
}
}

override fun onBindViewHolder(holder: FavoriteShowHolder, position: Int) {
val favoriteShow = favoriteShows[position]
Glide.with(holder.itemView.context).load(favoriteShow.imageUrl)
.apply(RequestOptions.placeholderOf(R.color.grey))
.transition(DrawableTransitionOptions.withCrossFade())
.into(holder.binding.showImage)
configureFavoriteIcon(holder.binding.favorite, favoriteShow.isFavorite)
}

private fun configureFavoriteIcon(favoriteIcon: ImageView, favorite: Boolean) {
if (favorite) {
val favoriteDrawable = AppCompatResources
.getDrawable(favoriteIcon.context, R.drawable.favorite)
favoriteIcon.setImageDrawable(favoriteDrawable)
} else {
val unFavoriteDrawable = AppCompatResources
.getDrawable(favoriteIcon.context, R.drawable.favorite_border)
favoriteIcon.setImageDrawable(unFavoriteDrawable)
}
}

override fun getItemCount(): Int {
Expand All @@ -63,8 +38,4 @@ class FavoriteShowsAdapter(

class FavoriteShowHolder(val binding: ShowListItemBinding) :
RecyclerView.ViewHolder(binding.root)

interface Callback {
fun onFavoriteClicked(show: FavoriteShow)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ constructor(private val showDao: ShowDao) {
imageUrl = show.image!!["original"],
summary = show.summary,
rating = show.rating!!["average"],
runtime = show.runtime!!,
isFavorite = true
runtime = show.runtime!!
)
showDao.insert(favoriteShow)
}
Expand All @@ -36,8 +35,7 @@ constructor(private val showDao: ShowDao) {
imageUrl = show.image!!["original"],
summary = show.summary,
rating = show.rating!!["average"],
runtime = show.runtime!!,
isFavorite = false
runtime = show.runtime!!
)
showDao.remove(favoriteShow)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,4 @@ constructor(
)
Timber.d(throwable)
}

fun onFavoriteClick(show: FavoriteShow) {
viewModelScope.launch(ioDispatcher) {
if (!show.isFavorite) {
favoriteShowsRepository.insertIntoFavorites(show)
_favoriteShowsStateFlow.emit(FavoriteShowState.AddedToFavorites(show))
} else {
favoriteShowsRepository.removeFromFavorites(show)
_favoriteShowsStateFlow.emit(FavoriteShowState.RemovedFromFavorites(show))
}
}
}
}
11 changes: 6 additions & 5 deletions app/src/main/java/com/android/tvflix/home/HomeActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import androidx.recyclerview.widget.GridLayoutManager
import com.android.tvflix.R
import com.android.tvflix.config.FavoritesFeatureFlag
import com.android.tvflix.databinding.ActivityHomeBinding
import com.android.tvflix.domain.GetSchedulesUseCase
import com.android.tvflix.favorite.FavoriteShowsActivity
import com.android.tvflix.shows.AllShowsActivity
import com.android.tvflix.utils.GridItemDecoration
Expand Down Expand Up @@ -57,10 +58,6 @@ class HomeActivity : AppCompatActivity(), ShowsAdapter.Callback {
lifecycleScope.launchWhenStarted {
homeViewModel.homeViewStateFlow.collect { setViewState(it) }
}
binding.popularShowHeader.text = String.format(
getString(R.string.popular_shows_airing_today),
homeViewModel.country
)
}

private fun setViewState(homeViewState: HomeViewState) {
Expand All @@ -71,7 +68,11 @@ class HomeActivity : AppCompatActivity(), ShowsAdapter.Callback {
showError(homeViewState.message!!)
}
is HomeViewState.Success -> {
binding.progress.isVisible = false
with(binding) {
progress.isVisible = false
popularShowHeader.text = homeViewState.homeViewData.heading
popularShowHeader.isVisible = true
}
showPopularShows(homeViewState.homeViewData)
}
is HomeViewState.AddedToFavorites ->
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/android/tvflix/home/HomeViewData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.android.tvflix.home

import com.android.tvflix.network.home.Show

data class HomeViewData(val episodes: List<EpisodeViewData>) {
data class HomeViewData(val heading: String, val episodes: List<EpisodeViewData>) {
data class EpisodeViewData(
val id: Long,
val showViewData: ShowViewData,
Expand Down
Loading