Created
August 5, 2020 04:36
-
-
Save necatisozer/8fe20171d96d881f71c5b93dfd7b0ec8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package tr.com.bisu.app.core.presentation.base.extension | |
import android.content.BroadcastReceiver | |
import android.content.Context | |
import android.content.Intent | |
import android.content.IntentFilter | |
import android.os.Build | |
import android.widget.DatePicker | |
import android.widget.TimePicker | |
import androidx.annotation.CheckResult | |
import com.afollestad.materialdialogs.MaterialDialog | |
import com.afollestad.materialdialogs.WhichButton.POSITIVE | |
import com.afollestad.materialdialogs.actions.setActionButtonEnabled | |
import com.afollestad.materialdialogs.callbacks.onDismiss | |
import com.afollestad.materialdialogs.customview.customView | |
import com.afollestad.materialdialogs.utils.MDUtil.isLandscape | |
import tr.com.bisu.app.core.presentation.R | |
import java.time.LocalDateTime | |
import java.time.ZoneId | |
import java.util.* | |
typealias DateTimeCallback = ((dialog: MaterialDialog, datetime: LocalDateTime) -> Unit)? | |
fun MaterialDialog.dateTimePickerSpinner( | |
minDateTime: LocalDateTime? = null, | |
maxDateTime: LocalDateTime? = null, | |
currentDateTime: LocalDateTime = LocalDateTime.now(), | |
requireFutureDateTime: Boolean = false, | |
show24HoursView: Boolean = false, | |
dateTimeCallback: DateTimeCallback = null | |
): MaterialDialog { | |
customView( | |
R.layout.view_date_time_picker, | |
dialogWrapContent = windowContext.isLandscape() | |
) | |
getDatePicker().apply { | |
minDateTime?.let { minDate = it.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() } | |
maxDateTime?.let { maxDate = it.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() } | |
init( | |
currentDateTime.year, | |
currentDateTime.monthValue - 1, | |
currentDateTime.dayOfMonth | |
) { view, year, monthOfYear, dayOfMonth -> | |
val futureTime = isFutureTime(getDatePicker(), getTimePicker()) | |
setActionButtonEnabled(POSITIVE, !requireFutureDateTime || futureTime) | |
} | |
} | |
getTimePicker().apply { | |
setIs24HourView(show24HoursView) | |
hour(currentDateTime.hour) | |
minute(currentDateTime.minute) | |
setOnTimeChangedListener { _, _, _ -> | |
val isFutureTime = isFutureTime(getDatePicker(), this) | |
setActionButtonEnabled(POSITIVE, !requireFutureDateTime || isFutureTime) | |
} | |
} | |
positiveButton(android.R.string.ok) { | |
val selectedTime = toDateTime(getDatePicker(), getTimePicker()) | |
dateTimeCallback?.invoke(it, selectedTime) | |
} | |
negativeButton(android.R.string.cancel) | |
if (requireFutureDateTime) { | |
val changeListener = TimeChangeListener(windowContext, getTimePicker()) { | |
val isFutureTime = isFutureTime(getDatePicker(), it) | |
setActionButtonEnabled(POSITIVE, !requireFutureDateTime || isFutureTime) | |
} | |
onDismiss { changeListener.dispose() } | |
} | |
return this | |
} | |
@CheckResult | |
fun MaterialDialog.selectedDateTime(): LocalDateTime { | |
return toDateTime(getDatePicker(), getTimePicker()) | |
} | |
/**************************************************************************************************/ | |
internal fun TimePicker.hour(): Int = if (isNougat()) hour else currentHour | |
internal fun TimePicker.minute(): Int = if (isNougat()) minute else currentMinute | |
internal fun TimePicker.hour(value: Int) { | |
if (isNougat()) hour = value else currentHour = value | |
} | |
internal fun TimePicker.minute(value: Int) { | |
if (isNougat()) minute = value else currentMinute = value | |
} | |
internal fun MaterialDialog.getDatePicker() = findViewById<DatePicker>(R.id.datePicker) | |
internal fun MaterialDialog.getTimePicker() = findViewById<TimePicker>(R.id.timePicker) | |
private fun isNougat() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N | |
/**************************************************************************************************/ | |
internal fun isFutureTime(datePicker: DatePicker, timePicker: TimePicker): Boolean { | |
val now = LocalDateTime.now() | |
val dateTime = toDateTime(datePicker, timePicker) | |
return dateTime >= now | |
} | |
internal fun TimePicker.isFutureTime(): Boolean { | |
val now = LocalDateTime.now() | |
return toDateTime() >= now | |
} | |
internal fun DatePicker.isFutureDate(): Boolean { | |
val now = LocalDateTime.now() | |
return toDateTime() >= now | |
} | |
internal fun DatePicker.toDateTime(): LocalDateTime { | |
return LocalDateTime.now() | |
.withYear(year) | |
.withMonth(month + 1) | |
.withDayOfMonth(dayOfMonth) | |
} | |
internal fun TimePicker.toDateTime(): LocalDateTime { | |
return LocalDateTime.now() | |
.withHour(hour()) | |
.withMinute(minute()) | |
} | |
internal fun toDateTime(datePicker: DatePicker, timePicker: TimePicker): LocalDateTime { | |
return LocalDateTime.of( | |
datePicker.year, | |
datePicker.month + 1, | |
datePicker.dayOfMonth, | |
timePicker.hour(), | |
timePicker.minute() | |
) | |
} | |
/**************************************************************************************************/ | |
internal class TimeChangeListener<T : Any>( | |
private var context: Context?, | |
private val argument: T?, | |
private var onChange: ((arg: T) -> Unit)? = null | |
) { | |
private var lastHour: Int = -1 | |
private var lastMinute: Int = -1 | |
private val receiver = object : BroadcastReceiver() { | |
override fun onReceive(context: Context?, intent: Intent?) { | |
val now = Calendar.getInstance() | |
val newHour = now.get(Calendar.HOUR_OF_DAY) | |
val newMinute = now.get(Calendar.MINUTE) | |
if (argument != null && (lastHour != newHour || lastMinute != newMinute)) { | |
onChange?.invoke(argument) | |
lastHour = newHour | |
lastMinute = newMinute | |
} | |
} | |
} | |
init { | |
requireNotNull(context) | |
requireNotNull(argument) | |
requireNotNull(onChange) | |
val filter = IntentFilter().apply { | |
addAction(Intent.ACTION_TIME_TICK) | |
addAction(Intent.ACTION_TIMEZONE_CHANGED) | |
addAction(Intent.ACTION_TIME_CHANGED) | |
} | |
context!!.registerReceiver(receiver, filter) | |
} | |
fun dispose() { | |
context?.unregisterReceiver(receiver) | |
context = null | |
onChange = null | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment