diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/polls/PollDeadlinePicker.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/polls/PollDeadlinePicker.kt index 64a70ae6a..538735cda 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/polls/PollDeadlinePicker.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/polls/PollDeadlinePicker.kt @@ -56,11 +56,10 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.note.timeAheadNoDot import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.ShortNotePostViewModel import com.vitorpamplona.amethyst.ui.stringRes +import com.vitorpamplona.quartz.utils.TimeUtils import java.time.Instant -import java.time.LocalDate -import java.time.LocalDateTime -import java.time.LocalTime import java.time.ZoneId +import java.time.ZoneOffset @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -69,15 +68,12 @@ fun PollDeadlinePicker(model: ShortNotePostViewModel) { var showTimePicker by remember { mutableStateOf(false) } // Get current time details - val currentTime = LocalDateTime.now() + val currentTime = Instant.ofEpochMilli(model.closedAt * 1000).atZone(ZoneId.systemDefault()).toLocalDateTime() val datePickerState = rememberDatePickerState( - initialSelectedDateMillis = - currentTime - .atZone(ZoneId.systemDefault()) - .toInstant() - .toEpochMilli(), + initialSelectedDateMillis = model.closedAt * 1000, + yearRange = currentTime.year..2050, selectableDates = object : SelectableDates { override fun isSelectableDate(utcTimeMillis: Long): Boolean { @@ -106,11 +102,11 @@ fun PollDeadlinePicker(model: ShortNotePostViewModel) { Icon(Icons.Default.DateRange, contentDescription = null) Spacer(Modifier.width(12.dp)) - if (model.closedAt == null) { - Text(stringRes(R.string.poll_closing_date_time), style = MaterialTheme.typography.bodyLarge) + if (model.closedAt < TimeUtils.oneMinuteFromNow()) { + Text(stringRes(R.string.poll_closing_date_time) + " " + model.closedAt, style = MaterialTheme.typography.bodyLarge) } else { Text( - text = timeAheadNoDot(model.closedAt, context), + text = stringRes(R.string.poll_closing_in, timeAheadNoDot(model.closedAt, context)), style = MaterialTheme.typography.bodyLarge, ) } @@ -140,28 +136,23 @@ fun PollDeadlinePicker(model: ShortNotePostViewModel) { }, onDismissRequest = { showTimePicker = false }, confirmButton = { - TextButton(onClick = { - val date = - datePickerState.selectedDateMillis?.let { - Instant.ofEpochMilli(it).atZone(ZoneId.systemDefault()).toLocalDate() - } ?: LocalDate.now() + TextButton( + onClick = { + val datetimeLocalTimeZone = + datePickerState.selectedDateMillis?.let { localDayAtZeroHourMillis -> + (localDayAtZeroHourMillis / 1000) + + (timePickerState.hour * TimeUtils.ONE_HOUR) + + (timePickerState.minute * TimeUtils.ONE_MINUTE) + } ?: TimeUtils.oneDayAhead() - val finalDateTime = - LocalDateTime.of( - date, - LocalTime.of(timePickerState.hour, timePickerState.minute), - ) + // Get the offset from UTC for the current instant in the local time zone + val offset: ZoneOffset = ZoneId.systemDefault().rules.getOffset(Instant.now()) - // 2. Convert to Unix Timestamp (Seconds) - val unixTimestamp = - finalDateTime - .atZone(ZoneId.systemDefault()) - .toInstant() - .epochSecond + model.closedAt = datetimeLocalTimeZone - offset.totalSeconds - model.closedAt = unixTimestamp - showTimePicker = false - }) { Text(stringResource(R.string.confirm)) } + showTimePicker = false + }, + ) { Text(stringResource(R.string.confirm)) } }, ) { TimePicker(state = timePickerState) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt index 0a40b2548..88de6da65 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt @@ -123,6 +123,7 @@ import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceEvent import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceReplyEvent import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.RandomInstance +import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.StateFlow @@ -220,7 +221,7 @@ open class ShortNotePostViewModel : var canUsePoll by mutableStateOf(false) var wantsPoll by mutableStateOf(false) var pollOptions: SnapshotStateMap = newStateMapPollOptions() - var closedAt by mutableStateOf(null) + var closedAt by mutableStateOf(TimeUtils.oneDayAhead()) // Invoices var canAddInvoice by mutableStateOf(false) @@ -539,9 +540,7 @@ open class ShortNotePostViewModel : pollOptions[index] = tag } - draftEvent.endsAt()?.let { - closedAt = it - } + closedAt = draftEvent.endsAt() ?: TimeUtils.oneDayAhead() message = TextFieldValue(draftEvent.content) @@ -889,7 +888,7 @@ open class ShortNotePostViewModel : wantsPoll = false pollOptions = newStateMapPollOptions() - closedAt = null + closedAt = TimeUtils.oneDayAhead() wantsInvoice = false wantsZapRaiser = false @@ -1018,7 +1017,8 @@ open class ShortNotePostViewModel : ( !wantsPoll || ( - pollOptions.isNotEmpty() && pollOptions.all { it.value.label.isNotEmpty() } + pollOptions.isNotEmpty() && pollOptions.all { it.value.label.isNotEmpty() } && + closedAt > TimeUtils.oneMinuteFromNow() ) ) && multiOrchestrator == null diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index 1096a822b..72b79c6fb 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -469,6 +469,7 @@ Consensus (0–100)% Poll Closing Date & Time + Poll closes in %1$s Close after days Unable to vote diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/TimeUtils.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/TimeUtils.kt index 313710f10..c8fcbde7d 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/TimeUtils.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/TimeUtils.kt @@ -55,6 +55,8 @@ object TimeUtils { fun oneDayAgo() = now() - ONE_DAY + fun oneDayAhead() = now() + ONE_DAY + fun eightHoursAgo() = now() - EIGHT_HOURS fun twoDays() = ONE_DAY * 2