From c17f1170dfd7a0dd6ad37b8655caf4046c7f2aae Mon Sep 17 00:00:00 2001 From: ii2001 Date: Thu, 19 Sep 2024 13:42:41 +0900 Subject: [PATCH] :sparkles: timer customizing --- .../presentation/step/RecipeStepFragment.kt | 5 +- .../step/RecipeStepPagerRecyclerAdapter.kt | 4 +- .../presentation/step/RecipeStepViewHolder.kt | 71 ++++++++++++------- .../step/TimerSettingDialogFragment.kt | 61 ++++++++++++++++ .../main/res/layout/dialog_timer_setting.xml | 63 ++++++++++++++++ .../src/main/res/layout/item_step_recipe.xml | 9 ++- .../app/src/main/res/layout/item_timer.xml | 1 + 7 files changed, 183 insertions(+), 31 deletions(-) create mode 100644 android/app/src/main/java/net/pengcook/android/presentation/step/TimerSettingDialogFragment.kt create mode 100644 android/app/src/main/res/layout/dialog_timer_setting.xml diff --git a/android/app/src/main/java/net/pengcook/android/presentation/step/RecipeStepFragment.kt b/android/app/src/main/java/net/pengcook/android/presentation/step/RecipeStepFragment.kt index e7567876..a5e0e53d 100644 --- a/android/app/src/main/java/net/pengcook/android/presentation/step/RecipeStepFragment.kt +++ b/android/app/src/main/java/net/pengcook/android/presentation/step/RecipeStepFragment.kt @@ -30,7 +30,10 @@ class RecipeStepFragment : Fragment() { get() = _binding!! private val recipeStepPagerRecyclerAdapter: RecipeStepPagerRecyclerAdapter by lazy { - RecipeStepPagerRecyclerAdapter(viewPager2 = binding.vpStepRecipe) + RecipeStepPagerRecyclerAdapter( + viewPager2 = binding.vpStepRecipe, + fragmentManager = childFragmentManager + ) } diff --git a/android/app/src/main/java/net/pengcook/android/presentation/step/RecipeStepPagerRecyclerAdapter.kt b/android/app/src/main/java/net/pengcook/android/presentation/step/RecipeStepPagerRecyclerAdapter.kt index 25622a1f..2f950b7a 100644 --- a/android/app/src/main/java/net/pengcook/android/presentation/step/RecipeStepPagerRecyclerAdapter.kt +++ b/android/app/src/main/java/net/pengcook/android/presentation/step/RecipeStepPagerRecyclerAdapter.kt @@ -2,6 +2,7 @@ package net.pengcook.android.presentation.step import android.view.LayoutInflater import android.view.ViewGroup +import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.ViewPager2 import net.pengcook.android.databinding.ItemStepRecipeBinding @@ -10,6 +11,7 @@ import net.pengcook.android.presentation.core.model.RecipeStep class RecipeStepPagerRecyclerAdapter( private var pageList: List = emptyList(), private val viewPager2: ViewPager2, + private val fragmentManager: FragmentManager, ) : RecyclerView.Adapter() { override fun onCreateViewHolder( @@ -19,7 +21,7 @@ class RecipeStepPagerRecyclerAdapter( val binding = ItemStepRecipeBinding.inflate( LayoutInflater.from(parent.context), parent, false ) - return RecipeStepViewHolder(binding) + return RecipeStepViewHolder(binding, fragmentManager = fragmentManager) } override fun getItemCount(): Int = pageList.size diff --git a/android/app/src/main/java/net/pengcook/android/presentation/step/RecipeStepViewHolder.kt b/android/app/src/main/java/net/pengcook/android/presentation/step/RecipeStepViewHolder.kt index 78e2b26c..eefc4649 100644 --- a/android/app/src/main/java/net/pengcook/android/presentation/step/RecipeStepViewHolder.kt +++ b/android/app/src/main/java/net/pengcook/android/presentation/step/RecipeStepViewHolder.kt @@ -2,47 +2,66 @@ package net.pengcook.android.presentation.step import android.os.CountDownTimer import android.view.View +import androidx.fragment.app.FragmentManager 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) { + private val fragmentManager: FragmentManager, +) : RecyclerView.ViewHolder(binding.root), TimerSettingDialogFragment.TimerSettingListener { private var isTimerRunning = false private var countDownTimer: CountDownTimer? = null - fun bind(recipeStep: RecipeStep, moveToNextStep: () -> Unit) { - binding.recipeStep = recipeStep + private var moveToNextStep: (() -> Unit)? = null - val cookingTimeInSeconds = convertToSeconds(recipeStep.cookingTime) + private var cookingTimeInMillis: Long = 0L - binding.timer.tvTimer.text = formatTime(cookingTimeInSeconds * 1000) + fun bind(recipeStep: RecipeStep, moveToNextStep: () -> Unit) { + this.moveToNextStep = moveToNextStep + binding.recipeStep = recipeStep - val clickListener = View.OnClickListener { - when { - cookingTimeInSeconds <= 1 -> { - moveToNextStep() - } + cookingTimeInMillis = convertToMillis(recipeStep.cookingTime) + binding.timer.tvTimer.text = formatTime(cookingTimeInMillis) - !isTimerRunning -> { - startTimer(cookingTimeInSeconds * 1000, moveToNextStep) - isTimerRunning = true - } + val timerClickListener = View.OnClickListener { + showTimerSettingDialog() + } + binding.clickListener = timerClickListener - else -> { - stopTimer() - moveToNextStep() - } + val contentClickListener = View.OnClickListener { + if (!isTimerRunning) { + startTimer(cookingTimeInMillis) + isTimerRunning = true + } else { + stopTimer() + moveToNextStep() } } - binding.clickListener = clickListener + binding.contentClickListener = contentClickListener binding.executePendingBindings() } - private fun startTimer(durationInMillis: Long, moveToNextStep: () -> Unit) { + private fun showTimerSettingDialog() { + val dialog = TimerSettingDialogFragment() + dialog.listener = this + dialog.show(fragmentManager, "TimerSettingDialog") + } + + override fun onTimeSet(minutes: Int, seconds: Int) { + val totalMillis = (minutes * 60 + seconds) * 1000L + cookingTimeInMillis = totalMillis + + binding.timer.tvTimer.text = formatTime(cookingTimeInMillis) + isTimerRunning = false + countDownTimer?.cancel() + countDownTimer = null + } + + private fun startTimer(durationInMillis: Long) { countDownTimer = object : CountDownTimer(durationInMillis, 1000) { override fun onTick(millisUntilFinished: Long) { binding.timer.tvTimer.text = formatTime(millisUntilFinished) @@ -51,7 +70,7 @@ class RecipeStepViewHolder( override fun onFinish() { binding.timer.tvTimer.text = "00:00" isTimerRunning = false - moveToNextStep() + moveToNextStep?.invoke() } }.start() } @@ -68,11 +87,11 @@ class RecipeStepViewHolder( return String.format("%02d:%02d", minutes, seconds) } - private fun convertToSeconds(time: String): Long { + private fun convertToMillis(time: String): Long { val timeParts = time.split(":") - val hours = timeParts.getOrNull(0)?.toIntOrNull() ?: 0 - val minutes = timeParts.getOrNull(1)?.toIntOrNull() ?: 0 - val seconds = timeParts.getOrNull(2)?.toIntOrNull() ?: 0 - return (hours * 3600 + minutes * 60 + seconds).toLong() + val hours = timeParts.getOrNull(0)?.toLongOrNull() ?: 0L + val minutes = timeParts.getOrNull(1)?.toLongOrNull() ?: 0L + val seconds = timeParts.getOrNull(2)?.toLongOrNull() ?: 0L + return (hours * 3600 + minutes * 60 + seconds) * 1000L } } diff --git a/android/app/src/main/java/net/pengcook/android/presentation/step/TimerSettingDialogFragment.kt b/android/app/src/main/java/net/pengcook/android/presentation/step/TimerSettingDialogFragment.kt new file mode 100644 index 00000000..51101201 --- /dev/null +++ b/android/app/src/main/java/net/pengcook/android/presentation/step/TimerSettingDialogFragment.kt @@ -0,0 +1,61 @@ +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.DialogFragment +import net.pengcook.android.databinding.DialogTimerSettingBinding + +class TimerSettingDialogFragment : DialogFragment() { + + private var _binding: DialogTimerSettingBinding? = null + private val binding get() = _binding!! + + interface TimerSettingListener { + fun onTimeSet(minutes: Int, seconds: Int) + } + + var listener: TimerSettingListener? = null + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + _binding = DialogTimerSettingBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setupNumberPickers() + + binding.btnConfirm.setOnClickListener { + val minutes = binding.npMinutes.value + val seconds = binding.npSeconds.value + listener?.onTimeSet(minutes, seconds) + dismiss() + } + + binding.btnCancel.setOnClickListener { + dismiss() + } + } + + private fun setupNumberPickers() { + binding.npMinutes.minValue = 0 + binding.npMinutes.maxValue = 59 + binding.npMinutes.wrapSelectorWheel = true + + binding.npSeconds.minValue = 0 + binding.npSeconds.maxValue = 59 + binding.npSeconds.wrapSelectorWheel = true + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} diff --git a/android/app/src/main/res/layout/dialog_timer_setting.xml b/android/app/src/main/res/layout/dialog_timer_setting.xml new file mode 100644 index 00000000..70c2ac9e --- /dev/null +++ b/android/app/src/main/res/layout/dialog_timer_setting.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + +