[Event] Add new manual event dialog

This commit is contained in:
Kuba Szczodrzyński 2019-11-12 23:35:47 +01:00
parent 472e768369
commit 16102de619
12 changed files with 780 additions and 67 deletions

View File

@ -4,11 +4,13 @@ import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.Typeface
import android.os.Build
import android.os.Bundle
import android.text.*
import android.text.style.ForegroundColorSpan
import android.text.style.StrikethroughSpan
import android.text.style.StyleSpan
import android.util.LongSparseArray
import android.util.SparseArray
import android.view.View
@ -16,6 +18,9 @@ import android.widget.TextView
import androidx.annotation.StringRes
import androidx.core.app.ActivityCompat
import androidx.core.util.forEach
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
@ -344,6 +349,11 @@ fun CharSequence?.asStrikethroughSpannable(): Spannable {
spannable.setSpan(StrikethroughSpan(), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
return spannable
}
fun CharSequence?.asItalicSpannable(): Spannable {
val spannable = SpannableString(this)
spannable.setSpan(StyleSpan(Typeface.ITALIC), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
return spannable
}
/**
* Returns a new read-only list only of those given elements, that are not empty.
@ -416,4 +426,13 @@ inline fun <T : View> T.onClick(crossinline onClickListener: (v: T) -> Unit) {
setOnClickListener { v: View ->
onClickListener(v as T)
}
}
fun <T> LiveData<T>.observeOnce(lifecycleOwner: LifecycleOwner, observer: Observer<T>) {
observe(lifecycleOwner, object : Observer<T> {
override fun onChanged(t: T?) {
observer.onChanged(t)
removeObserver(this)
}
})
}

View File

@ -5,6 +5,7 @@ import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.Index;
import pl.szczodrzynski.edziennik.utils.models.Date;
import pl.szczodrzynski.edziennik.utils.models.Time;
@ -85,6 +86,23 @@ public class Event {
this.teamId = teamId;
}
@Override
public Event clone() throws CloneNotSupportedException {
return new Event(
profileId,
id,
eventDate.clone(),
startTime == null ? null : startTime.clone(),
topic,
color,
type,
addedManually,
subjectId,
teacherId,
teamId
);
}
@Override
public String toString() {
return "Event{" +

View File

@ -62,6 +62,25 @@ class LessonFull(profileId: Int, id: Long) : Lesson(profileId, id) {
return classroom ?: oldClassroom
}
val displayTeamId: Long?
get() {
if (type == TYPE_SHIFTED_SOURCE)
return oldTeamId
return teamId ?: oldTeamId
}
val displaySubjectId: Long?
get() {
if (type == TYPE_SHIFTED_SOURCE)
return oldSubjectId
return subjectId ?: oldSubjectId
}
val displayTeacherId: Long?
get() {
if (type == TYPE_SHIFTED_SOURCE)
return oldTeacherId
return teacherId ?: oldTeacherId
}
// metadata
var seen: Boolean = false
var notified: Boolean = false

View File

@ -43,7 +43,31 @@ interface TimetableDao {
LEFT JOIN teams AS oldG ON timetable.profileId = oldG.profileId AND timetable.oldTeamId = oldG.teamId
LEFT JOIN metadata ON id = thingId AND thingType = ${Metadata.TYPE_LESSON_CHANGE} AND metadata.profileId = timetable.profileId
WHERE timetable.profileId = :profileId AND (type != 3 AND date = :date) OR ((type = 3 OR type = 1) AND oldDate = :date)
ORDER BY type
ORDER BY id, type
""")
fun getForDate(profileId: Int, date: Date) : LiveData<List<LessonFull>>
@Query("""
SELECT
timetable.*,
subjects.subjectLongName AS subjectName,
teachers.teacherName ||" "|| teachers.teacherSurname AS teacherName,
teams.teamName AS teamName,
oldS.subjectLongName AS oldSubjectName,
oldT.teacherName ||" "|| oldT.teacherSurname AS oldTeacherName,
oldG.teamName AS oldTeamName,
metadata.seen, metadata.notified, metadata.addedDate
FROM timetable
LEFT JOIN subjects USING(profileId, subjectId)
LEFT JOIN teachers USING(profileId, teacherId)
LEFT JOIN teams USING(profileId, teamId)
LEFT JOIN subjects AS oldS ON timetable.profileId = oldS.profileId AND timetable.oldSubjectId = oldS.subjectId
LEFT JOIN teachers AS oldT ON timetable.profileId = oldT.profileId AND timetable.oldTeacherId = oldT.teacherId
LEFT JOIN teams AS oldG ON timetable.profileId = oldG.profileId AND timetable.oldTeamId = oldG.teamId
LEFT JOIN metadata ON id = thingId AND thingType = ${Metadata.TYPE_LESSON_CHANGE} AND metadata.profileId = timetable.profileId
WHERE timetable.profileId = :profileId AND ((type != 3 AND date > :today) OR ((type = 3 OR type = 1) AND oldDate > :today)) AND timetable.subjectId = :subjectId
ORDER BY id, type
LIMIT 1
""")
fun getNextWithSubject(profileId: Int, today: Date, subjectId: Long) : LiveData<LessonFull>
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-12.
*/
package pl.szczodrzynski.edziennik.ui.dialogs.event
import android.app.Activity
import androidx.appcompat.app.AlertDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time
class EventAddTypeDialog(
val activity: Activity,
val profileId: Int,
val date: Date? = null,
val time: Time? = null
) {
companion object {
private const val TAG = "EventAddTypeDialog"
}
private lateinit var dialog: AlertDialog
init { run {
dialog = MaterialAlertDialogBuilder(activity)
.setItems(R.array.main_menu_add_options) { dialog, which ->
dialog.dismiss()
EventManualDialog(activity, profileId)
.show(
activity.application as App,
null,
date,
time,
when (which) {
1 -> EventManualDialog.DIALOG_HOMEWORK
else -> EventManualDialog.DIALOG_EVENT
}
)
}
.setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
.show()
}}
}

View File

@ -0,0 +1,379 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-12.
*/
package pl.szczodrzynski.edziennik.ui.dialogs.event
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.*
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
import pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull
import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding
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 EventManualV2Dialog(
val activity: AppCompatActivity,
val profileId: Int,
val defaultLesson: LessonFull? = null,
val defaultDate: Date? = null,
val defaultTime: Time? = null,
val defaultType: Int? = null,
val editingEvent: Event? = null
) : CoroutineScope {
companion object {
private const val TAG = "EventManualDialog"
}
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
private val app by lazy { activity.application as App }
private lateinit var b: DialogEventManualV2Binding
private lateinit var dialog: AlertDialog
private lateinit var event: Event
private var defaultLoaded = false
init { run {
job = Job()
b = DialogEventManualV2Binding.inflate(activity.layoutInflater)
dialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.dialog_event_manual_title)
.setView(b.root)
.setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
.setPositiveButton(R.string.save) { _, _ -> saveEvent() }
.show()
event = editingEvent?.clone() ?: Event().also { event ->
event.profileId = profileId
/*defaultDate?.let {
event.eventDate = it
b.date = it
}
defaultTime?.let {
event.startTime = it
b.time = it
}
defaultType?.let {
event.type = it
}*/
}
loadLists()
}}
private fun loadLists() { launch {
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) }
}
deferred.await()
b.teamDropdown.isEnabled = true
b.subjectDropdown.isEnabled = true
b.teacherDropdown.isEnabled = true
// copy IDs from event being edited
editingEvent?.let {
b.teamDropdown.select(it.teamId)
b.subjectDropdown.select(it.subjectId)
b.teacherDropdown.select(it.teacherId)
}
// copy IDs from the LessonFull
defaultLesson?.let {
b.teamDropdown.select(it.displayTeamId)
b.subjectDropdown.select(it.displaySubjectId)
b.teacherDropdown.select(it.displayTeacherId)
}
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<TextInputDropDown.Item>()
// 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)
editingEvent?.let {
b.dateDropdown.select(it.eventDate.value.toLong())
}
defaultLesson?.let {
b.dateDropdown.select(it.displayDate?.value?.toLong())
}
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 -> {
app.db.timetableDao().getNextWithSubject(profileId, Date.getToday(), -item.id).observeOnce(activity, Observer {
val lessonDate = it?.displayDate ?: return@Observer
b.dateDropdown.selected = TextInputDropDown.Item(
lessonDate.value.toLong(),
lessonDate.formattedString,
tag = lessonDate
)
// TODO load correct hour when selecting next lesson
b.dateDropdown.updateText()
it.let {
b.teamDropdown.select(it.displayTeamId)
b.subjectDropdown.select(it.displaySubjectId)
b.teacherDropdown.select(it.displayTeacherId)
}
defaultLoaded = false
loadHours()
})
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.selected = TextInputDropDown.Item(
dateSelected.value.toLong(),
dateSelected.formattedString,
tag = dateSelected
)
b.dateDropdown.updateText()
loadHours()
}
show(this@EventManualV2Dialog.activity.supportFragmentManager, "MaterialDatePicker")
}
return@setOnChangeListener false
}
// a specific date
else -> {
b.dateDropdown.select(item)
loadHours()
}
}
return@setOnChangeListener true
}
loadHours()
}}
private fun loadHours() {
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<TextInputDropDown.Item>()
// 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 -> 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 {
editingEvent?.let {
b.timeDropdown.select(it.startTime?.value?.toLong())
}
defaultLesson?.let {
b.timeDropdown.select(it.displayStartTime?.value?.toLong())
}
}
defaultLoaded = true
b.timeDropdown.isEnabled = true
// attach a listener to time dropdown
b.timeDropdown.setOnChangeListener { item ->
when {
// custom start hour
item.id == -1L -> {
return@setOnChangeListener false
}
// no lessons this day
item.id == -2L -> {
b.timeDropdown.deselect()
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 saveEvent() {
}
}

View File

@ -4,39 +4,43 @@
package pl.szczodrzynski.edziennik.ui.dialogs.timetable
import android.app.Activity
import android.content.Intent
import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
import pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull
import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding
import pl.szczodrzynski.edziennik.setText
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualV2Dialog
import pl.szczodrzynski.edziennik.ui.modules.timetable.v2.TimetableFragment
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Week
class LessonDetailsDialog(
val activity: Activity,
val activity: AppCompatActivity,
val lesson: LessonFull
) {
companion object {
private const val TAG = "LessonDetailsDialog"
}
private lateinit var b: DialogLessonDetailsBinding
private lateinit var dialog: AlertDialog
init { run {
val b = DialogLessonDetailsBinding.inflate(activity.layoutInflater)
val dialog = MaterialAlertDialogBuilder(activity)
b = DialogLessonDetailsBinding.inflate(activity.layoutInflater)
dialog = MaterialAlertDialogBuilder(activity)
.setView(b.root)
.setPositiveButton(R.string.close) { dialog, _ ->
dialog.dismiss()
}
.setNeutralButton(R.string.add) { dialog, _ ->
dialog.dismiss()
MaterialAlertDialogBuilder(activity)
EventManualV2Dialog(activity, lesson.profileId, lesson)
/*MaterialAlertDialogBuilder(activity)
.setItems(R.array.main_menu_add_options) { dialog2, which ->
dialog2.dismiss()
EventManualDialog(activity, lesson.profileId)
@ -53,11 +57,15 @@ class LessonDetailsDialog(
}
.setNegativeButton(R.string.cancel) { dialog2, _ -> dialog2.dismiss() }
.show()
.show()*/
}
.show()
update()
}}
private fun update() {
b.lesson = lesson
val lessonDate = lesson.displayDate ?: return@run
val lessonDate = lesson.displayDate ?: return
b.lessonDate.text = Week.getFullDayName(lessonDate.weekDay) + ", " + lessonDate.formattedString
if (lesson.type >= Lesson.TYPE_SHIFTED_SOURCE) {
@ -135,5 +143,5 @@ class LessonDetailsDialog(
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.teamId != null) {
b.teamName = lesson.teamName
}
}}
}
}

View File

@ -1,55 +0,0 @@
package pl.szczodrzynski.edziennik.utils;
import android.content.Context;
import com.google.android.material.textfield.TextInputEditText;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import androidx.core.graphics.drawable.DrawableCompat;
import pl.szczodrzynski.edziennik.R;
public class TextInputDropDown extends TextInputEditText {
public TextInputDropDown(Context context) {
super(context);
create(context);
}
public TextInputDropDown(Context context, AttributeSet attrs) {
super(context, attrs);
create(context);
}
public TextInputDropDown(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
create(context);
}
public void create(Context context) {
Drawable drawable = context.getResources().getDrawable(R.drawable.dropdown_arrow);
Drawable wrappedDrawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTint(wrappedDrawable, Themes.INSTANCE.getPrimaryTextColor(context));
setCompoundDrawablesWithIntrinsicBounds(null, null, wrappedDrawable, null);
setFocusableInTouchMode(false);
setCursorVisible(false);
setLongClickable(false);
setMaxLines(1);
setInputType(0);
setKeyListener(null);
setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
v.setFocusableInTouchMode(false);
}
});
}
public final void setOnClickListener(OnClickListener onClickListener) {
super.setOnClickListener(v -> {
setFocusableInTouchMode(true);
requestFocus();
onClickListener.onClick(v);
});
}
}

View File

@ -0,0 +1,142 @@
package pl.szczodrzynski.edziennik.utils
import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.PopupMenu
import androidx.core.graphics.drawable.DrawableCompat
import com.google.android.material.textfield.TextInputEditText
import pl.szczodrzynski.edziennik.R
class TextInputDropDown : TextInputEditText {
constructor(context: Context) : super(context) {
create(context)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
create(context)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
create(context)
}
var items = mutableListOf<Item>()
private var onChangeListener: ((item: Item) -> Boolean)? = null
var selected: Item? = null
val selectedId
get() = selected?.id
fun updateText() {
setText(selected?.displayText ?: selected?.text)
}
fun create(context: Context) {
val drawable = context.resources.getDrawable(R.drawable.dropdown_arrow)
val wrappedDrawable = DrawableCompat.wrap(drawable)
DrawableCompat.setTint(wrappedDrawable, Themes.getPrimaryTextColor(context))
setCompoundDrawablesWithIntrinsicBounds(null, null, wrappedDrawable, null)
isFocusableInTouchMode = false
isCursorVisible = false
isLongClickable = false
maxLines = 1
inputType = 0
keyListener = null
setOnFocusChangeListener { v, hasFocus ->
if (!hasFocus) {
v.isFocusableInTouchMode = false
}
}
setOnClickListener {
isFocusableInTouchMode = true
requestFocus()
val popup = PopupMenu(context, this)
items.forEachIndexed { index, item ->
popup.menu.add(0, item.id.toInt(), index, item.text)
}
popup.setOnMenuItemClickListener { menuItem ->
val item = items[menuItem.order]
if (onChangeListener?.invoke(item) != false) {
select(item)
}
clearFocus()
true
}
popup.setOnDismissListener {
clearFocus()
}
popup.show()
}
}
fun select(item: Item) {
selected = item
updateText()
}
fun select(id: Long?) {
items.singleOrNull { it.id == id }?.let { select(it) }
}
fun select(tag: Any?) {
items.singleOrNull { it.tag == tag }?.let { select(it) }
}
fun select(index: Int) {
items.getOrNull(index)?.let { select(it) }
}
fun deselect(): TextInputDropDown {
selected = null
text = null
return this
}
fun clear(): TextInputDropDown {
items.clear()
return this
}
fun append(items: List<Item>): TextInputDropDown {
this.items.addAll(items)
return this
}
fun prepend(items: List<Item>): TextInputDropDown{
this.items.addAll(0, items)
return this
}
operator fun plusAssign(items: Item) {
this.items.add(items)
}
operator fun plusAssign(items: List<Item>) {
this.items.addAll(items)
}
/**
* Set the listener called when other item is selected.
*
* The listener should return true to allow the item to be selected, false otherwise.
*/
fun setOnChangeListener(onChangeListener: ((item: Item) -> Boolean)? = null): TextInputDropDown {
this.onChangeListener = onChangeListener
return this
}
override fun setOnClickListener(onClickListener: OnClickListener?) {
super.setOnClickListener { v ->
isFocusableInTouchMode = true
requestFocus()
onClickListener!!.onClick(v)
}
}
class Item(val id: Long, val text: CharSequence, val displayText: CharSequence? = null, val tag: Any? = null)
}

View File

@ -97,7 +97,8 @@
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:text="@string/dialog_event_manual_share_first_notice"
android:visibility="gone" />
android:visibility="gone"
tools:visibility="visible" />
<LinearLayout
android:layout_width="match_parent"

View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2019-11-12.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:padding="24dp">
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/dialog_event_manual_date">
<pl.szczodrzynski.edziennik.utils.TextInputDropDown
android:id="@+id/dateDropdown"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false"
tools:text="13 listopada"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:hint="@string/dialog_event_manual_time">
<pl.szczodrzynski.edziennik.utils.TextInputDropDown
android:id="@+id/timeDropdown"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false"
tools:text="8:10 - język polski"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:hint="@string/dialog_event_manual_team">
<pl.szczodrzynski.edziennik.utils.TextInputDropDown
android:id="@+id/teamDropdown"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false"
tools:text="2b3T"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:hint="@string/dialog_event_manual_subject">
<pl.szczodrzynski.edziennik.utils.TextInputDropDown
android:id="@+id/subjectDropdown"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false"
tools:text="2b3T"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:hint="@string/dialog_event_manual_teacher">
<pl.szczodrzynski.edziennik.utils.TextInputDropDown
android:id="@+id/teacherDropdown"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false"
tools:text="2b3T"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:hint="@string/dialog_event_manual_topic">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/topic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textLongMessage|textMultiLine|textImeMultiLine"
android:minLines="2"
tools:text="2b3T" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</layout>

View File

@ -1013,4 +1013,13 @@
<string name="dialog_lesson_details_number">Nr lekcji</string>
<string name="dialog_lesson_details_shifted_to">Lekcja przeniesiona na %s</string>
<string name="dialog_lesson_details_shifted_from">Lekcja przeniesiona z %s</string>
<string name="dialog_event_manual_title">Dodaj wpis do terminarza</string>
<string name="dialog_event_manual_time">Lekcja/godzina</string>
<string name="dialog_event_manual_date_next_lesson">nast. lekcja %s</string>
<string name="dialog_event_manual_date_tomorrow">jutro (%s)</string>
<string name="dialog_event_manual_date_this_week">%s (%s)</string>
<string name="dialog_event_manual_date_other">-- inna data --</string>
<string name="dialog_event_manual_date_today">dzisiaj (%s)</string>
<string name="dialog_event_manual_date_next_week">następny %s (%s)</string>
<string name="dialog_event_manual_no_lessons">Nie ma lekcji tego dnia</string>
</resources>