Skip to content

Commit

Permalink
✨ implement RecipeStepFragment
Browse files Browse the repository at this point in the history
  • Loading branch information
Hogu59 committed Jul 25, 2024
1 parent 5e969f6 commit 99b0d4c
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package net.pengcook.android.presentation.step

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.viewpager2.widget.ViewPager2
import net.pengcook.android.data.datasource.feed.DefaultFeedRemoteDataSource
import net.pengcook.android.data.remote.api.FeedService
import net.pengcook.android.data.repository.feed.DefaultFeedRepository
import net.pengcook.android.data.util.network.RetrofitClient
import net.pengcook.android.databinding.FragmentRecipeStepBinding

class RecipeStepFragment : Fragment() {
private val recipeId: Long = 1L
private val viewModel: RecipeStepViewModel by viewModels {
RecipeStepViewModelFactory(
recipeId = recipeId,
feedRepository =
DefaultFeedRepository(
feedRemoteDataSource =
DefaultFeedRemoteDataSource(
RetrofitClient.service(
FeedService::class.java,
),
),
),
)
}

private var _binding: FragmentRecipeStepBinding? = null
val binding: FragmentRecipeStepBinding
get() = _binding!!

private val recipeStepPagerRecyclerAdapter: RecipeStepPagerRecyclerAdapter by lazy {
RecipeStepPagerRecyclerAdapter()
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
_binding = FragmentRecipeStepBinding.inflate(layoutInflater)
return binding.root
}

override fun onViewCreated(
view: View,
savedInstanceState: Bundle?,
) {
super.onViewCreated(view, savedInstanceState)
viewModel.fetchRecipeSteps()

viewModel.recipeSteps.observe(viewLifecycleOwner) { recipeSteps ->
recipeStepPagerRecyclerAdapter.updateList(recipeSteps)
}

binding.vpStepRecipe.apply {
adapter = recipeStepPagerRecyclerAdapter
orientation = ViewPager2.ORIENTATION_HORIZONTAL
}

binding.dotsIndicator.attachTo(binding.vpStepRecipe)
}

override fun onDestroyView() {
super.onDestroyView()
_binding = null
}

companion object {
fun newInstance(recipeId: Long): RecipeStepFragment {
val fragment = RecipeStepFragment()
val args = Bundle()
args.putLong("recipeId", recipeId)
fragment.arguments = args
return fragment
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package net.pengcook.android.presentation.step

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import net.pengcook.android.databinding.ItemStepRecipeBinding
import net.pengcook.android.presentation.core.model.RecipeStep

class RecipeStepPagerRecyclerAdapter(
private var pageList: List<RecipeStep> = emptyList(),
) : RecyclerView.Adapter<RecipeStepViewHolder>() {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int,
): RecipeStepViewHolder {
val binding = ItemStepRecipeBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return RecipeStepViewHolder(binding)
}

override fun getItemCount(): Int = pageList.size

override fun onBindViewHolder(
holder: RecipeStepViewHolder,
position: Int,
) {
holder.bind(pageList[position])
}

fun updateList(list: List<RecipeStep>) {
pageList = list
notifyItemInserted(pageList.size)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package net.pengcook.android.presentation.step

import android.os.SystemClock
import androidx.recyclerview.widget.RecyclerView
import net.pengcook.android.databinding.ItemStepRecipeBinding
import net.pengcook.android.presentation.core.model.RecipeStep

class RecipeStepViewHolder(
private val binding: ItemStepRecipeBinding,
) : RecyclerView.ViewHolder(binding.root) {
fun bind(recipeStep: RecipeStep) {
binding.recipeStep = recipeStep
binding.chronometer.format = "%MM:ss"
binding.chronometer.base = SystemClock.elapsedRealtime() + recipeStep.sequence * 1000
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.pengcook.android.presentation.step

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
import net.pengcook.android.data.repository.feed.FeedRepository
import net.pengcook.android.presentation.core.model.RecipeStep

class RecipeStepViewModel(
private val recipeId: Long,
private val feedRepository: FeedRepository,
) : ViewModel() {
private var _recipeSteps: MutableLiveData<List<RecipeStep>> = MutableLiveData(emptyList())
val recipeSteps: LiveData<List<RecipeStep>>
get() = _recipeSteps

fun fetchRecipeSteps() {
viewModelScope.launch {
val response = feedRepository.fetchRecipeSteps(recipeId)
if (response.isSuccess) {
_recipeSteps.value = response.getOrNull() ?: emptyList()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package net.pengcook.android.presentation.step

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import net.pengcook.android.data.repository.feed.FeedRepository

class RecipeStepViewModelFactory(
private val recipeId: Long,
private val feedRepository: FeedRepository,
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(RecipeStepViewModel::class.java)) {
return RecipeStepViewModel(
recipeId = recipeId,
feedRepository = feedRepository,
) as T
} else {
throw IllegalArgumentException()
}
}
}

0 comments on commit 99b0d4c

Please sign in to comment.