我有 3 个下拉菜单来选择开始时间、间隔和结束时间。基于这三个,我想生成药物的 nextIntakeTime 的时间单位列表。它适用于较小的时间,例如:小时、天、周和月。但当我使用年份作为治疗期时,它会提供额外的时间。
这是我到目前为止所得到的,但我得到了多年的额外时间单位。
import library
sealed class DropDownType {
data object MedicineTime : DropDownType()
data object MedicineIntervals : DropDownType()
data object TreatmentPeriod : DropDownType()
}
@RequiresApi(Build.VERSION_CODES.O)
fun getDropDownData(type: DropDownType): Pair<String, List<Pair<String, Int>>> {
return when (type) {
is DropDownType.MedicineTime -> {
val title = "Set intake time"
val formatter = DateTimeFormatter.ofPattern("h:mm a")
// Generate times for each hour of the day
val times = (0 until 24).map {
val time = LocalDateTime.of(2024, 1, 1, it, 0).format(formatter)
time to it
}
// If you want to exclude the exact time, use just the 'times' list
title to times
}
is DropDownType.MedicineIntervals -> {
val title = "Select Interval"
// You can dynamically map ChronoUnit intervals instead of hardcoding
val intervals = listOf(
"1 hour" to 1,
"6 hours" to 6,
"8 hours" to 8,
"16 hours" to 16,
"1 day" to 24, // 24 hours = 1 day
"2 days" to 48,
"3 days" to 72,
"4 days" to 96,
"5 days" to 120,
"6 days" to 144,
"1 week" to 168, // 1 week = 7 days = 168 hours
"2 weeks" to 336,
"1 month" to 720, // Approximate 1 month (30 days)
"2 months" to 1440,
"3 months" to 2160,
"6 months" to 4320,
)
title to intervals
}
is DropDownType.TreatmentPeriod -> {
val title = "Select Treatment Period"
// Same logic for treatment periods
val treatmentPeriods = listOf(
"1 day" to 24,
"2 days" to 48,
"1 week" to 168,
"2 weeks" to 336,
"3 weeks" to 504,
"4 weeks" to 672,
"1 month" to 720,
"2 months" to 1440,
"3 months" to 2160,
"6 months" to 4320,
"1 year" to 8760
)
title to treatmentPeriods
}
else -> "" to emptyList()
}
}
import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.RequiresApi
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Button
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import org.differenttouch.myapp.ui.theme.MyAppTheme
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
class MainActivity : ComponentActivity() {
@RequiresApi(Build.VERSION_CODES.O)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = Color.White
) {
CalculateHoursScreen()
}
}
}
}
}
@RequiresApi(Build.VERSION_CODES.O)
@Composable
fun CalculateHoursScreen() {
// Hold the selected options for intervals, time, and treatment period
var selectedInterval by remember { mutableStateOf<Pair<String, Any>?>(null) }
var selectedTime by remember { mutableStateOf<Pair<String, Any>?>(null) }
var selectedTreatmentPeriod by remember { mutableStateOf<Pair<String, Any>?>(null) }
var hoursList by remember { mutableStateOf<List<LocalDateTime>>(emptyList()) }
Column(modifier = Modifier.padding(16.dp)) {
// Dropdown for Medicine Time
val timeOptions = getDropDownData(DropDownType.MedicineTime)
CustomDropDown(
label = timeOptions.first,
options = timeOptions.second,
selectedOption = selectedTime
) { selectedTime = it }
Spacer(modifier = Modifier.height(16.dp))
// Dropdown for Medicine Intervals
val intervalOptions = getDropDownData(DropDownType.MedicineIntervals)
CustomDropDown(
label = intervalOptions.first,
options = intervalOptions.second,
selectedOption = selectedInterval
) { selectedInterval = it }
Spacer(modifier = Modifier.height(16.dp))
// Dropdown for Treatment Period
val treatmentPeriodOptions = getDropDownData(DropDownType.TreatmentPeriod)
CustomDropDown(
label = treatmentPeriodOptions.first,
options = treatmentPeriodOptions.second,
selectedOption = selectedTreatmentPeriod
) { selectedTreatmentPeriod = it }
Spacer(modifier = Modifier.height(16.dp))
// Button to trigger calculation
Button(
onClick = {
// Use the selected intake time instead of LocalDateTime.now()
val selectedHour = selectedTime?.second as? Int ?: LocalDateTime.now().hour
val startTime = LocalDateTime.now().withHour(selectedHour).withMinute(0) // Set start time to selected hour with 0 minutes
val intervalInHours = selectedInterval?.second as? Int ?: 1
// Define end time based on treatment period dropdown (can be plusDays(), plusWeeks(), etc.)
val endTime = calculateEndTime(startTime, selectedTreatmentPeriod?.second as? Int)
// Calculate intake times
hoursList = calculateTimesWithLargerUnits(startTime, endTime, intervalInHours, determineTimeUnit(selectedInterval?.first))
},
modifier = Modifier.fillMaxWidth()
) {
Text("Calculate Hours")
}
Spacer(modifier = Modifier.height(16.dp))
// Display the calculated hours
DisplayHoursList(hoursList)
}
}
@RequiresApi(Build.VERSION_CODES.O)
fun calculateEndTime(startTime: LocalDateTime, treatmentPeriodInHours: Int?): LocalDateTime {
return when {
treatmentPeriodInHours == null -> startTime.plusDays(1) // Default: plus 1 day
treatmentPeriodInHours <= 24 -> startTime.plusHours(treatmentPeriodInHours.toLong()) // Add hours if <= 24 hours
treatmentPeriodInHours <= 168 -> startTime.plusDays((treatmentPeriodInHours / 24).toLong()) // Add days if <= 1 week
treatmentPeriodInHours <= 720 -> startTime.plusWeeks((treatmentPeriodInHours / 168).toLong()) // Add weeks if <= 1 month
else -> startTime.plusMonths((treatmentPeriodInHours / 730).toLong()) // Add months for longer durations (730 hours ~ 30.42 days)
}
}
@RequiresApi(Build.VERSION_CODES.O)
fun determineTimeUnit(intervalLabel: String?): ChronoUnit {
return when (intervalLabel) {
"Week", "Weeks" -> ChronoUnit.WEEKS
"Month", "Months" -> ChronoUnit.MONTHS
"Year", "Years" -> ChronoUnit.YEARS
else -> ChronoUnit.HOURS
}
}
@RequiresApi(Build.VERSION_CODES.O)
@Composable
fun DisplayHoursList(hoursList: List<LocalDateTime>) {
// Formatter for date and 12-hour time format with AM/PM
val formatter = DateTimeFormatter.ofPattern("MMM d, yyyy h:mm a")
LazyColumn {
items(hoursList) { time ->
// Format each time to show date and time in 12-hour format
val formattedTime = time.format(formatter)
Text(
text = formattedTime,
modifier = Modifier.padding(8.dp)
)
}
}
}
@RequiresApi(Build.VERSION_CODES.O)
fun calculateTimesWithLargerUnits(
startTime: LocalDateTime,
endTime: LocalDateTime,
intervalValue: Int,
unit: ChronoUnit
): List<LocalDateTime> {
val steps = mutableListOf<LocalDateTime>()
// Always include the start time in the steps
steps.add(startTime)
// If unit is YEARS, calculate only the second time point
if (unit == ChronoUnit.YEARS) {
val secondTime = startTime.plusYears(intervalValue.toLong())
if (secondTime.isAfter(endTime)) {
steps.add(secondTime)
}
} else {
// For other units, calculate time points as before
var time = startTime
while (true) {
val nextTime = when (unit) {
ChronoUnit.DAYS -> time.plusDays(intervalValue.toLong())
ChronoUnit.WEEKS -> time.plusWeeks(intervalValue.toLong())
ChronoUnit.MONTHS -> time.plusMonths(intervalValue.toLong())
ChronoUnit.YEARS -> time.plusYears(intervalValue.toLong())
else -> time.plusHours(intervalValue.toLong())
}
if (nextTime.isAfter(endTime) || nextTime.isEqual(endTime)) {
break
}
steps.add(nextTime)
time = nextTime
}
}
return steps
}
这就是我得到的:
i set the intake time 12 am, Interval 6 months and treatment period 1 year it generates 3 intake times as:
Sep 22, 2024 12:00 am
Mar 21, 2025 12:00 am
Sep 17, 2025 12:00 am
while my app requires only first two intake:
Sep 22, 2024 12:00 am
Mar 21, 2025 12:00 am
示例用例:
For Months:
Start time: Sep 24, 2024 12:00 AM
Interval: 1 month
Treatment period: 3 months
Expected Output:
Sep 24, 2024 12:00 AM
Oct 24, 2024 12:00 AM
Nov 24, 2024 12:00 AM
For Years:
Start time: Sep 24, 2024 12:00 AM
Interval: 6 months
Treatment period: 1 year
Expected Output:
Sep 24, 2024 12:00 AM
Mar 24, 2025 12:00 AM
您假设
1 month
是 720 hours
,1 year
是 8760 hours
,等等 val intervals = listOf(
"1 hour" to (1 to ChronoUnit.HOURS),
"6 hours" to (6 to ChronoUnit.HOURS),
// others...
"1 day" to (1 to ChronoUnit.DAYS),
"2 days" to (2 to ChronoUnit.DAYS),
// others...
然后使用
calculateTimesWithLargerUnits
中的方法来获取下一次摄入时间,直到结束时间之前。