@ -29,12 +29,15 @@ import kotlinx.coroutines.launch
import org.tasks.R
import org.tasks.databinding.DialogDateTimePickerBinding
import org.tasks.date.DateTimeUtils.newDateTime
import org.tasks.date.DateTimeUtils.toDateTime
import org.tasks.dialogs.MyTimePickerDialog.newTimePicker
import org.tasks.locale.Locale
import org.tasks.notifications.NotificationManager
import org.tasks.preferences.Preferences
import org.tasks.themes.Theme
import org.tasks.time.DateTime
import org.tasks.time.DateTimeUtils.millisOfDay
import org.tasks.time.DateTimeUtils.startOfDay
import java.time.format.FormatStyle
import javax.inject.Inject
@ -49,12 +52,13 @@ class DateTimePicker : BottomSheetDialogFragment() {
@Inject lateinit var theme : Theme
lateinit var binding : DialogDateTimePickerBinding
private var customDate : DateTime ? = null
private var selected : DateTime ? = null
private var customDate = NO _DAY
private var customTime = NO _TIME
private var selectedDay = NO _DAY
private var selectedTime = NO _TIME
private val today = newDateTime ( ) . startOfDay ( )
private val tomorrow = today . plusDays ( 1 )
private val nextWeek = today . plusDays ( 7 )
private var customTime = 0
private var morning = 32401000
private var afternoon = 46801000
private var evening = 61201000
@ -66,17 +70,25 @@ class DateTimePicker : BottomSheetDialogFragment() {
}
companion object {
const val EXTRA _DAY = " extra_day "
const val EXTRA _TIME = " extra_time "
const val EXTRA _TASKS = " extra_tasks "
const val EXTRA _TIMESTAMP = " extra_timestamp "
const val EXTRA _TASK = " extra_task "
private const val EXTRA _AUTO _CLOSE = " extra_auto_close "
private const val EXTRA _SELECTED = " extra_selected "
private const val REQUEST _TIME = 10101
private const val FRAG _TAG _TIME _PICKER = " frag_tag_time_picker "
private const val NO _DAY = 0L
private const val NO _TIME = 0
private const val MULTIPLE _DAYS = - 1L
private const val MULTIPLE _TIMES = - 1
fun newDateTimePicker ( task : Long , current : Long , autoClose : Boolean ) : DateTimePicker {
fun newDateTimePicker ( autoClose: Boolean , vararg tasks : Task ) : DateTimePicker {
val bundle = Bundle ( )
bundle . putLong ( EXTRA _TASK , task )
bundle . putLong ( EXTRA _TIMESTAMP , current )
bundle . putLongArray ( EXTRA _TASKS , tasks . map { it . id } . toLongArray ( ) )
val dueDates = tasks . map { it . dueDate . startOfDay ( ) } . toSet ( )
val dueTimes = tasks . map { it . dueDate . millisOfDay ( ) } . toSet ( )
bundle . putLong ( EXTRA _DAY , if ( dueDates . size == 1 ) dueDates . first ( ) else - 1 )
bundle . putInt ( EXTRA _TIME , if ( dueTimes . size == 1 ) dueTimes . first ( ) else - 1 )
bundle . putBoolean ( EXTRA _AUTO _CLOSE , autoClose )
val fragment = DateTimePicker ( )
fragment . arguments = bundle
@ -85,7 +97,8 @@ class DateTimePicker : BottomSheetDialogFragment() {
fun newDateTimePicker ( target : Fragment , rc : Int , current : Long , autoClose : Boolean ) : DateTimePicker {
val bundle = Bundle ( )
bundle . putLong ( EXTRA _TIMESTAMP , current )
bundle . putLong ( EXTRA _DAY , current . startOfDay ( ) )
bundle . putInt ( EXTRA _TIME , current . millisOfDay ( ) )
bundle . putBoolean ( EXTRA _AUTO _CLOSE , autoClose )
val fragment = DateTimePicker ( )
fragment . arguments = bundle
@ -108,18 +121,15 @@ class DateTimePicker : BottomSheetDialogFragment() {
binding . shortcuts . nextWeekButton . text =
getString ( R . string . next , DateUtilities . getWeekdayShort ( newDateTime ( ) . plusWeeks ( 1 ) , locale . locale ) )
binding . calendarView . setOnDateChangeListener { _ , y , m , d ->
selected = DateTime ( y , m + 1 , d , selected ?. hourOfDay ?: 0 , selected ?. minuteOfHour
?: 0 , selected ?. secondOfMinute ?: 0 )
returnDate ( selected !! . millis )
returnDate ( day = DateTime ( y , m + 1 , d ) . millis )
refreshButtons ( )
}
val firstDayOfWeek = preferences . firstDayOfWeek
if ( firstDayOfWeek in 1. . 7 ) {
binding . calendarView . firstDayOfWeek = firstDayOfWeek
}
val timestamp = savedInstanceState ?. getLong ( EXTRA _SELECTED )
?: requireArguments ( ) . getLong ( EXTRA _TIMESTAMP )
selected = if ( timestamp > 0 ) DateTime ( timestamp ) else null
selectedDay = savedInstanceState ?. getLong ( EXTRA _DAY ) ?: requireArguments ( ) . getLong ( EXTRA _DAY )
selectedTime = savedInstanceState ?. getInt ( EXTRA _TIME ) ?: requireArguments ( ) . getInt ( EXTRA _TIME )
return binding . root
}
@ -141,54 +151,61 @@ class DateTimePicker : BottomSheetDialogFragment() {
}
private fun refreshButtons ( ) {
when ( selected ?. startOf Day( ) ) {
null -> binding . shortcuts . dateGroup . check ( R . id . no _date _button )
today -> binding . shortcuts . dateGroup . check ( R . id . today _button )
tomorrow -> binding . shortcuts . dateGroup . check ( R . id . tomorrow _button )
nextWeek -> binding . shortcuts . dateGroup . check ( R . id . next _week _button )
when ( selected Day) {
0L -> binding . shortcuts . dateGroup . check ( R . id . no _date _button )
today . millis -> binding . shortcuts . dateGroup . check ( R . id . today _button )
tomorrow . millis -> binding . shortcuts . dateGroup . check ( R . id . tomorrow _button )
nextWeek . millis -> binding . shortcuts . dateGroup . check ( R . id . next _week _button )
else -> {
customDate = selected
customDate = selected Day
binding . shortcuts . dateGroup . check ( R . id . current _date _selection )
binding . shortcuts . currentDateSelection . visibility = View . VISIBLE
binding . shortcuts . currentDateSelection . text =
DateUtilities . getRelativeDay ( context , selected !! . millis , locale . locale , FormatStyle . MEDIUM )
binding . shortcuts . currentDateSelection . text = if ( customDate == MULTIPLE _DAYS ) {
requireContext ( ) . getString ( R . string . date _picker _multiple )
} else {
DateUtilities . getRelativeDay ( context , selectedDay , locale . locale , FormatStyle . MEDIUM )
}
}
}
if ( Task . hasDueTime ( selected ?. millis ?: 0 ) ) {
when ( selected ?. millisOfDay ) {
if ( selectedTime == MULTIPLE _TIMES || Task . hasDueTime ( selected Time. toLong ( ) ) ) {
when ( selected Time ) {
morning -> binding . shortcuts . timeGroup . check ( R . id . morning _button )
afternoon -> binding . shortcuts . timeGroup . check ( R . id . afternoon _button )
evening -> binding . shortcuts . timeGroup . check ( R . id . evening _button )
night -> binding . shortcuts . timeGroup . check ( R . id . night _button )
else -> {
customTime = selected !! . millisOfDay
customTime = selected Time
binding . shortcuts . timeGroup . check ( R . id . current _time _selection )
binding . shortcuts . currentTimeSelection . visibility = View . VISIBLE
binding . shortcuts . currentTimeSelection . text = DateUtilities . getTimeString ( context , selected )
binding . shortcuts . currentTimeSelection . text = if ( customTime == MULTIPLE _TIMES ) {
requireContext ( ) . getString ( R . string . date _picker _multiple )
} else {
DateUtilities . getTimeString ( context , today . withMillisOfDay ( selectedTime ) )
}
}
}
} else {
binding . shortcuts . timeGroup . check ( R . id . no _time )
}
if ( selected != null ) {
binding . calendarView . setDate ( selected !! . millis , true , true )
if ( selected Day > 0 ) {
binding . calendarView . setDate ( selected Day , true , true )
}
}
@OnClick ( R . id . no _date _button )
fun clearDate ( ) = returnDate ( 0 )
fun clearDate ( ) = returnDate ( day = 0 , time = 0 )
@OnClick ( R . id . no _time )
fun clearTime ( ) = returnDate ( selected?. startOfDay ( ) ?. millis ?: 0 )
fun clearTime ( ) = returnDate ( time = 0 )
@OnClick ( R . id . today _button )
fun setToday ( ) = returnDate ( today. withMillisOfDay ( selected ?. millisOfDay ?: 0 ) )
fun setToday ( ) = returnDate ( day = today . startOfDay ( ) . millis )
@OnClick ( R . id . tomorrow _button )
fun setTomorrow ( ) = returnDate ( tomorrow. withMillisOfDay ( selected ?. millisOfDay ?: 0 ) )
fun setTomorrow ( ) = returnDate ( day = tomorrow . startOfDay ( ) . millis )
@OnClick ( R . id . next _week _button )
fun setNextWeek ( ) = returnDate ( nextWeek. withMillisOfDay ( selected ?. millisOfDay ?: 0 ) )
fun setNextWeek ( ) = returnDate ( day = nextWeek . startOfDay ( ) . millis )
@OnClick ( R . id . morning _button )
fun setMorning ( ) = returnSelectedTime ( morning )
@ -203,33 +220,35 @@ class DateTimePicker : BottomSheetDialogFragment() {
fun setNight ( ) = returnSelectedTime ( night )
@OnClick ( R . id . current _date _selection )
fun currentDate ( ) = returnDate ( customDate)
fun currentDate ( ) = returnDate ( day = customDate)
@OnClick ( R . id . current _time _selection )
fun currentTime ( ) = returnSelectedTime ( customTime )
@OnClick ( R . id . pick _time _button )
fun pickTime ( ) {
newTimePicker ( this , REQUEST _TIME , selected ?. millis ?: today . noon ( ) . millis )
val time = if ( Task . hasDueTime ( today . withMillisOfDay ( selectedTime ) . millis ) ) {
selectedTime
} else {
today . noon ( ) . millisOfDay
}
newTimePicker ( this , REQUEST _TIME , today . withMillisOfDay ( time ) . millis )
. show ( parentFragmentManager , FRAG _TAG _TIME _PICKER )
}
private fun returnSelectedTime ( millisOfDay : Int ) {
if ( selected == null ) {
selected = today . withMillisOfDay ( millisOfDay )
if ( selected !! . isBeforeNow ) {
selected = selected !! . plusDays ( 1 )
}
} else {
selected = selected !! . withMillisOfDay ( millisOfDay )
val day = when {
selectedDay == MULTIPLE _DAYS -> MULTIPLE _DAYS
selectedDay > 0 -> selectedDay
today . withMillisOfDay ( millisOfDay ) . isAfterNow -> today . millis
else -> today . plusDays ( 1 ) . millis
}
returnDate ( selected!! . millis )
returnDate ( day = day , time = millisOfDay )
}
private fun returnDate ( dt : DateTime ? = selected ) = returnDate ( dt ?. millis ?: 0 )
private fun returnDate ( date : Long ? = selected ?. millis ) {
selected = if ( date == null || date <= 0 ) null else DateTime ( date )
private fun returnDate ( day : Long = selectedDay , time : Int = selectedTime ) {
selectedDay = day
selectedTime = time
if ( closeAutomatically ( ) ) {
sendSelected ( )
} else {
@ -237,21 +256,37 @@ class DateTimePicker : BottomSheetDialogFragment() {
}
}
private val taskIds : LongArray
get ( ) = arguments ?. getLongArray ( EXTRA _TASKS ) ?: longArrayOf ( )
private fun sendSelected ( ) {
val taskId = arguments ?. getLong ( EXTRA _TASK ) ?: 0
val dueDate = selected ?. millis ?: 0
if ( dueDate != arguments ?. getLong ( EXTRA _TIMESTAMP ) ) {
if ( taskId > 0 ) {
if ( selectedDay != arguments ?. getLong ( EXTRA _DAY )
|| selectedTime != arguments ?. getInt ( EXTRA _TIME ) ) {
if ( taskIds . isEmpty ( ) ) {
val intent = Intent ( )
intent . putExtra ( EXTRA _TIMESTAMP , when {
selectedDay == NO _DAY -> 0
selectedTime == NO _TIME -> selectedDay
else -> selectedDay . toDateTime ( ) . withMillisOfDay ( selectedTime ) . millis
} )
targetFragment ?. onActivityResult ( targetRequestCode , RESULT _OK , intent )
} else {
lifecycleScope . launch ( NonCancellable ) {
taskIds . forEach { taskId ->
taskDao . fetch ( taskId ) ?. let {
it . setDueDateAdjustingHideUntil ( dueDate )
it . setDueDateAdjustingHideUntil ( when {
selectedDay == MULTIPLE _DAYS ->
it . dueDate . toDateTime ( ) . withMillisOfDay ( selectedTime ) . millis
selectedDay == NO _DAY -> 0L
selectedTime == MULTIPLE _TIMES ->
selectedDay . toDateTime ( ) . withMillisOfDay ( it . dueDate . millisOfDay ( ) ) . millis
selectedTime == NO _TIME -> selectedDay
else -> selectedDay . toDateTime ( ) . withMillisOfDay ( selectedTime ) . millis
} )
taskDao . save ( it )
}
}
} else {
val intent = Intent ( )
intent . putExtra ( EXTRA _TIMESTAMP , dueDate )
targetFragment ?. onActivityResult ( targetRequestCode , RESULT _OK , intent )
}
}
}
dismiss ( )
@ -268,7 +303,8 @@ class DateTimePicker : BottomSheetDialogFragment() {
override fun onSaveInstanceState ( outState : Bundle ) {
super . onSaveInstanceState ( outState )
outState . putSerializable ( EXTRA _SELECTED , selected ?. millis )
outState . putLong ( EXTRA _DAY , selectedDay )
outState . putInt ( EXTRA _TIME , selectedTime )
}
override fun onCreateDialog ( savedInstanceState : Bundle ? ) : Dialog {