I am working on a program that the user can use to track the parameters of his body (such as weight, waist size). I have a code that builds a chart based on these data. I would like to hear criticism on my code. What I don't like :
- MeasurementCHartHelperю - It seems to me that this is not a very good name.
- Also I do not like that I mixed business logic and code for draw chart. But I do not know how it would be better to separate, what is the best way to name the classes
- Measurement.kt. I want to know if it is correct to have my extension functions there
MeasurementChartHelper.kt
class MeasurementChartHelper{
private val now = Date(LocalDateTime.now())
fun getChartData(measurements: List<Measurement>,timeInterval: TimeInterval): LineChartData? {
val points = getChartPoints(measurements,timeInterval)
if(points.isNotEmpty()) {
val seriesData = listOf(LineChartData.SeriesData("", points, Green,gradientFill = true))
return LineChartData(seriesData,autoYLabels = true,horizontalLines = true)
}
return null
}
private fun getChartPoints(measurements: List<Measurement>,timeInterval: TimeInterval): List<LineChartData.SeriesData.Point> {
return getMeasurementValuesForTimeInterval(measurements.sortByDate(),timeInterval).map { LineChartData.SeriesData.Point(it.key,it.value.toFloat()) }
}
private fun getMeasurementValuesForTimeInterval(measurements: List<Measurement>,timeInterval: TimeInterval): Map<Int, Double> {
return measurements
.groupBy { getMeasurementTimeIntervalNumber(it, timeInterval) }
.filterKeys { it != -1 }
.mapValues { it.value.map { measurement -> measurement.value }.average() }
}
private fun getMeasurementTimeIntervalNumber(measurement: Measurement, timeInterval: TimeInterval): Int {
val timeDifference = now - measurement.date
if(timeDifference.epochMillis >= 0) {
val daysDifference = (timeDifference.epochMillis / (TimeUnit.DAYS.toSeconds(1) * 1000)).toInt()
if (daysDifference <= timeInterval.days && daysDifference >= 0)
return timeInterval.days - (daysDifference / timeInterval.daysInInterval)
}
return -1
}
}
Measurement.kt
@Entity
class Measurement(
@PrimaryKey(autoGenerate = true) var id: Int = 0,
var measurementType: MeasurementType,
var value: Float,
var date: Date
)
fun List<Measurement>.byMeasurementType(): Map<MeasurementType, List<Measurement>> {
return this.sortByDate().groupBy(Measurement::measurementType)
}
fun List<Measurement>.sortByDate(): List<Measurement> {
return this.sortedBy { measurement -> measurement.date.epochMillis }
}
MeasurementType,kt
enum class MeasurementType(
val measurement: String,
@StringRes val measurementDescription: Int,
@StringRes val measurementFullDescription: Int
) {
Weight(
"Weight",
R.string.weight_measurement_description,
R.string.weight_measurement_full_description
),
CaloricIntake(
"CaloricIntake",
R.string.weight_caloric_intake_description,
R.string.weight_caloric_intake_full_description
),
BodyFat(
"BodyFat",
R.string.weight_body_fat_description,
R.string.weight_body_fat_full_description
),
Waist(
"Waist",
R.string.waist_description,
R.string.waist_full_description
),
Chest(
"Chest",
R.string.chest_description,
R.string.chest_full_description
),
Arm(
"Arm",
R.string.arm_description,
R.string.arm_full_description
);
companion object {
fun getMeasurementType(measurementName: String): MeasurementType {
try {
return values().find { it.measurement == measurementName }!!
} catch (ex: Exception) {
throw EnumConstantNotPresentException(MeasurementType::class.java, measurementName)
}
}
fun getAllMeasurements(): List<MeasurementType> {
return values().toList()
}
}
}
TimeInterval.kt
enum class TimeInterval(val id: Int, val days: Int, val daysInInterval: Int) {
LastWeek(0, 7, 1),
LastMonth(1, 30, 3),
LastTwoMonths(2, 60, 6),
LastYear(3, 365, 30),
AllTime(4, 1000000, 1);
companion object {
fun findTimeIntervalById(id: Int): TimeInterval {
return values().firstOrNull { it.id == id }
?: error("Cant find TimeInterval with id - $id")
}
}
}