Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update(home): Show home feed and refactoring listener home adapter #3

Merged
merged 1 commit into from
Jan 22, 2024
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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
2
1
0
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified buildSrc/build/kotlin/compileKotlin/cacheable/last-build.bin
Binary file not shown.
Binary file not shown.
Binary file modified buildSrc/build/libs/buildSrc.jar
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ import id.heycoding.home.data.repository.HomeRepository
import id.heycoding.home.data.repository.HomeRepositoryImpl
import id.heycoding.home.domain.GetHomeFeedsUseCase
import id.heycoding.home.domain.GetWatchlistUseCase
import id.heycoding.home.presentation.ui.home.HomeViewModel
import id.heycoding.shared.data.remote.NetworkClient
import kotlinx.coroutines.Dispatchers
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.androidx.viewmodel.dsl.viewModelOf
import org.koin.core.module.Module
import org.koin.dsl.module

Expand All @@ -27,8 +30,9 @@ object HomeModules : FeatureModules {
override val repositories: Module = module {
single<HomeRepository> { HomeRepositoryImpl(get()) }
}
override val viewModels: Module
get() = TODO("Not yet implemented")
override val viewModels: Module = module {
viewModelOf(::HomeViewModel)
}
override val dataSources: Module = module {
single<HomeDataSource> { HomeDataSourceImpl(get()) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
import id.heycoding.home.R
import id.heycoding.home.databinding.ItemHeaderHomeBinding
import id.heycoding.home.databinding.ItemSectionMovieBinding
import id.heycoding.home.presentation.adapter.viewholder.HomeHeaderClickListener
import id.heycoding.home.presentation.adapter.viewholder.HomeHeaderViewHolder
import id.heycoding.home.presentation.adapter.viewholder.HomeSectionViewHolder
import id.heycoding.home.presentation.viewparam.homeitem.HomeUiItem
Expand All @@ -20,8 +19,7 @@ import id.heycoding.shared.data.model.viewparam.MovieViewParam
* [email protected]
*/
class HomeFeedsAdapter(
private val headerClickListener: HomeHeaderClickListener,
private val onMovieClicked: (MovieViewParam) -> Unit,
private val listener: HomeAdapterClickListener,
private val recycledViewPool: RecycledViewPool
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val items = mutableListOf<HomeUiItem>()
Expand All @@ -39,7 +37,7 @@ class HomeFeedsAdapter(
parent,
false
)
HomeHeaderViewHolder(binding, headerClickListener)
HomeHeaderViewHolder(binding, listener)
}

else -> {
Expand All @@ -48,7 +46,7 @@ class HomeFeedsAdapter(
parent,
false
)
HomeSectionViewHolder(binding, recycledViewPool, onMovieClicked)
HomeSectionViewHolder(binding, recycledViewPool, listener)
}
}
}
Expand All @@ -73,4 +71,10 @@ class HomeFeedsAdapter(
}
}

}

interface HomeAdapterClickListener {
fun onMyListClicked(movieViewParam: MovieViewParam)
fun onPlayMovieClicked(movieViewParam: MovieViewParam)
fun onMovieClicked(movieViewParam: MovieViewParam)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package id.heycoding.home.presentation.adapter.viewholder
import androidx.recyclerview.widget.RecyclerView
import coil.load
import id.heycoding.home.databinding.ItemHeaderHomeBinding
import id.heycoding.home.presentation.adapter.HomeAdapterClickListener
import id.heycoding.home.presentation.viewparam.homeitem.HomeUiItem
import id.heycoding.shared.data.model.viewparam.MovieViewParam
import id.heycoding.shared.utils.CommonUtils
Expand All @@ -15,7 +16,7 @@ import id.heycoding.shared.utils.CommonUtils
*/
class HomeHeaderViewHolder(
private val binding: ItemHeaderHomeBinding,
private val listener: HomeHeaderClickListener
private val listener: HomeAdapterClickListener
) : RecyclerView.ViewHolder(binding.root) {
fun bindView(item: HomeUiItem.HeaderSectionItem) {
with(item.movieViewParam) {
Expand All @@ -28,7 +29,7 @@ class HomeHeaderViewHolder(
binding.ivHeaderMovie.load(this.posterUrl)
binding.tvTitleMovie.text = this.title
binding.tvInfoHeader.setOnClickListener {
listener.onInfoClicked(this)
listener.onMovieClicked(this)
}
binding.tvAddToWatchlistHeader.setOnClickListener {
listener.onMyListClicked(this)
Expand All @@ -38,10 +39,4 @@ class HomeHeaderViewHolder(
}
}
}
}

interface HomeHeaderClickListener {
fun onMyListClicked(movieViewParam: MovieViewParam)
fun onPlayMovieClicked(movieViewParam: MovieViewParam)
fun onInfoClicked(movieViewParam: MovieViewParam)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
import id.heycoding.home.databinding.ItemSectionMovieBinding
import id.heycoding.home.presentation.adapter.HomeAdapterClickListener
import id.heycoding.home.presentation.adapter.HomeFeedsAdapter
import id.heycoding.home.presentation.adapter.MovieAdapter
import id.heycoding.home.presentation.viewparam.homeitem.HomeUiItem
Expand All @@ -18,24 +19,25 @@ import id.heycoding.shared.data.model.viewparam.MovieViewParam
class HomeSectionViewHolder(
private val binding: ItemSectionMovieBinding,
private val recyclerViewPool: RecycledViewPool,
private val onMovieClicked: (MovieViewParam) -> Unit
private val listener: HomeAdapterClickListener
) : RecyclerView.ViewHolder(binding.root) {

private val movieAdapter: MovieAdapter by lazy {
MovieAdapter {
onMovieClicked.invoke(it)
listener.onMovieClicked(it)
}
}

fun bindView(item: HomeUiItem.ContentSectionItem) {
with(item) {
binding.tvTitleSection.text = this.sectionViewParam.sectionName
movieAdapter.setItems(this.sectionViewParam.contents)
binding.rvContents.apply {
setRecycledViewPool(recyclerViewPool)
adapter = movieAdapter
layoutManager =
LinearLayoutManager(itemView.context, LinearLayoutManager.HORIZONTAL, false)
}
movieAdapter.setItems(this.sectionViewParam.contents)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,57 @@
package id.heycoding.home.presentation.ui.home

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import id.heycoding.home.R

class HomeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
import androidx.fragment.app.Fragment
import id.heycoding.core.base.BaseActivity
import id.heycoding.home.databinding.ActivityHomeBinding
import id.heycoding.home.presentation.ui.homefeeds.HomeFeedsFragment
import id.heycoding.home.presentation.ui.watchlist.WatchlistFragment
import org.koin.androidx.viewmodel.ext.android.viewModel

class HomeActivity :
BaseActivity<ActivityHomeBinding, HomeViewModel>(ActivityHomeBinding::inflate) {
private val homeFeedsFragment = HomeFeedsFragment()
private val watchListFragment = WatchlistFragment()
private var activeFragment: Fragment = homeFeedsFragment

override val viewModel: HomeViewModel by viewModel()

override fun initView() {
setupFragment()
}

private fun setupFragment() {
// delete all fragment in fragment manager first
for (fragment in supportFragmentManager.fragments) {
supportFragmentManager.beginTransaction().remove(fragment).commit()
}
// add fragment to fragment manager
supportFragmentManager.beginTransaction().apply {
add(binding.container.id, homeFeedsFragment)
add(binding.container.id, watchListFragment)
hide(watchListFragment)
}.commit()
// set click menu for changing fragment
binding.bottomNavView.setOnItemSelectedListener {
when (it.itemId) {
id.heycoding.styling.R.id.home -> {
showFragment(homeFeedsFragment)
true
}

else -> {
showFragment(watchListFragment)
true
}
}
}
}

private fun showFragment(fragment: Fragment) {
supportFragmentManager.beginTransaction()
.hide(activeFragment)
.show(fragment)
.commit()
activeFragment = fragment
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package id.heycoding.home.presentation.ui.home

Check warning

Code scanning / detekt

Checks whether files end with a line separator. Warning

The file /home/runner/work/LayarTancepXXI/LayarTancepXXI/feature/home/src/main/java/id/heycoding/home/presentation/ui/home/HomeViewModel.kt is not ending with a new line.

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import id.heycoding.core.wrapper.ViewResource
import id.heycoding.home.domain.GetHomeFeedsUseCase
import id.heycoding.home.domain.GetWatchlistUseCase
import id.heycoding.home.presentation.viewparam.homeitem.HomeUiItem
import id.heycoding.shared.data.model.viewparam.MovieViewParam
import id.heycoding.shared.data.model.viewparam.UserViewParam
import id.heycoding.shared.domain.GetCurrentUserUseCase
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch


/**
* Created by Irfan Nawawi on 18/01/24.
* heycoding.tech
* [email protected]
*/
class HomeViewModel(
private val getHomeFeedsUseCase: GetHomeFeedsUseCase,
private val getWatchlistUseCase: GetWatchlistUseCase,
private val getCurrentUserUseCase: GetCurrentUserUseCase
) : ViewModel() {
val homeFeedsResult: MutableLiveData<ViewResource<List<HomeUiItem>>> = MutableLiveData()
val watchlistResult: MutableLiveData<ViewResource<List<MovieViewParam>>> = MutableLiveData()
val currentUserResult: MutableLiveData<ViewResource<UserViewParam>> = MutableLiveData()
fun fetchHomeFeeds() {
viewModelScope.launch {
getHomeFeedsUseCase().collect {
homeFeedsResult.postValue(it)
}
}
}

fun fetchWatchList() {
viewModelScope.launch {
getWatchlistUseCase().collect {
watchlistResult.postValue(it)
}
}
}

fun getCurrentUser() {
viewModelScope.launch {
getCurrentUserUseCase().collect {
currentUserResult.postValue(it)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,104 @@
package id.heycoding.home.presentation.ui.homefeeds

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import id.heycoding.home.R


class HomeFeedsFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home_feeds, container, false)
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
import id.heycoding.core.base.BaseFragment
import id.heycoding.home.databinding.FragmentHomeFeedsBinding
import id.heycoding.home.presentation.adapter.HomeAdapterClickListener
import id.heycoding.home.presentation.adapter.HomeFeedsAdapter
import id.heycoding.home.presentation.ui.home.HomeViewModel
import id.heycoding.shared.data.model.viewparam.MovieViewParam
import id.heycoding.shared.utils.ColorUtils
import id.heycoding.shared.utils.ext.subscribe
import id.heycoding.shared.utils.textdrawable.ColorGenerator
import id.heycoding.shared.utils.textdrawable.TextDrawable
import id.heycoding.styling.ProjectColor
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
import kotlin.math.min


class HomeFeedsFragment :
BaseFragment<FragmentHomeFeedsBinding, HomeViewModel>(FragmentHomeFeedsBinding::inflate) {
override val viewModel: HomeViewModel by sharedViewModel()
private val recyclerViewPool: RecycledViewPool by lazy {
RecycledViewPool()
}
private val homeFeedsAdapter: HomeFeedsAdapter by lazy {
HomeFeedsAdapter(object : HomeAdapterClickListener {
override fun onMyListClicked(movieViewParam: MovieViewParam) {
// TODO : Add to Watchlist
}

override fun onPlayMovieClicked(movieViewParam: MovieViewParam) {
// TODO : Handle click item
}

override fun onMovieClicked(movieViewParam: MovieViewParam) {
// TODO : On Movie Clicked
}
}, recyclerViewPool)
}

private fun setupRecyclerView() {
binding.rvHome.apply {
adapter = homeFeedsAdapter
layoutManager = LinearLayoutManager(requireContext())
setRecycledViewPool(recyclerViewPool)
addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val scrollY: Int = binding.rvHome.computeVerticalScrollOffset()
val color = ColorUtils.changeAlpha(
ContextCompat.getColor(requireActivity(), ProjectColor.black_transparent),
(min(255, scrollY).toFloat() / 255.0f).toDouble()

Check warning

Code scanning / detekt

Report magic numbers. Magic number is a numeric literal that is not defined as a constant and hence it's unclear what the purpose of this number is. It's better to declare such numbers as constants and give them a proper name. By default, -1, 0, 1, and 2 are not considered to be magic numbers. Warning

This expression contains a magic number. Consider defining it to a well named constant.

Check warning

Code scanning / detekt

Report magic numbers. Magic number is a numeric literal that is not defined as a constant and hence it's unclear what the purpose of this number is. It's better to declare such numbers as constants and give them a proper name. By default, -1, 0, 1, and 2 are not considered to be magic numbers. Warning

This expression contains a magic number. Consider defining it to a well named constant.
)
binding.clToolbarHomeFeed.setBackgroundColor(color)
}
})
}
}

override fun initView() {
setupRecyclerView()
initData()
}

override fun observeData() {
super.observeData()
viewModel.homeFeedsResult.observe(viewLifecycleOwner) {
it.subscribe(doOnSuccess = { result ->
showLoading(false)
result.payload?.let { data ->
homeFeedsAdapter.setItems(data)
}
}, doOnLoading = {
showLoading(true)
}, doOnError = { error ->
showLoading(false)
error.exception?.let { e -> showError(true, e) }
})
}
viewModel.currentUserResult.observe(viewLifecycleOwner) {
it.subscribe(doOnSuccess = { result ->
binding.ivAvatarUser.setImageDrawable(
TextDrawable.builder().beginConfig().bold().toUpperCase().endConfig().buildRect(
result.payload?.username?.get(0).toString(),
ColorGenerator.MATERIAL.randomColor
)
)
})
}
}

private fun initData() {
viewModel.getCurrentUser()
viewModel.fetchHomeFeeds()
}

private fun showLoading(isShowLoading: Boolean) {
binding.pbHome.isVisible = isShowLoading
}
}
Loading
Loading