[UI] Add event type colors to type dropdown.

This commit is contained in:
Kuba Szczodrzyński 2021-04-14 11:21:45 +02:00
parent db598af28a
commit 297867cbf3
No known key found for this signature in database
GPG Key ID: 70CB8A85BA1633CB
5 changed files with 181 additions and 49 deletions

View File

@ -4,8 +4,6 @@
package pl.szczodrzynski.edziennik.ui.dialogs.event
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
@ -26,7 +24,6 @@ import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskFinishedEvent
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
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.entity.Profile
import pl.szczodrzynski.edziennik.data.db.full.EventFull
@ -35,7 +32,6 @@ import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding
import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegistrationConfigDialog
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 kotlin.coroutines.CoroutineContext
@ -323,57 +319,41 @@ class EventManualDialog(
selectDefault(defaultLesson?.displayTeacherId)
}
with (b.typeDropdown) {
db = app.db
profileId = this@EventManualDialog.profileId
loadItems()
selectDefault(editingEvent?.type)
selectDefault(defaultType)
val deferred = async(Dispatchers.Default) {
// get the event type list
var eventTypes = app.db.eventTypeDao().getAllNow(profileId)
if (eventTypes.none { it.id in -1L..10L }) {
eventTypes = app.db.eventTypeDao().addDefaultTypes(activity, profileId)
onTypeSelected = {
b.typeColor.background.setTintColor(it.color)
customColor = null
}
}
b.typeDropdown.clear()
b.typeDropdown += eventTypes.map { TextInputDropDown.Item(it.id, it.name, tag = it) }
}
deferred.await()
b.typeDropdown.isEnabled = true
defaultType?.let {
b.typeDropdown.select(it)
}
b.typeDropdown.selected?.let { item ->
customColor = (item.tag as EventType).color
}
// copy IDs from event being edited
// copy data from event being edited
editingEvent?.let {
b.topic.setText(it.topic)
b.typeDropdown.select(it.type)?.let { item ->
customColor = (item.tag as EventType).color
}
if (it.color != null && it.color != -1)
if (it.color != -1)
customColor = it.color
}
b.typeColor.background.setTintColor(
customColor
?: b.typeDropdown.getSelected()?.color
?: Event.COLOR_DEFAULT
)
// copy IDs from the LessonFull
defaultLesson?.let {
b.teamDropdown.select(it.displayTeamId)
}
b.typeDropdown.setOnChangeListener {
b.typeColor.background.colorFilter = PorterDuffColorFilter((it.tag as EventType).color, PorterDuff.Mode.SRC_ATOP)
customColor = null
return@setOnChangeListener true
}
(customColor ?: Event.COLOR_DEFAULT).let {
b.typeColor.background.colorFilter = PorterDuffColorFilter(it, PorterDuff.Mode.SRC_ATOP)
}
b.typeColor.onClick {
val currentColor = (b.typeDropdown.selected?.tag as EventType?)?.color ?: Event.COLOR_DEFAULT
val currentColor = customColor
?: b.typeDropdown.getSelected()?.color
?: Event.COLOR_DEFAULT
val colorPickerDialog = ColorPickerDialog.newBuilder()
.setColor(currentColor)
.create()
@ -381,7 +361,7 @@ class EventManualDialog(
object : ColorPickerDialogListener {
override fun onDialogDismissed(dialogId: Int) {}
override fun onColorSelected(dialogId: Int, color: Int) {
b.typeColor.background.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)
b.typeColor.background.setTintColor(color)
customColor = color
}
})
@ -597,7 +577,12 @@ class EventManualDialog(
}
}
onSaveListener?.invoke(eventObject.withMetadata(metadataObject))
onSaveListener?.invoke(eventObject.withMetadata(metadataObject).also {
it.subjectLongName = b.subjectDropdown.selected?.text?.toString()
it.teacherName = b.teacherDropdown.selected?.text?.toString()
it.teamName = b.teamDropdown.selected?.text?.toString()
it.typeName = b.typeDropdown.selected?.text?.toString()
})
dialog.dismiss()
Toast.makeText(activity, R.string.saved, Toast.LENGTH_SHORT).show()
}

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-4-14.
*/
package pl.szczodrzynski.edziennik.ui.modules.views
import android.content.Context
import android.content.ContextWrapper
import android.util.AttributeSet
import androidx.appcompat.app.AppCompatActivity
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.EventType
import pl.szczodrzynski.edziennik.utils.TextInputDropDown
class EventTypeDropdown : TextInputDropDown {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
private val activity: AppCompatActivity?
get() {
var context: Context? = context ?: return null
if (context is AppCompatActivity) return context
while (context is ContextWrapper) {
if (context is AppCompatActivity)
return context
context = context.baseContext
}
return null
}
lateinit var db: AppDb
var profileId: Int = 0
var onTypeSelected: ((eventType: EventType) -> Unit)? = null
override fun create(context: Context) {
super.create(context)
isEnabled = false
}
suspend fun loadItems() {
val types = withContext(Dispatchers.Default) {
val list = mutableListOf<Item>()
var types = db.eventTypeDao().getAllNow(profileId)
if (types.none { it.id in -1L..10L }) {
types = db.eventTypeDao().addDefaultTypes(context, profileId)
}
list += types.map {
Item(it.id, it.name, tag = it, icon = IconicsDrawable(context).apply {
icon = CommunityMaterial.Icon.cmd_circle
sizeDp = 24
colorInt = it.color
})
}
list
}
clear().append(types)
isEnabled = true
setOnChangeListener {
when (it.tag) {
is EventType -> {
// selected an event type
onTypeSelected?.invoke(it.tag)
true
}
else -> false
}
}
}
/**
* Select an event type by the [typeId].
*/
fun selectType(typeId: Long) {
select(typeId)
}
/**
* Select an event type by the [typeId] **if it's not selected yet**.
*/
fun selectDefault(typeId: Long?) {
if (typeId == null || selected != null)
return
selectType(typeId)
}
/**
* Get the currently selected event type.
* ### Returns:
* - null if no valid type is selected
* - [EventType] - the selected event type
*/
fun getSelected(): EventType? {
return when (selected?.tag) {
is EventType -> selected?.tag as EventType
else -> null
}
}
}

View File

@ -84,6 +84,9 @@ class TeacherDropdown : TextInputDropDown {
}
}
/**
* Select a teacher by the [teacherId].
*/
fun selectTeacher(teacherId: Long) {
if (select(teacherId) == null)
select(Item(
@ -93,6 +96,9 @@ class TeacherDropdown : TextInputDropDown {
))
}
/**
* Select a teacher by the [teacherId] **if it's not selected yet**.
*/
fun selectDefault(teacherId: Long?) {
if (teacherId == null || selected != null)
return

View File

@ -1,7 +1,11 @@
package pl.szczodrzynski.edziennik.utils
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import androidx.appcompat.view.menu.MenuBuilder
import androidx.appcompat.view.menu.MenuPopupHelper
import androidx.appcompat.widget.PopupMenu
import com.google.android.material.textfield.TextInputEditText
import com.mikepenz.iconics.IconicsDrawable
@ -33,6 +37,7 @@ open class TextInputDropDown : TextInputEditText {
setText(selected?.displayText ?: selected?.text)
}
@SuppressLint("RestrictedApi")
open fun create(context: Context) {
val drawable = IconicsDrawable(context, CommunityMaterial.Icon.cmd_chevron_down).apply {
colorInt = Themes.getPrimaryTextColor(context)
@ -58,7 +63,9 @@ open class TextInputDropDown : TextInputEditText {
val popup = PopupMenu(context, this)
items.forEachIndexed { index, item ->
popup.menu.add(0, item.id.toInt(), index, item.text)
popup.menu.add(0, item.id.toInt(), index, item.text).also {
it.icon = item.icon
}
}
popup.setOnMenuItemClickListener { menuItem ->
@ -70,29 +77,46 @@ open class TextInputDropDown : TextInputEditText {
true
}
popup.setOnDismissListener {
val helper = MenuPopupHelper(context, popup.menu as MenuBuilder, this)
helper.setForceShowIcon(true)
helper.setOnDismissListener {
clearFocus()
}
popup.show()
helper.show()
}
}
fun select(item: Item): Item? {
/**
* Select an arbitrary [item]. Allows to select an item not present
* in the original list.
*/
fun select(item: Item): Item {
selected = item
updateText()
error = null
return item
}
/**
* Select an item by its ID. Returns the selected item
* if found.
*/
fun select(id: Long?): Item? {
return items.singleOrNull { it.id == id }?.let { select(it) }
}
/**
* Select an item by its tag. Returns the selected item
* if found.
*/
fun select(tag: Any?): Item? {
return items.singleOrNull { it.tag == tag }?.let { select(it) }
}
/**
* Select an item by its index. Returns the selected item
* if the index exists.
*/
fun select(index: Int): Item? {
return items.getOrNull(index)?.let { select(it) }
}
@ -143,5 +167,11 @@ open class TextInputDropDown : TextInputEditText {
}
}
class Item(val id: Long, val text: CharSequence, val displayText: CharSequence? = null, val tag: Any? = null)
class Item(
val id: Long,
val text: CharSequence,
val displayText: CharSequence? = null,
val tag: Any? = null,
val icon: Drawable? = null
)
}

View File

@ -94,7 +94,7 @@
android:layout_weight="1"
android:hint="@string/dialog_event_manual_type">
<pl.szczodrzynski.edziennik.utils.TextInputDropDown
<pl.szczodrzynski.edziennik.ui.modules.views.EventTypeDropdown
android:id="@+id/typeDropdown"
android:layout_width="match_parent"
android:layout_height="wrap_content"