Yug Mewada
Yug Mewada

Reputation: 1

How to get top and bottom margin using android kotlin

Click here to see screenshot ROTA chart

As shown in attached screenshot I am setting bars based on time line and managing their top using below calculation here I am facing one issue which is As you can see in Red color bar My time difference comes 33 minutes then it should be drawn from slight below from center line which is between 11:00 and 12:00, Same as for Blue color bar The time difference is 43 minutes so it should be drawn from below of Center line which is between 15:00 and 16:00 but it has drawn from 16:00 which is wrong so can anyone provide me solution for the same?, Below is code for whole adapter please let me know my mistake.

NOTE : Whole code is for what i implemented in whole adapter just facing issue of getting margin based on time diffrence, I want to give margin top and bottom based on time difference For example My appointment time is 11:00 But I have started appointment at 11:30 then my Bars should apply top and bottom margin based on difference of 33 mins all code for calculating difference works well but i am not getting accurate margin, Also for information

  1. Red color indicates that appointment has missed by user
  2. Blue color indicates that time duration of an appointment in which user has worked for example appointment time is 11:00 But user worked 11:33 to 01:00
  3. Green color indicates the scheduled appointment time for example appointment time is 11:00 to 12:00
class RotaChartAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    
        var shiftTimeList = arrayListOf<RotaTimeListResponse>()
        private val mChartDataList: ArrayList<RotaHolderTimeData> = CommonDataProvider.getDaysHours24()
        private var mainAdapterPosition: Int = -1
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
            return ViewHolder(
                RotaRowItemChartBinding.inflate(
                    LayoutInflater.from(parent.context), parent, false
                )
            )
        }
    
        override fun getItemCount(): Int {
            return 24
        }
    
        override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
            (holder as ViewHolder).apply {
                binding()
                manageRedBlock()
                manageGreenBlock()
            }
        }
    
        private fun String?.extractHourOnly(): Int {
            return this?.getLocalTime()?.substring(0, 2)?.toIntOrNull() ?: 0
        }
    
        private fun getBetween(startTime: String, endTime: String): Long {
            val timeFormatter = DateTimeFormatter.ofPattern("HH:mm")
            val start = LocalTime.parse(startTime, timeFormatter)
            val end = LocalTime.parse(endTime, timeFormatter)
            return abs(Duration.between(start, end).toMinutes())
        }
    
        private fun String?.getLocalTime(): String? {
            return this?.getUTCToLocalLong()?.formatDate("HH:mm")
        }
    
        private fun String?.getAccurateEnd(): Int {
            var endHour = this?.getLocalTime()?.substring(0, 2)?.toIntOrNull() ?: 0
            val endMinutes = this?.getLocalTime()?.substring(3)?.toIntOrNull() ?: 0
            if (endMinutes > 0) {
                endHour += 1
            }
            return endHour
        }
    
        inner class ViewHolder(private val binding: RotaRowItemChartBinding) :
            RecyclerView.ViewHolder(binding.root) {
            fun binding() = with(binding) {
                setHeightDynamic(root, blockBlue, blockGreen, blockRed)
    
                if (mainAdapterPosition == 0) {
                    viewGrayLine.setStartMargin(R.dimen.dp_12)
                }
                viewBlueBottom.isVisible = adapterPosition == (itemCount - 1)
    
                manageView()
                ivProfile.gone()
            }
    
            private fun manageView() = with(binding) {
                blockBlue.isInvisible = true
                blockRed.isInvisible = true
                blockGreen.isInvisible = true
            }
    
            fun manageRedBlock() = with(binding) {
                shiftTimeList.forEach terminateLoop@{
                    val data = mChartDataList[adapterPosition]
                    if (!it.startTime.isNullOrEmpty() && !it.endTime.isNullOrEmpty()) {
                        if (it.appointmentStatus == StatusEnum.MISSED.value) {
                            if (areTimesWithinRange(
                                    startTime = data.fixedStartTime,
                                    endTime = data.fixedEndTime,
                                    betweenStartTime = it.startTime.getLocalTime().toString(),
                                    betweenEndTime = it.endTime.getLocalTime().toString(),
                                    position = adapterPosition
                                )
                            ) {
                                blockRed.post {
                                    blockRed.isVisible = true
    
                                    handleStartTime(
                                        startTime = it.startTime,
                                        fixedStartTime = data.fixedStartTime,
                                        block = blockRed
                                    )
    
                                    handleEndTime(
                                        endTime = it.endTime,
                                        fixedEndTime = data.fixedEndTime,
                                        block = blockRed
                                    )
                                }
                                return@terminateLoop
                            }
                        }
                    }
                }
            }
    
            fun manageGreenBlock() = with(binding) {
                shiftTimeList.forEach terminateLoop@{
                    val data = mChartDataList[adapterPosition]
                    if (!it.shiftStartTime.isNullOrEmpty() && !it.shiftEndTime.isNullOrEmpty()) {
                        if (it.appointmentStatus == StatusEnum.COMPLETED.value) {
                            if (areTimesWithinRange(
                                    startTime = data.fixedStartTime,
                                    endTime = data.fixedEndTime,
                                    betweenStartTime = it.startTime.getLocalTime().toString(),
                                    betweenEndTime = it.endTime.getLocalTime().toString(),
                                    position = adapterPosition
                                )
                            ) {
                                blockGreen.post {
                                    blockGreen.isVisible = true
                                    val cornerRadius =
                                        itemView.resources.getDimensionPixelSize(R.dimen.dp_8).toFloat()
    
                                    if (
                                        handleStartTime(
                                            startTime = it.startTime,
                                            fixedStartTime = data.fixedStartTime,
                                            block = blockGreen
                                        )
                                    ) {
                                        ivProfile.isVisible = true
                                        setTopRadius(cornerRadius, blockGreen)
                                    } else {
                                        ivProfile.isVisible = false
                                        setTopRadius(0f, blockGreen)
                                    }
    
                                    if (
                                        handleEndTime(
                                            endTime = it.endTime,
                                            fixedEndTime = data.fixedEndTime,
                                            block = blockGreen
                                        )
                                    ) {
                                        setBottomRadius(cornerRadius, blockGreen)
                                    } else {
                                        setBottomRadius(0f, blockGreen)
                                    }
                                }
                            }
    
                            if (areTimesWithinRange(
                                    startTime = data.fixedStartTime,
                                    endTime = data.fixedEndTime,
                                    betweenStartTime = it.shiftStartTime.getLocalTime().toString(),
                                    betweenEndTime = it.shiftEndTime.getLocalTime().toString(),
                                    position = adapterPosition
                                )
                            ) {
                                blockBlue.post {
                                    blockBlue.isVisible = true
    
                                    handleStartTime(
                                        startTime = it.shiftStartTime,
                                        fixedStartTime = data.fixedStartTime,
                                        block = blockBlue
                                    )
    
                                    handleEndTime(
                                        endTime = it.shiftEndTime,
                                        fixedEndTime = data.fixedEndTime,
                                        block = blockBlue
                                    )
                                }
                            }
                        }
                    }
                }
            }
        }
    
        private fun setTopRadius(radius: Float, vararg views: View) {
            views.forEach {
                it.setBackgroundRadiusTopPx(radius)
            }
        }
    
        private fun setBottomRadius(radius: Float, vararg views: View) {
            views.forEach {
                it.setBackgroundRadiusBottomPx(radius)
            }
        }
    
        private fun setRadius(radius: Float, vararg views: View) {
            views.forEach {
                it.setBackgroundRadiusPx(radius)
            }
        }
    
        private fun handleStartTime(
            startTime: String?,
            fixedStartTime: String,
            block: View
        ): Boolean {
            return if (startTime?.extractHourOnly() == fixedStartTime.substring(0, 2).toInt()) {
                val difference = getBetween(
                    startTime = fixedStartTime,
                    endTime = startTime.getLocalTime().toString()
                )
                val topMargin = calculateTopMargin(
                    view = block,
                    context = block.context,
                    differenceInMinutes = difference,
                    isTop = true
                )
                eLog("============================================================================")
                eLog("Difference ====> $difference Start Time: ${startTime.getLocalTime()}")
                block.setTopMargin(topMargin)
                true
            } else {
                false
            }
        }
    
        private fun areTimesWithinRange(
            startTime: String,
            endTime: String,
            betweenStartTime: String,
            betweenEndTime: String,
            position: Int
        ): Boolean {
            val format = SimpleDateFormat("HH:mm", Locale.getDefault())
            val start = format.parse(startTime)
            val end = format.parse(endTime)
            val betweenStart = format.parse(betweenStartTime)
            val betweenEnd = format.parse(betweenEndTime)
    
            val isBetween =
                if (start != null && end != null && betweenStart != null && betweenEnd != null) {
                    if (betweenStart <= betweenEnd) {
                        // Check for overlap in the normal case
                        !(end <= betweenStart || start >= betweenEnd)
                    } else {
                        // Check for overlap when the range crosses midnight
                        !(end <= betweenStart && start >= betweenEnd)
                    }
                } else {
                    false
                }
            return isBetween
        }
    
        private fun handleEndTime(
            endTime: String?,
            fixedEndTime: String,
            block: View
        ): Boolean {
            return if (endTime?.getAccurateEnd() == fixedEndTime.substring(0, 2).toInt()) {
                val difference = getBetween(
                    startTime = fixedEndTime,
                    endTime = endTime.getLocalTime().toString()
                )
                val bottomMargin = calculateTopMargin(
                    view = block,
                    context = block.context,
                    differenceInMinutes = difference,
                    isTop = false
                )
                block.setBottomMargin(bottomMargin)
                true
            } else {
                false
            }
        }
    
    
        fun setList(time: ArrayList<RotaTimeListResponse>, mainAdapterPosition: Int) {
            this.mainAdapterPosition = mainAdapterPosition
            shiftTimeList = time
            notifyChangeAll()
        }
    
        private fun setHeightDynamic(vararg views: View) {
            // Get the screen density from any view (all views share the same context density)
            val density = views.firstOrNull()?.context?.resources?.displayMetrics?.density ?: return
    
            // Calculate the height dynamically based on density
            val dynamicHeight =
                (100 * density).toInt() // Adjust '100' to your desired base height logic
    
            // Loop through each view and set its height
            views.forEach { view ->
                val layoutParams = view.layoutParams
                layoutParams.height = dynamicHeight
                view.layoutParams = layoutParams
            }
        }
    
    
        private fun calculateTopMargin(
            context: Context,
            differenceInMinutes: Long,
            view: View,
            isTop: Boolean
        ): Int {
            try {
                val totalHeightOfView = view.height.toFloat()
                val heightPerMinute = totalHeightOfView / 60L
                val topMargin = differenceInMinutes * heightPerMinute
    
                eLog("TOP totalHeightOfView  =====> $$totalHeightOfView")
                eLog("TOP totalHeightOfView IN DP  =====> $${totalHeightOfView.toInt().toDp(context)}")
                eLog("TOP heightPerMinute  =====> $$heightPerMinute")
                eLog("TOP topMargin  =====> $$topMargin")
                eLog("TOP topMargin IN INTEGER  =====> $${topMargin.toInt()}")
                eLog("TOP topMargin IN DP  =====> $${topMargin.toInt().toDp(context)}")
                eLog("TOP topMargin coerceAtMost  =====> $${topMargin.coerceAtMost(300f).toInt()}")
    
                // Convert pixels to dp
                return topMargin.toInt().toDp(context)
            } catch (e: Exception) {
                e.printStackTrace()
                return 0
            }
        }
    }

Upvotes: 0

Views: 45

Answers (0)

Related Questions