-
Notifications
You must be signed in to change notification settings - Fork 0
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
2 | ||
1 | ||
0 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
@@ -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>() | ||
|
@@ -39,7 +37,7 @@ class HomeFeedsAdapter( | |
parent, | ||
false | ||
) | ||
HomeHeaderViewHolder(binding, headerClickListener) | ||
HomeHeaderViewHolder(binding, listener) | ||
} | ||
|
||
else -> { | ||
|
@@ -48,7 +46,7 @@ class HomeFeedsAdapter( | |
parent, | ||
false | ||
) | ||
HomeSectionViewHolder(binding, recycledViewPool, onMovieClicked) | ||
HomeSectionViewHolder(binding, recycledViewPool, listener) | ||
} | ||
} | ||
} | ||
|
@@ -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 |
---|---|---|
@@ -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 | ||
|
||
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 | ||
} | ||
} |
Check warning
Code scanning / detekt
Checks whether files end with a line separator. Warning