From 611ab0f100acabe5e6374a7aa5fa7a769762080b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 7 Mar 2020 20:03:47 +0100 Subject: [PATCH] [Events/Manual] Create custom views for dropdowns. Simplify dialog code. Fix wrong start time saving. --- .../ui/dialogs/event/EventManualDialog.kt | 418 ++++-------------- .../ui/modules/views/DateDropdown.kt | 240 ++++++++++ .../ui/modules/views/SubjectDropdown.kt | 153 +++++++ .../ui/modules/views/TeacherDropdown.kt | 115 +++++ .../ui/modules/views/TeamDropdown.kt | 122 +++++ .../ui/modules/views/TimeDropdown.kt | 214 +++++++++ .../edziennik/utils/TextInputDropDown.kt | 4 +- .../res/layout/dialog_event_manual_v2.xml | 10 +- .../main/res/layout/dialog_lesson_details.xml | 7 +- app/src/main/res/values/strings.xml | 4 + 10 files changed, 953 insertions(+), 334 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/DateDropdown.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/SubjectDropdown.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/TeacherDropdown.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/TeamDropdown.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/views/TimeDropdown.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt index 20e03b75..0e6ec86f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/event/EventManualDialog.kt @@ -12,8 +12,6 @@ import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog.BUTTON_NEUTRAL import androidx.appcompat.app.AlertDialog.BUTTON_POSITIVE import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.Observer -import com.google.android.material.datepicker.MaterialDatePicker import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.jaredrummler.android.colorpicker.ColorPickerDialog import com.jaredrummler.android.colorpicker.ColorPickerDialogListener @@ -21,15 +19,17 @@ import kotlinx.coroutines.* import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi -import pl.szczodrzynski.edziennik.data.db.entity.* +import pl.szczodrzynski.edziennik.data.db.entity.Event +import pl.szczodrzynski.edziennik.data.db.entity.EventType +import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.LessonFull import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding +import pl.szczodrzynski.edziennik.ui.modules.views.TimeDropdown.Companion.DISPLAY_LESSONS import pl.szczodrzynski.edziennik.utils.Anim import pl.szczodrzynski.edziennik.utils.TextInputDropDown import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time -import pl.szczodrzynski.edziennik.utils.models.Week import kotlin.coroutines.CoroutineContext class EventManualDialog( @@ -56,7 +56,6 @@ class EventManualDialog( private lateinit var b: DialogEventManualV2Binding private lateinit var dialog: AlertDialog - private lateinit var event: Event private var customColor: Int? = null private val editingShared = editingEvent?.sharedBy != null private val editingOwn = editingEvent?.sharedBy == "self" @@ -104,12 +103,6 @@ class EventManualDialog( show() } - event = editingEvent?.clone() ?: Event().also { event -> - event.profileId = profileId - defaultType?.let { - event.type = it - } - } b.shareSwitch.isChecked = editingShared b.shareSwitch.isEnabled = !editingShared || (editingShared && editingOwn) @@ -144,41 +137,85 @@ class EventManualDialog( else -> R.string.dialog_event_manual_share_first_notice } - b.shareDetails.setText(text, event.sharedByName ?: "") + b.shareDetails.setText(text, editingEvent?.sharedByName ?: "") } private fun loadLists() { launch { + with (b.dateDropdown) { + db = app.db + profileId = App.profileId + showWeekDays = false + showDays = true + showOtherDate = true + defaultLesson?.let { + nextLessonSubjectId = it.displaySubjectId + nextLessonSubjectName = it.displaySubjectName + nextLessonTeamId = it.displayTeamId + } + loadItems() + selectDefault(editingEvent?.eventDate) + selectDefault(defaultLesson?.displayDate ?: defaultDate) + onDateSelected = { date, lesson -> + b.timeDropdown.deselect() + b.timeDropdown.lessonsDate = date + this@EventManualDialog.launch { + b.timeDropdown.loadItems() + lesson?.displayStartTime?.let { b.timeDropdown.selectTime(it) } + lesson?.displaySubjectId?.let { b.subjectDropdown.selectSubject(it) } ?: b.subjectDropdown.deselect() + lesson?.displayTeacherId?.let { b.teacherDropdown.selectTeacher(it) } ?: b.teacherDropdown.deselect() + lesson?.displayTeamId?.let { b.teamDropdown.selectTeam(it) } ?: b.teamDropdown.selectTeamClass() + } + } + } + + with (b.timeDropdown) { + db = app.db + profileId = App.profileId + showAllDay = true + showCustomTime = true + lessonsDate = b.dateDropdown.getSelected() as? Date ?: Date.getToday() + displayMode = DISPLAY_LESSONS + loadItems() + selectDefault(editingEvent?.startTime) + selectDefault(defaultLesson?.displayStartTime ?: defaultTime) + onLessonSelected = { lesson -> + lesson.displaySubjectId?.let { b.subjectDropdown.selectSubject(it) } ?: b.subjectDropdown.deselect() + lesson.displayTeacherId?.let { b.teacherDropdown.selectTeacher(it) } ?: b.teacherDropdown.deselect() + lesson.displayTeamId?.let { b.teamDropdown.selectTeam(it) } ?: b.teamDropdown.selectTeamClass() + } + } + + with (b.teamDropdown) { + db = app.db + profileId = App.profileId + showNoTeam = true + loadItems() + selectTeamClass() + selectDefault(editingEvent?.teamId) + selectDefault(defaultLesson?.displayTeamId) + } + + with (b.subjectDropdown) { + db = app.db + profileId = App.profileId + showNoSubject = true + showCustomSubject = false + loadItems() + selectDefault(editingEvent?.subjectId) + selectDefault(defaultLesson?.displaySubjectId) + } + + with (b.teacherDropdown) { + db = app.db + profileId = App.profileId + showNoTeacher = true + loadItems() + selectDefault(editingEvent?.teacherId) + selectDefault(defaultLesson?.displayTeacherId) + } + + val deferred = async(Dispatchers.Default) { - // get the team list - val teams = app.db.teamDao().getAllNow(profileId) - b.teamDropdown.clear() - b.teamDropdown += TextInputDropDown.Item( - -1, - activity.getString(R.string.dialog_event_manual_no_team), - "" - ) - b.teamDropdown += teams.map { TextInputDropDown.Item(it.id, it.name, tag = it) } - - // get the subject list - val subjects = app.db.subjectDao().getAllNow(profileId) - b.subjectDropdown.clear() - b.subjectDropdown += TextInputDropDown.Item( - -1, - activity.getString(R.string.dialog_event_manual_no_subject), - "" - ) - b.subjectDropdown += subjects.map { TextInputDropDown.Item(it.id, it.longName, tag = it) } - - // get the teacher list - val teachers = app.db.teacherDao().getAllNow(profileId) - b.teacherDropdown.clear() - b.teacherDropdown += TextInputDropDown.Item( - -1, - activity.getString(R.string.dialog_event_manual_no_teacher), - "" - ) - b.teacherDropdown += teachers.map { TextInputDropDown.Item(it.id, it.fullName, tag = it) } - // get the event type list val eventTypes = app.db.eventTypeDao().getAllNow(profileId) b.typeDropdown.clear() @@ -186,13 +223,10 @@ class EventManualDialog( } deferred.await() - b.teamDropdown.isEnabled = true - b.subjectDropdown.isEnabled = true - b.teacherDropdown.isEnabled = true b.typeDropdown.isEnabled = true defaultType?.let { - b.typeDropdown.select(it.toLong()) + b.typeDropdown.select(it) } b.typeDropdown.selected?.let { item -> @@ -201,9 +235,6 @@ class EventManualDialog( // copy IDs from event being edited editingEvent?.let { - b.teamDropdown.select(it.teamId) - b.subjectDropdown.select(it.subjectId) - b.teacherDropdown.select(it.teacherId) b.topic.setText(it.topic) b.typeDropdown.select(it.type.toLong())?.let { item -> customColor = (item.tag as EventType).color @@ -215,8 +246,6 @@ class EventManualDialog( // copy IDs from the LessonFull defaultLesson?.let { b.teamDropdown.select(it.displayTeamId) - b.subjectDropdown.select(it.displaySubjectId) - b.teacherDropdown.select(it.displayTeacherId) } b.typeDropdown.setOnChangeListener { @@ -244,278 +273,8 @@ class EventManualDialog( }) colorPickerDialog.show(activity.fragmentManager, "color-picker-dialog") } - - loadDates() }} - private fun loadDates() { launch { - val date = Date.getToday() - val today = date.value - var weekDay = date.weekDay - - val deferred = async(Dispatchers.Default) { - val dates = mutableListOf() - // item choosing the next lesson of specific subject - b.subjectDropdown.selected?.let { - if (it.tag is Subject) { - dates += TextInputDropDown.Item( - -it.id, - activity.getString(R.string.dialog_event_manual_date_next_lesson, it.tag.longName) - ) - } - } - - // TODAY - dates += TextInputDropDown.Item( - date.value.toLong(), - activity.getString(R.string.dialog_event_manual_date_today, date.formattedString), - tag = date.clone() - ) - - // TOMORROW - if (weekDay < 4) { - date.stepForward(0, 0, 1) - weekDay++ - dates += TextInputDropDown.Item( - date.value.toLong(), - activity.getString(R.string.dialog_event_manual_date_tomorrow, date.formattedString), - tag = date.clone() - ) - } - // REMAINING SCHOOL DAYS OF THE CURRENT WEEK - while (weekDay < 4) { - date.stepForward(0, 0, 1) // step one day forward - weekDay++ - dates += TextInputDropDown.Item( - date.value.toLong(), - activity.getString(R.string.dialog_event_manual_date_this_week, Week.getFullDayName(weekDay), date.formattedString), - tag = date.clone() - ) - } - // go to next week Monday - date.stepForward(0, 0, -weekDay + 7) - weekDay = 0 - // ALL SCHOOL DAYS OF THE NEXT WEEK - while (weekDay < 4) { - dates += TextInputDropDown.Item( - date.value.toLong(), - activity.getString(R.string.dialog_event_manual_date_next_week, Week.getFullDayName(weekDay), date.formattedString), - tag = date.clone() - ) - date.stepForward(0, 0, 1) // step one day forward - weekDay++ - } - dates += TextInputDropDown.Item( - -1L, - activity.getString(R.string.dialog_event_manual_date_other) - ) - dates - } - - val dates = deferred.await() - b.dateDropdown.clear().append(dates) - - defaultDate?.let { - event.eventDate = it - if (b.dateDropdown.select(it) == null) - b.dateDropdown.select(TextInputDropDown.Item( - it.value.toLong(), - it.formattedString, - tag = it - )) - } - - editingEvent?.eventDate?.let { - b.dateDropdown.select(TextInputDropDown.Item( - it.value.toLong(), - it.formattedString, - tag = it - )) - } - - defaultLesson?.displayDate?.let { - b.dateDropdown.select(TextInputDropDown.Item( - it.value.toLong(), - it.formattedString, - tag = it - )) - } - - if (b.dateDropdown.selected == null) { - b.dateDropdown.select(today.toLong()) - } - - b.dateDropdown.isEnabled = true - - b.dateDropdown.setOnChangeListener { item -> - when { - // next lesson with specified subject - item.id < -1 -> { - val teamId = defaultLesson?.teamId ?: -1 - val selectedLessonDate = defaultLesson?.date ?: Date.getToday() - - when (teamId) { - -1L -> app.db.timetableDao().getNextWithSubject(profileId, selectedLessonDate, -item.id) - else -> app.db.timetableDao().getNextWithSubjectAndTeam(profileId, selectedLessonDate, -item.id, teamId) - }.observeOnce(activity, Observer { - val lessonDate = it?.displayDate ?: return@Observer - b.dateDropdown.select(TextInputDropDown.Item( - lessonDate.value.toLong(), - lessonDate.formattedString, - tag = lessonDate - )) - b.teamDropdown.select(it.displayTeamId) - b.subjectDropdown.select(it.displaySubjectId) - b.teacherDropdown.select(it.displayTeacherId) - defaultLoaded = false - loadHours(it.displayStartTime) - }) - return@setOnChangeListener false - } - // custom date - item.id == -1L -> { - MaterialDatePicker.Builder - .datePicker() - .setSelection((b.dateDropdown.selectedId?.let { Date.fromValue(it.toInt()) } - ?: Date.getToday()).inMillis) - .build() - .apply { - addOnPositiveButtonClickListener { - val dateSelected = Date.fromMillis(it) - b.dateDropdown.select(TextInputDropDown.Item( - dateSelected.value.toLong(), - dateSelected.formattedString, - tag = dateSelected - )) - loadHours() - } - show(this@EventManualDialog.activity.supportFragmentManager, "MaterialDatePicker") - } - - return@setOnChangeListener false - } - // a specific date - else -> { - b.dateDropdown.select(item) - loadHours() - } - } - return@setOnChangeListener true - } - - loadHours() - }} - - private fun loadHours(defaultHour: Time? = null) { - b.timeDropdown.isEnabled = false - // get the selected date - val date = b.dateDropdown.selectedId?.let { Date.fromValue(it.toInt()) } ?: return - // get all lessons for selected date - app.db.timetableDao().getForDate(profileId, date).observeOnce(activity, Observer { lessons -> - val hours = mutableListOf() - // add All day time choice - hours += TextInputDropDown.Item( - 0L, - activity.getString(R.string.dialog_event_manual_all_day) - ) - lessons.forEach { lesson -> - if (lesson.type == Lesson.TYPE_NO_LESSONS) { - // indicate there are no lessons this day - hours += TextInputDropDown.Item( - -2L, - activity.getString(R.string.dialog_event_manual_no_lessons) - ) - return@forEach - } - // create the lesson caption - val text = listOfNotEmpty( - lesson.displayStartTime?.stringHM ?: "", - lesson.displaySubjectName?.let { - when { - lesson.type == Lesson.TYPE_CANCELLED - || lesson.type == Lesson.TYPE_SHIFTED_SOURCE -> it.asStrikethroughSpannable() - lesson.type != Lesson.TYPE_NORMAL -> it.asItalicSpannable() - else -> it - } - } ?: "" - ) - // add an item with LessonFull as the tag - hours += TextInputDropDown.Item( - lesson.displayStartTime?.value?.toLong() ?: -1, - text.concat(" "), - tag = lesson - ) - } - b.timeDropdown.clear().append(hours) - - if (defaultLoaded) { - b.timeDropdown.deselect() - // select the TEAM_CLASS if possible - b.teamDropdown.items.singleOrNull { - it.tag is Team && it.tag.type == Team.TYPE_CLASS - }?.let { - b.teamDropdown.select(it) - } ?: b.teamDropdown.deselect() - - // clear subject, teacher selection - b.subjectDropdown.deselect() - b.teacherDropdown.deselect() - } - else { - val setTime: (Time) -> Unit = { - event.startTime = it - if (b.timeDropdown.select(it) == null) - b.timeDropdown.select(TextInputDropDown.Item( - it.value.toLong(), - it.stringHM, - tag = it - )) - } - defaultTime?.let(setTime) - editingEvent?.startTime?.let(setTime) - defaultLesson?.displayStartTime?.let(setTime) - defaultHour?.let(setTime) - } - defaultLoaded = true - b.timeDropdown.isEnabled = true - - // attach a listener to time dropdown - b.timeDropdown.setOnChangeListener { item -> - when (item.id) { - // no lessons this day - -2L -> { - b.timeDropdown.deselect() - return@setOnChangeListener false - } - - // custom start hour - -1L -> return@setOnChangeListener false - - // selected a specific lesson - else -> { - if (item.tag is LessonFull) { - // update team, subject, teacher dropdowns, - // using the LessonFull from item tag - b.teamDropdown.deselect() - b.subjectDropdown.deselect() - b.teacherDropdown.deselect() - item.tag.displayTeamId?.let { - b.teamDropdown.select(it) - } - item.tag.displaySubjectId?.let { - b.subjectDropdown.select(it) - } - item.tag.displayTeacherId?.let { - b.teacherDropdown.select(it) - } - } - } - } - return@setOnChangeListener true - } - }) - } - private fun showRemoveEventDialog() { val shareNotice = when { editingShared && editingOwn -> "\n\n"+activity.getString(R.string.dialog_event_manual_remove_shared_self) @@ -541,22 +300,29 @@ class EventManualDialog( } private fun saveEvent() { - val date = b.dateDropdown.selected?.tag.instanceOfOrNull() - val startTime = b.timeDropdown.selected?.tag.instanceOfOrNull