<repo_name>diousk/CustomTimePicker<file_sep>/app/src/main/java/com/example/timepicker/NumberPickerFragment.kt
package com.example.timepicker

import android.app.Dialog
import android.content.DialogInterface
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.NumberPicker
import androidx.annotation.ColorInt
import com.example.timepicker.databinding.FragmentNumberPickerBinding
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import timber.log.Timber
import java.util.*


class NumberPickerFragment : BottomSheetDialogFragment() {

    lateinit var binding: FragmentNumberPickerBinding
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentNumberPickerBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.serviceTimePicker.setConfirmListener { dayOffset, hour, minute ->
            Timber.d("dayOffset $dayOffset, $hour, $minute")
        }
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
        dialog.setOnShowListener { setupBottomSheet(it) }
        return dialog
    }

    private fun setupBottomSheet(dialogInterface: DialogInterface) {
        val bottomSheetDialog = dialogInterface as BottomSheetDialog
        val bottomSheet = bottomSheetDialog.findViewById<View>(
            com.google.android.material.R.id.design_bottom_sheet)
            ?: return
        bottomSheet.setBackgroundColor(Color.TRANSPARENT)
    }
}
private const val TAG = "WidgetUtil"

internal fun NumberPicker.setDividerColor(@ColorInt color: Int) {
    try {
        NumberPicker::class.java.getDeclaredField("mSelectionDivider").apply {
            isAccessible = true
        }.set(this, ColorDrawable(color))
        invalidate()
    } catch (e: Exception) {
        Log.e(TAG, "setDividerColor failed. " + e.message)
    }
}


internal fun NumberPicker.setDividerHeight(height: Int) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        selectionDividerHeight = height
        return
    }

    try {
        NumberPicker::class.java.getDeclaredField("mSelectionDividerHeight")
            .apply { isAccessible = true }.set(this, height)
        invalidate()
    } catch (e: Exception) {
        Log.e(TAG, "setDividerHeight failed. " + e.message)
    }
}<file_sep>/app/src/main/java/com/example/timepicker/MainActivity.kt
package com.example.timepicker

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.timepicker.databinding.ActivityMainBinding
import timber.log.Timber

class MainActivity : AppCompatActivity() {

    lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Timber.plant(Timber.DebugTree())
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.picker.setOnClickListener {
            NumberPickerFragment().show(supportFragmentManager, "picker")
        }

    }
}<file_sep>/app/src/main/java/com/example/timepicker/ServiceTimePicker.kt
package com.example.timepicker

import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.FrameLayout
import com.example.timepicker.databinding.ViewServiceTimePickerBinding
import java.util.*

class ServiceTimePicker @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
    private val binding = ViewServiceTimePickerBinding
        .inflate(LayoutInflater.from(context), this, true)

    fun interface OnConfirmListener {
        fun onConfirm(dayOffset: Int, hour: Int, minute: Int)
    }
    private var confirmListener: OnConfirmListener? = null
    fun setConfirmListener(listener: OnConfirmListener) {
        confirmListener = listener
    }

    fun interface OnDismissListener {
        fun onDismiss()
    }

    init {
        binding.confirm.setOnClickListener {
            val dayOffset = binding.datePicker.value
            val hour = binding.hourPicker.value
            val minute = binding.minutePicker.value * MINUTE_INTERVAL
            confirmListener?.onConfirm(dayOffset, hour, minute)
        }

        val now = Calendar.getInstance()
        val nowHour = now.get(Calendar.HOUR_OF_DAY)
        val nowMin = now.get(Calendar.MINUTE)

        // minute picker
        val incHour = with(binding) {
            val stepForward = (nowMin >= MINUTE_INTERVAL)
            val minutes = (0..59).step(MINUTE_INTERVAL)
                .map { String.format("%02d", it) }.toTypedArray()
            minutePicker.displayedValues = minutes
            minutePicker.minValue = 0
            minutePicker.maxValue = minutes.size - 1
            minutePicker.setDividerHeight(1)
            minutePicker.value = if (stepForward) 0 else 1
            stepForward
        }

        // hour picker
        val incDay = with(binding) {
            val hourIncremental = if (incHour) 1 else 0
            val targetHour = nowHour + hourIncremental
            val hours = (0..23).map { String.format("%02d", it) }.toTypedArray()
            hourPicker.displayedValues = hours
            hourPicker.minValue = 0
            hourPicker.maxValue = hours.size - 1
            hourPicker.setDividerHeight(1)
            hourPicker.value = targetHour % 24
            targetHour >= 24
        }

        // date picker
        with(binding) {
            val dates = resources.getStringArray(R.array.readable_date_offset)
            datePicker.wrapSelectorWheel = false
            datePicker.displayedValues = dates
            datePicker.minValue = 0
            datePicker.maxValue = dates.size - 1
            datePicker.setDividerHeight(DIVIDER_HEIGHT)
            datePicker.value = if (incDay) 1 else 0
        }
    }

    companion object {
        private const val DIVIDER_HEIGHT = 1
        private const val MINUTE_INTERVAL = 30
    }
}