Look schedule to room and/or time

This commit is contained in:
Lars Westermann 2019-06-02 18:44:01 +02:00
parent 0288150c6e
commit bd8f10f1e7
Signed by: lars.westermann
GPG key ID: 9D417FA5BB9D5E1D
14 changed files with 1418 additions and 521 deletions

View file

@ -3,15 +3,14 @@ package de.kif.common
import de.kif.common.model.Model import de.kif.common.model.Model
import de.westermann.kobserve.event.EventHandler import de.westermann.kobserve.event.EventHandler
abstract class CachedRepository<T : Model>(val repository: Repository<T>) : Repository<T> {
class CacheRepository<T : Model>(val repository: Repository<T>) : Repository<T> {
override val onCreate = EventHandler<Long>() override val onCreate = EventHandler<Long>()
override val onUpdate = EventHandler<Long>() override val onUpdate = EventHandler<Long>()
override val onDelete = EventHandler<Long>() override val onDelete = EventHandler<Long>()
var cache: Map<Long, T> = emptyMap() private var cache: Map<Long, T> = emptyMap()
var cacheComplete: Boolean = false private var cacheComplete: Boolean = false
override suspend fun get(id: Long): T? { override suspend fun get(id: Long): T? {
return if (id in cache) { return if (id in cache) {
@ -32,29 +31,37 @@ class CacheRepository<T : Model>(val repository: Repository<T>) : Repository<T>
} }
override suspend fun update(model: T) { override suspend fun update(model: T) {
val id = model.id
if (id != null) {
cache = cache - id
}
repository.update(model) repository.update(model)
} }
override suspend fun delete(id: Long) { override suspend fun delete(id: Long) {
cache = cache - id
repository.delete(id) repository.delete(id)
} }
override suspend fun all(): List<T> { override suspend fun all(): List<T> {
if (cacheComplete) { return if (cacheComplete) {
return cache.values.toList() cache.values.toList()
} else { } else {
val all = repository.all() val all = repository.all()
cache = all.associateBy { it.id!! } cache = all.associateBy { it.id!! }
cacheComplete = true cacheComplete = true
return all all
} }
} }
init {
repository.onCreate {
cacheComplete = false
cache = cache - it
}
repository.onUpdate {
cacheComplete = false
cache = cache - it
}
repository.onDelete {
cache = cache - it
}
}
} }

View file

@ -10,6 +10,8 @@ data class Schedule(
val room: Room, val room: Room,
val day: Int, val day: Int,
val time: Int, val time: Int,
val lookRoom: Boolean,
val lookTime: Boolean,
override val createdAt: Long = 0, override val createdAt: Long = 0,
override val updateAt: Long = 0 override val updateAt: Long = 0
) : Model { ) : Model {
@ -27,4 +29,16 @@ data class Schedule(
fun getAbsoluteStartTime(): Int = day * 60 * 24 + time fun getAbsoluteStartTime(): Int = day * 60 * 24 + time
fun getAbsoluteEndTime(): Int = getAbsoluteStartTime() + workGroup.length fun getAbsoluteEndTime(): Int = getAbsoluteStartTime() + workGroup.length
companion object {
fun timeToString(time: Int): String {
var day = time % (24 * 60)
if (day < 0) day += 24 * 60
val hour = day / 60
val minute = day % 60
return hour.toString().padStart(2, '0') + ":" + minute.toString().padStart(2, '0')
}
}
} }

View file

@ -78,8 +78,6 @@ class Calendar(calendar: HTMLElement) : View(calendar) {
} }
} }
val cont = document.getElementsByClassName("header-right")[0] as HTMLElement
val view = View.wrap(document.getElementById("calendar-check-constraints") as HTMLElement) val view = View.wrap(document.getElementById("calendar-check-constraints") as HTMLElement)
view.onClick { view.onClick {
launch { launch {

View file

@ -1,6 +1,7 @@
package de.kif.frontend.views.calendar package de.kif.frontend.views.calendar
import de.kif.common.CALENDAR_GRID_WIDTH import de.kif.common.CALENDAR_GRID_WIDTH
import de.kif.common.model.Room
import de.kif.common.model.Schedule import de.kif.common.model.Schedule
import de.kif.common.model.WorkGroup import de.kif.common.model.WorkGroup
import de.kif.frontend.iterator import de.kif.frontend.iterator
@ -36,6 +37,9 @@ class CalendarEntry(private val calendar: Calendar, view: HTMLElement) : View(vi
var editable: Boolean = false var editable: Boolean = false
var moveLookRoom: Long? = null
var moveLookTime: Int? = null
private fun onMove(event: MouseEvent) { private fun onMove(event: MouseEvent) {
val position = event.toPoint() - mouseDelta val position = event.toPoint() - mouseDelta
@ -44,6 +48,13 @@ class CalendarEntry(private val calendar: Calendar, view: HTMLElement) : View(vi
} }
if (cell != null) { if (cell != null) {
if (moveLookRoom != null && cell.roomId != moveLookRoom) {
return
}
if (moveLookTime != null && cell.time != moveLookTime) {
return
}
cell += this cell += this
if (newCell == null) { if (newCell == null) {
@ -80,6 +91,10 @@ class CalendarEntry(private val calendar: Calendar, view: HTMLElement) : View(vi
} }
} }
launch {
calendarTools.setName(cell.getRoom(), cell.time)
}
newCell = cell newCell = cell
} }
@ -104,7 +119,9 @@ class CalendarEntry(private val calendar: Calendar, view: HTMLElement) : View(vi
workGroup, workGroup,
newRoom, newRoom,
calendar.day, calendar.day,
newTime newTime,
lookRoom = false,
lookTime = false
) )
) )
html.remove() html.remove()
@ -127,6 +144,8 @@ class CalendarEntry(private val calendar: Calendar, view: HTMLElement) : View(vi
private var listeners: List<de.westermann.kobserve.event.EventListener<*>> = emptyList() private var listeners: List<de.westermann.kobserve.event.EventListener<*>> = emptyList()
fun startDrag() { fun startDrag() {
classList += "drag"
listeners = listOf( listeners = listOf(
Body.onMouseMove.reference(this::onMove), Body.onMouseMove.reference(this::onMove),
Body.onMouseUp.reference(this::onFinishMove), Body.onMouseUp.reference(this::onFinishMove),
@ -134,6 +153,8 @@ class CalendarEntry(private val calendar: Calendar, view: HTMLElement) : View(vi
) )
} }
private val calendarTools = CalendarTools(this)
init { init {
onMouseDown { event -> onMouseDown { event ->
if (!editable || event.target != html || "pending" in classList) { if (!editable || event.target != html || "pending" in classList) {
@ -142,8 +163,6 @@ class CalendarEntry(private val calendar: Calendar, view: HTMLElement) : View(vi
} }
launch { launch {
classList += "drag"
val s = schedule.get() val s = schedule.get()
val time = s.time / CALENDAR_GRID_WIDTH * CALENDAR_GRID_WIDTH val time = s.time / CALENDAR_GRID_WIDTH * CALENDAR_GRID_WIDTH
@ -153,22 +172,20 @@ class CalendarEntry(private val calendar: Calendar, view: HTMLElement) : View(vi
mouseDelta = event.toPoint() - p mouseDelta = event.toPoint() - p
moveLookRoom = if (s.lookRoom) s.room.id else null
moveLookTime = if (s.lookTime) s.time else null
startDrag() startDrag()
} }
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
} }
var calendarTools: CalendarTools? = null
for (item in html.children) {
if (item.classList.contains("calendar-tools")) {
calendarTools = CalendarTools(this, item)
break
}
}
if (calendarTools == null) {
calendarTools = CalendarTools(this, createHtmlView())
html.appendChild(calendarTools.html) html.appendChild(calendarTools.html)
launch {
val s = schedule.get()
calendarTools.update(s)
} }
} }
@ -188,6 +205,7 @@ class CalendarEntry(private val calendar: Calendar, view: HTMLElement) : View(vi
} }
load(schedule.workGroup) load(schedule.workGroup)
calendarTools.update(schedule)
val time = schedule.time / CALENDAR_GRID_WIDTH * CALENDAR_GRID_WIDTH val time = schedule.time / CALENDAR_GRID_WIDTH * CALENDAR_GRID_WIDTH
val cell = calendar.calendarCells.find { val cell = calendar.calendarCells.find {

View file

@ -1,129 +1,116 @@
package de.kif.frontend.views.calendar package de.kif.frontend.views.calendar
import de.kif.common.CALENDAR_GRID_WIDTH import de.kif.common.model.Room
import de.kif.frontend.iterator import de.kif.common.model.Schedule
import de.kif.frontend.launch import de.kif.frontend.launch
import de.kif.frontend.repository.ScheduleRepository import de.kif.frontend.repository.ScheduleRepository
import de.westermann.kwebview.View import de.westermann.kwebview.View
import de.westermann.kwebview.createHtmlView import de.westermann.kwebview.ViewCollection
import org.w3c.dom.HTMLAnchorElement import de.westermann.kwebview.components.*
import org.w3c.dom.HTMLElement
import org.w3c.dom.events.EventListener
class CalendarTools(entry: CalendarEntry, view: HTMLElement) : View(view) { class CalendarTools(entry: CalendarEntry) : ViewCollection<View>() {
fun setName(room: Room, time: Int) {
nameView.text = room.name + " - " + Schedule.timeToString(time)
}
lateinit var schedule: Schedule
fun update(schedule: Schedule) {
this.schedule = schedule
setName(schedule.room, schedule.time)
lookRoomButton.classList["disabled"] = !schedule.lookRoom
lookTimeButton.classList["disabled"] = !schedule.lookTime
}
private lateinit var nameView: TextView
private lateinit var lookRoomButton: IconView
private lateinit var lookTimeButton: IconView
init { init {
var linkM10: HTMLAnchorElement? = null boxView {
var linkM5: HTMLAnchorElement? = null nameView = textView { }
var linkReset: HTMLAnchorElement? = null
var linkP5: HTMLAnchorElement? = null
var linkP10: HTMLAnchorElement? = null
var linkDel: HTMLAnchorElement? = null
for (element in html.children) { lookRoomButton = iconView(MaterialIcon.GPS_FIXED) {
when { title = "Look room"
element.classList.contains("calendar-tools-m10") -> linkM10 = element as? HTMLAnchorElement onClick {
element.classList.contains("calendar-tools-m5") -> linkM5 = element as? HTMLAnchorElement entry.pending = true
element.classList.contains("calendar-tools-reset") -> linkReset = element as? HTMLAnchorElement launch {
element.classList.contains("calendar-tools-p5") -> linkP5 = element as? HTMLAnchorElement val s = entry.schedule.get()
element.classList.contains("calendar-tools-p10") -> linkP10 = element as? HTMLAnchorElement ScheduleRepository.update(s.copy(lookRoom = "disabled" in this.classList))
element.classList.contains("calendar-tools-del") -> linkDel = element as? HTMLAnchorElement
} }
} }
}
lookTimeButton = iconView(MaterialIcon.ALARM) {
title = "Look time slot"
onClick {
entry.pending = true
launch {
val s = entry.schedule.get()
ScheduleRepository.update(s.copy(lookTime = "disabled" in this.classList))
}
}
}
}
boxView {
textView("-10") {
title = "Schedule 10 minutes earlier"
onClick {
if (schedule.lookTime) return@onClick
linkM10 = linkM10 ?: run {
val link = createHtmlView<HTMLAnchorElement>()
link.classList.add("calendar-tools-m10")
link.textContent = "-10"
html.appendChild(link)
link
}
linkM10.removeAttribute("href")
linkM10.addEventListener("click", EventListener {
entry.pending = true entry.pending = true
launch { launch {
val s = entry.schedule.get() val s = entry.schedule.get()
ScheduleRepository.update(s.copy(time = s.time - 10)) ScheduleRepository.update(s.copy(time = s.time - 10))
} }
})
linkM5 = linkM5 ?: run {
val link = createHtmlView<HTMLAnchorElement>()
link.classList.add("calendar-tools-m5")
link.textContent = "-5"
html.appendChild(link)
link
} }
linkM5.removeAttribute("href") }
linkM5.addEventListener("click", EventListener { textView("-5") {
title = "Schedule 5 minutes earlier"
onClick {
if (schedule.lookTime) return@onClick
entry.pending = true entry.pending = true
launch { launch {
val s = entry.schedule.get() val s = entry.schedule.get()
ScheduleRepository.update(s.copy(time = s.time - 5)) ScheduleRepository.update(s.copy(time = s.time - 5))
} }
}) }
}
textView("+5") {
title = "Schedule 5 minutes later"
onClick {
if (schedule.lookTime) return@onClick
linkReset = linkReset ?: run {
val link = createHtmlView<HTMLAnchorElement>()
link.classList.add("calendar-tools-reset")
link.textContent = "reset"
html.appendChild(link)
link
}
linkReset.removeAttribute("href")
linkReset.addEventListener("click", EventListener {
entry.pending = true
launch {
val s = entry.schedule.get()
ScheduleRepository.update(s.copy(time = s.time / CALENDAR_GRID_WIDTH * CALENDAR_GRID_WIDTH))
}
})
linkP5 = linkP5 ?: run {
val link = createHtmlView<HTMLAnchorElement>()
link.classList.add("calendar-tools-p5")
link.textContent = "+5"
html.appendChild(link)
link
}
linkP5.removeAttribute("href")
linkP5.addEventListener("click", EventListener {
entry.pending = true entry.pending = true
launch { launch {
val s = entry.schedule.get() val s = entry.schedule.get()
ScheduleRepository.update(s.copy(time = s.time + 5)) ScheduleRepository.update(s.copy(time = s.time + 5))
} }
})
linkP10 = linkP10 ?: run {
val link = createHtmlView<HTMLAnchorElement>()
link.classList.add("calendar-tools-p10")
link.textContent = "+10"
html.appendChild(link)
link
} }
linkP10.removeAttribute("href") }
linkP10.addEventListener("click", EventListener { textView("+10") {
title = "Schedule 10 minutes later"
onClick {
if (schedule.lookTime) return@onClick
entry.pending = true entry.pending = true
launch { launch {
val s = entry.schedule.get() val s = entry.schedule.get()
ScheduleRepository.update(s.copy(time = s.time + 10)) ScheduleRepository.update(s.copy(time = s.time + 10))
} }
})
linkDel = linkDel ?: run {
val link = createHtmlView<HTMLAnchorElement>()
link.classList.add("calendar-tools-del")
link.textContent = "del"
html.appendChild(link)
link
} }
linkDel.removeAttribute("href") }
linkDel.addEventListener("click", EventListener {
iconView(MaterialIcon.DELETE) {
title = "Delete"
onClick {
entry.pending = true entry.pending = true
launch { launch {
ScheduleRepository.delete(entry.scheduleId) ScheduleRepository.delete(entry.scheduleId)
} }
}) }
}
}
} }
} }

View file

@ -0,0 +1,15 @@
package de.westermann.kwebview.components
import org.w3c.dom.Element
/**
* Base interface for all icons.
*
* @author lars
*/
interface Icon {
/**
* Dom element that represents an icon.
*/
val element: Element
}

View file

@ -0,0 +1,53 @@
package de.westermann.kwebview.components
import de.westermann.kobserve.Property
import de.westermann.kobserve.ReadOnlyProperty
import de.westermann.kobserve.property.property
import de.westermann.kwebview.KWebViewDsl
import de.westermann.kwebview.View
import de.westermann.kwebview.ViewCollection
import de.westermann.kwebview.createHtmlView
import org.w3c.dom.HTMLSpanElement
import kotlin.dom.clear
/**
* Represents all kinds of icon views.
*
* @author lars
*/
class IconView(icon: Icon?) : View(createHtmlView<HTMLSpanElement>()) {
override val html = super.html as HTMLSpanElement
fun bind(property: ReadOnlyProperty<Icon?>) {
iconProperty.bind(property)
}
fun unbind() {
iconProperty.unbind()
}
var icon: Icon? = null
set(value) {
field = value
html.clear()
value?.let {
html.appendChild(it.element)
}
iconProperty.invalidate()
}
val iconProperty: Property<Icon?> = property(this::icon)
init {
this.icon = icon
}
}
@KWebViewDsl
fun ViewCollection<in IconView>.iconView(icon: Icon? = null, init: IconView.() -> Unit = {}) =
IconView(icon).also(this::append).also(init)
@KWebViewDsl
fun ViewCollection<in IconView>.iconView(icon: ReadOnlyProperty<Icon?>, init: IconView.() -> Unit = {}) =
IconView(icon.value).also(this::append).also { it.bind(icon) }.also(init)

View file

@ -0,0 +1,948 @@
package de.westermann.kwebview.components
import org.w3c.dom.Element
import kotlin.browser.document
/**
* List of material design icons.
*/
enum class MaterialIcon(private val ligature: String) : Icon {
ROTATION_3D("3d_rotation"),
AC_UNIT("ac_unit"),
ACCESS_ALARM("access_alarm "),
ACCESS_ALARMS("access_alarms"),
ACCESS_TIME("access_time"),
ACCESSIBILITY("accessibility"),
ACCESSIBLE("accessible"),
ACCOUNT_BALANCE("account_balance"),
ACCOUNT_BALANCE_WALLET("account_balance_wallet"),
ACCOUNT_BOX("account_box"),
ACCOUNT_CIRCLE("account_circle"),
ADB("adb"),
ADD("add"),
ADD_A_PHOTO("add_a_photo"),
ADD_ALARM("add_alarm"),
ADD_ALERT("add_alert"),
ADD_BOX("add_box"),
ADD_CIRCLE("add_circle"),
ADD_CIRCLE_OUTLINE("add_circle_outline"),
ADD_LOCATION("add_location "),
ADD_SHOPPING_CART("add_shopping_cart"),
ADD_TO_PHOTOS("add_to_photos"),
ADD_TO_QUEUE("add_to_queue "),
ADJUST("adjust"),
AIRLINE_SEAT_FLAT("airline_seat_flat"),
AIRLINE_SEAT_FLAT_ANGLED("airline_seat_flat_angled"),
AIRLINE_SEAT_INDIVIDUAL_SUITE("airline_seat_individual_suite"),
AIRLINE_SEAT_LEGROOM_EXTRA("airline_seat_legroom_extra"),
AIRLINE_SEAT_LEGROOM_NORMAL("airline_seat_legroom_normal"),
AIRLINE_SEAT_LEGROOM_REDUCED("airline_seat_legroom_reduced"),
AIRLINE_SEAT_RECLINE_EXTRA("airline_seat_recline_extra"),
AIRLINE_SEAT_RECLINE_NORMAL("airline_seat_recline_normal"),
AIRPLANEMODE_ACTIVE("airplanemode_active"),
AIRPLANEMODE_INACTIVE("airplanemode_inactive"),
AIRPLAY("airplay"),
AIRPORT_SHUTTLE("airport_shuttle"),
ALARM("alarm"),
ALARM_ADD("alarm_add"),
ALARM_OFF("alarm_off"),
ALARM_ON("alarm_on"),
ALBUM("album"),
ALL_INCLUSIVE("all_inclusive"),
ALL_OUT("all_out"),
ANDROID("android"),
ANNOUNCEMENT("announcement "),
APPS("apps"),
ARCHIVE("archive"),
ARROW_BACK("arrow_back"),
ARROW_DOWNWARD("arrow_downward"),
ARROW_DROP_DOWN("arrow_drop_down"),
ARROW_DROP_DOWN_CIRCLE("arrow_drop_down_circle"),
ARROW_DROP_UP("arrow_drop_up"),
ARROW_FORWARD("arrow_forward"),
ARROW_UPWARD("arrow_upward "),
ART_TRACK("art_track"),
ASPECT_RATIO("aspect_ratio "),
ASSESSMENT("assessment"),
ASSIGNMENT("assignment"),
ASSIGNMENT_IND("assignment_ind"),
ASSIGNMENT_LATE("assignment_late"),
ASSIGNMENT_RETURN("assignment_return"),
ASSIGNMENT_RETURNED("assignment_returned"),
ASSIGNMENT_TURNED_IN("assignment_turned_in"),
ASSISTANT("assistant"),
ASSISTANT_PHOTO("assistant_photo"),
ATTACH_FILE("attach_file"),
ATTACH_MONEY("attach_money "),
ATTACHMENT("attachment"),
AUDIOTRACK("audiotrack"),
AUTORENEW("autorenew"),
AV_TIMER("av_timer"),
BACKSPACE("backspace"),
BACKUP("backup"),
BATTERY_ALERT("battery_alert"),
BATTERY_CHARGING_FULL("battery_charging_full"),
BATTERY_FULL("battery_full "),
BATTERY_STD("battery_std"),
BATTERY_UNKNOWN("battery_unknown"),
BEACH_ACCESS("beach_access "),
BEENHERE("beenhere"),
BLOCK("block"),
BLUETOOTH("bluetooth"),
BLUETOOTH_AUDIO("bluetooth_audio"),
BLUETOOTH_CONNECTED("bluetooth_connected"),
BLUETOOTH_DISABLED("bluetooth_disabled"),
BLUETOOTH_SEARCHING("bluetooth_searching"),
BLUR_CIRCULAR("blur_circular"),
BLUR_LINEAR("blur_linear"),
BLUR_OFF("blur_off"),
BLUR_ON("blur_on"),
BOOK("book"),
BOOKMARK("bookmark"),
BOOKMARK_BORDER("bookmark_border"),
BORDER_ALL("border_all"),
BORDER_BOTTOM("border_bottom"),
BORDER_CLEAR("border_clear "),
BORDER_COLOR("border_color "),
BORDER_HORIZONTAL("border_horizontal"),
BORDER_INNER("border_inner "),
BORDER_LEFT("border_left"),
BORDER_OUTER("border_outer "),
BORDER_RIGHT("border_right "),
BORDER_STYLE("border_style "),
BORDER_TOP("border_top"),
BORDER_VERTICAL("border_vertical"),
BRANDING_WATERMARK("branding_watermark"),
BRIGHTNESS_1("brightness_1 "),
BRIGHTNESS_2("brightness_2 "),
BRIGHTNESS_3("brightness_3 "),
BRIGHTNESS_4("brightness_4 "),
BRIGHTNESS_5("brightness_5 "),
BRIGHTNESS_6("brightness_6 "),
BRIGHTNESS_7("brightness_7 "),
BRIGHTNESS_AUTO("brightness_auto"),
BRIGHTNESS_HIGH("brightness_high"),
BRIGHTNESS_LOW("brightness_low"),
BRIGHTNESS_MEDIUM("brightness_medium"),
BROKEN_IMAGE("broken_image "),
BRUSH("brush"),
BUBBLE_CHART("bubble_chart "),
BUG_REPORT("bug_report"),
BUILD("build"),
BURST_MODE("burst_mode"),
BUSINESS("business"),
BUSINESS_CENTER("business_center"),
CACHED("cached"),
CAKE("cake"),
CALL("call"),
CALL_END("call_end"),
CALL_MADE("call_made"),
CALL_MERGE("call_merge"),
CALL_MISSED("call_missed"),
CALL_MISSED_OUTGOING("call_missed_outgoing"),
CALL_RECEIVED("call_received"),
CALL_SPLIT("call_split"),
CALL_TO_ACTION("call_to_action"),
CAMERA("camera"),
CAMERA_ALT("camera_alt"),
CAMERA_ENHANCE("camera_enhance"),
CAMERA_FRONT("camera_front "),
CAMERA_REAR("camera_rear"),
CAMERA_ROLL("camera_roll"),
CANCEL("cancel"),
CARD_GIFTCARD("card_giftcard"),
CARD_MEMBERSHIP("card_membership"),
CARD_TRAVEL("card_travel"),
CASINO("casino"),
CAST("cast"),
CAST_CONNECTED("cast_connected"),
CENTER_FOCUS_STRONG("center_focus_strong"),
CENTER_FOCUS_WEAK("center_focus_weak"),
CHANGE_HISTORY("change_history"),
CHAT("chat"),
CHAT_BUBBLE("chat_bubble"),
CHAT_BUBBLE_OUTLINE("chat_bubble_outline"),
CHECK("checkUpdates"),
CHECK_BOX("check_box"),
CHECK_BOX_OUTLINE_BLANK("check_box_outline_blank"),
CHECK_CIRCLE("check_circle "),
CHEVRON_LEFT("chevron_left "),
CHEVRON_RIGHT("chevron_right"),
CHILD_CARE("child_care"),
CHILD_FRIENDLY("child_friendly"),
CHROME_RR_MODE("chrome_rr_mode"),
CLASS("class"),
CLEAR("clear"),
CLEAR_ALL("clear_all"),
CLOSE("close"),
CLOSED_CAPTION("closed_caption"),
CLOUD("cloud"),
CLOUD_CIRCLE("cloud_circle "),
CLOUD_DONE("cloud_done"),
CLOUD_DOWNLOAD("cloud_download"),
CLOUD_OFF("cloud_off"),
CLOUD_QUEUE("cloud_queue"),
CLOUD_UPLOAD("cloud_upload "),
CODE("code"),
COLLECTIONS("collections"),
COLLECTIONS_BOOKMARK("collections_bookmark"),
COLOR_LENS("color_lens"),
COLORIZE("colorize"),
COMMENT("comment"),
COMPARE("compare"),
COMPARE_ARROWS("compare_arrows"),
COMPUTER("computer"),
CONFIRMATION_NUMBER("confirmation_number"),
CONTACT_MAIL("contact_mail "),
CONTACT_PHONE("contact_phone"),
CONTACTS("contacts"),
CONTENT_COPY("content_copy "),
CONTENT_CUT("content_cut"),
CONTENT_PASTE("content_paste"),
CONTROL_POINT("control_point"),
CONTROL_POINT_DUPLICATE("control_point_duplicate"),
COPYRIGHT("copyright"),
CREATE("onCreate"),
CREATE_NEW_FOLDER("create_new_folder"),
CREDIT_CARD("credit_card"),
CROP("crop"),
CROP_16_9("crop_16_9"),
CROP_3_2("crop_3_2"),
CROP_5_4("crop_5_4"),
CROP_7_5("crop_7_5"),
CROP_DIN("crop_din"),
CROP_FREE("crop_free"),
CROP_LANDSCAPE("crop_landscape"),
CROP_ORIGINAL("crop_original"),
CROP_PORTRAIT("crop_portrait"),
CROP_ROTATE("crop_rotate"),
CROP_SQUARE("crop_square"),
DASHBOARD("dashboard"),
DATA_USAGE("data_usage"),
DATE_RANGE("date_range"),
DEHAZE("dehaze"),
DELETE("delete"),
DELETE_FOREVER("delete_forever"),
DELETE_SWEEP("delete_sweep "),
DESCRIPTION("description"),
DESKTOP_MAC("desktop_mac"),
DESKTOP_WINDOWS("desktop_windows"),
DETAILS("details"),
DEVELOPER_BOARD("developer_board"),
DEVELOPER_MODE("developer_mode"),
DEVICE_HUB("device_hub"),
DEVICES("devices"),
DEVICES_OTHER("devices_other"),
DIALER_SIP("dialer_sip"),
DIALPAD("dialpad"),
DIRECTIONS("directions"),
DIRECTIONS_BIKE("directions_bike"),
DIRECTIONS_BOAT("directions_boat"),
DIRECTIONS_BUS("directions_bus"),
DIRECTIONS_CAR("directions_car"),
DIRECTIONS_RAILWAY("directions_railway"),
DIRECTIONS_RUN("directions_run"),
DIRECTIONS_SUBWAY("directions_subway"),
DIRECTIONS_TRANSIT("directions_transit"),
DIRECTIONS_WALK("directions_walk"),
DISC_FULL("disc_full"),
DNS("dns"),
DO_NOT_DISTURB("do_not_disturb"),
DO_NOT_DISTURB_ALT("do_not_disturb_alt"),
DO_NOT_DISTURB_OFF("do_not_disturb_off"),
DO_NOT_DISTURB_ON("do_not_disturb_on"),
DOCK("dock"),
DOMAIN("domain"),
DONE("done"),
DONE_ALL("done_all"),
DONUT_LARGE("donut_large"),
DONUT_SMALL("donut_small"),
DRAFTS("drafts"),
DRAG_HANDLE("drag_handle"),
DRIVE_ETA("drive_eta"),
DVR("dvr"),
EDIT("edit"),
EDIT_LOCATION("edit_location"),
EJECT("eject"),
EMAIL("email"),
ENHANCED_ENCRYPTION("enhanced_encryption"),
EQUALIZER("equalizer"),
ERROR("error"),
ERROR_OUTLINE("error_outline"),
EURO_SYMBOL("euro_symbol"),
EV_STATION("ev_station"),
EVENT("model"),
EVENT_AVAILABLE("event_available"),
EVENT_BUSY("event_busy"),
EVENT_NOTE("event_note"),
EVENT_SEAT("event_seat"),
EXIT_TO_APP("exit_to_app"),
EXPAND_LESS("expand_less"),
EXPAND_MORE("expand_more"),
EXPLICIT("explicit"),
EXPLORE("explore"),
EXPOSURE("exposure"),
EXPOSURE_NEG_1("exposure_neg_1"),
EXPOSURE_NEG_2("exposure_neg_2"),
EXPOSURE_PLUS_1("exposure_plus_1"),
EXPOSURE_PLUS_2("exposure_plus_2"),
EXPOSURE_ZERO("exposure_zero"),
EXTENSION("extension"),
FACE("face"),
FAST_FORWARD("fast_forward "),
FAST_REWIND("fast_rewind"),
FAVORITE("favorite"),
FAVORITE_BORDER("favorite_border"),
FEATURED_PLAY_LIST("featured_play_list"),
FEATURED_VIDEO("featured_video"),
FACK("fack"),
FIBER_DVR("fiber_dvr"),
FIBER_MANUAL_RECORD("fiber_manual_record"),
FIBER_NEW("fiber_new"),
FIBER_PIN("fiber_pin"),
FIBER_SMART_RECORD("fiber_smart_record"),
FILE_DOWNLOAD("file_download"),
FILE_UPLOAD("file_upload"),
FILTER("filter"),
FILTER_1("filter_1"),
FILTER_2("filter_2"),
FILTER_3("filter_3"),
FILTER_4("filter_4"),
FILTER_5("filter_5"),
FILTER_6("filter_6"),
FILTER_7("filter_7"),
FILTER_8("filter_8"),
FILTER_9("filter_9"),
FILTER_9_PLUS("filter_9_plus"),
FILTER_B_AND_W("filter_b_and_w"),
FILTER_CENTER_FOCUS("filter_center_focus"),
FILTER_DRAMA("filter_drama "),
FILTER_FRAMES("filter_frames"),
FILTER_HDR("filter_hdr"),
FILTER_LIST("filter_list"),
FILTER_NONE("filter_none"),
FILTER_TILT_SHIFT("filter_tilt_shift"),
FILTER_VINTAGE("filter_vintage"),
FIND_IN_PAGE("find_in_page "),
FIND_REPLACE("find_replace "),
FINGERPRINT("fingerprint"),
FIRST_PAGE("first_page"),
FITNESS_CENTER("fitness_center"),
FLAG("flag"),
FLARE("flare"),
FLASH_AUTO("flash_auto"),
FLASH_OFF("flash_off"),
FLASH_ON("flash_on"),
FLIGHT("flight"),
FLIGHT_LAND("flight_land"),
FLIGHT_TAKEOFF("flight_takeoff"),
FLIP("flip"),
FLIP_TO_BACK("flip_to_back "),
FLIP_TO_FRONT("flip_to_front"),
FOLDER("folder"),
FOLDER_OPEN("folder_open"),
FOLDER_SHARED("folder_shared"),
FOLDER_SPECIAL("folder_special"),
FONT_DOWNLOAD("font_download"),
FORMAT_ALIGN_CENTER("format_align_center"),
FORMAT_ALIGN_JUSTIFY("format_align_justify"),
FORMAT_ALIGN_LEFT("format_align_left"),
FORMAT_ALIGN_RIGHT("format_align_right"),
FORMAT_BOLD("format_bold"),
FORMAT_CLEAR("format_clear "),
FORMAT_COLOR_FILL("format_color_fill"),
FORMAT_COLOR_RESET("format_color_reset"),
FORMAT_COLOR_TEXT("format_color_text"),
FORMAT_INDENT_DECREASE("format_indent_decrease"),
FORMAT_INDENT_INCREASE("format_indent_increase"),
FORMAT_ITALIC("format_italic"),
FORMAT_LINE_SPACING("format_line_spacing"),
FORMAT_LIST_BULLETED("format_list_bulleted"),
FORMAT_LIST_NUMBERED("format_list_numbered"),
FORMAT_PAINT("format_paint "),
FORMAT_QUOTE("format_quote "),
FORMAT_SHAPES("format_shapes"),
FORMAT_SIZE("format_size"),
FORMAT_STRIKETHROUGH("format_strikethrough"),
FORMAT_TEXTDIRECTION_L_TO_R("format_textdirection_l_to_r"),
FORMAT_TEXTDIRECTION_R_TO_L("format_textdirection_r_to_l"),
FORMAT_UNDERLINED("format_underlined"),
FORUM("forum"),
FORWARD("forward"),
FORWARD_10("forward_10"),
FORWARD_30("forward_30"),
FORWARD_5("forward_5"),
FREE_BREAKFAST("free_breakfast"),
FULLSCREEN("fullscreen"),
FULLSCREEN_EXIT("fullscreen_exit"),
FUNCTIONS("functions"),
G_TRANSLATE("g_translate"),
GAMEPAD("gamepad"),
GAMES("games"),
GAVEL("gavel"),
GESTURE("gesture"),
GET_APP("get_app"),
GIF("gif"),
GOLF_COURSE("golf_course"),
GPS_FIXED("gps_fixed"),
GPS_NOT_FIXED("gps_not_fixed"),
GPS_OFF("gps_off"),
GRADE("grade"),
GRADIENT("gradient"),
GRAIN("grain"),
GRAPHIC_EQ("graphic_eq"),
GRID_OFF("grid_off"),
GRID_ON("grid_on"),
GROUP("group"),
GROUP_ADD("group_add"),
GROUP_WORK("group_work"),
HD("hd"),
HDR_OFF("hdr_off"),
HDR_ON("hdr_on"),
HDR_STRONG("hdr_strong"),
HDR_WEAK("hdr_weak"),
HEADSET("headset"),
HEADSET_MIC("headset_mic"),
HEALING("healing"),
HEARING("hearing"),
HELP("help"),
HELP_OUTLINE("help_outline "),
HIGH_QUALITY("high_quality "),
HIGHLIGHT("highlight"),
HIGHLIGHT_OFF("highlight_off"),
HISTORY("history"),
HOME("home"),
HOT_TUB("hot_tub"),
HOTEL("hotel"),
HOURGLASS_EMPTY("hourglass_empty"),
HOURGLASS_FULL("hourglass_full"),
HTTP("http"),
HTTPS("https"),
IMAGE("image"),
IMAGE_ASPECT_RATIO("image_aspect_ratio"),
IMPORT_CONTACTS("import_contacts"),
IMPORT_EXPORT("import_export"),
IMPORTANT_DEVICES("important_devices"),
INBOX("inbox"),
INDETERMINATE_CHECK_BOX("indeterminate_check_box"),
INFO("info"),
INFO_OUTLINE("info_outline "),
INPUT("input"),
INSERT_CHART("insert_chart "),
INSERT_COMMENT("insert_comment"),
INSERT_DRIVE_FILE("insert_drive_file"),
INSERT_EMOTICON("insert_emoticon"),
INSERT_INVITATION("insert_invitation"),
INSERT_LINK("insert_link"),
INSERT_PHOTO("insert_photo "),
INVERT_COLORS("invert_colors"),
INVERT_COLORS_OFF("invert_colors_off"),
ISO("iso"),
KEYBOARD("keyboard"),
KEYBOARD_ARROW_DOWN("keyboard_arrow_down"),
KEYBOARD_ARROW_LEFT("keyboard_arrow_left"),
KEYBOARD_ARROW_RIGHT("keyboard_arrow_right"),
KEYBOARD_ARROW_UP("keyboard_arrow_up"),
KEYBOARD_BACKSPACE("keyboard_backspace"),
KEYBOARD_CAPSLOCK("keyboard_capslock"),
KEYBOARD_HIDE("keyboard_hide"),
KEYBOARD_RETURN("keyboard_return"),
KEYBOARD_TAB("keyboard_tab "),
KEYBOARD_VOICE("keyboard_voice"),
KITCHEN("kitchen"),
LABEL("label"),
LABEL_OUTLINE("label_outline"),
LANDSCAPE("landscape"),
LANGUAGE("language"),
LAPTOP("laptop"),
LAPTOP_CHROMEBOOK("laptop_chromebook"),
LAPTOP_MAC("laptop_mac"),
LAPTOP_WINDOWS("laptop_windows"),
LAST_PAGE("last_page"),
LAUNCH("launch"),
LAYERS("layers"),
LAYERS_CLEAR("layers_clear "),
LEAK_ADD("leak_add"),
LEAK_REMOVE("leak_remove"),
LENS("lens"),
LIBRARY_ADD("library_add"),
LIBRARY_BOOKS("library_books"),
LIBRARY_MUSIC("library_music"),
LIGHTBULB_OUTLINE("lightbulb_outline"),
LINE_STYLE("line_style"),
LINE_WEIGHT("line_weight"),
LINEAR_SCALE("linear_scale "),
LINK("link"),
LINKED_CAMERA("linked_camera"),
LIST("list"),
LIVE_HELP("live_help"),
LIVE_TV("live_tv"),
LOCAL_ACTIVITY("local_activity"),
LOCAL_AIRPORT("local_airport"),
LOCAL_ATM("local_atm"),
LOCAL_BAR("local_bar"),
LOCAL_CAFE("local_cafe"),
LOCAL_CAR_WASH("local_car_wash"),
LOCAL_CONVENIENCE_STORE("local_convenience_store"),
LOCAL_DINING("local_dining "),
LOCAL_DRINK("local_drink"),
LOCAL_FLORIST("local_florist"),
LOCAL_GAS_STATION("local_gas_station"),
LOCAL_GROCERY_STORE("local_grocery_store"),
LOCAL_HOSPITAL("local_hospital"),
LOCAL_HOTEL("local_hotel"),
LOCAL_LAUNDRY_SERVICE("local_laundry_service"),
LOCAL_LIBRARY("local_library"),
LOCAL_MALL("local_mall"),
LOCAL_MOVIES("local_movies "),
LOCAL_OFFER("local_offer"),
LOCAL_PARKING("local_parking"),
LOCAL_PHARMACY("local_pharmacy"),
LOCAL_PHONE("local_phone"),
LOCAL_PIZZA("local_pizza"),
LOCAL_PLAY("local_play"),
LOCAL_POST_OFFICE("local_post_office"),
LOCAL_PRINTSHOP("local_printshop"),
LOCAL_SEE("local_see"),
LOCAL_SHIPPING("local_shipping"),
LOCAL_TAXI("local_taxi"),
LOCATION_CITY("location_city"),
LOCATION_DISABLED("location_disabled"),
LOCATION_OFF("location_off "),
LOCATION_ON("location_on"),
LOCATION_SEARCHING("location_searching"),
LOCK("lock"),
LOCK_OPEN("lock_open"),
LOCK_OUTLINE("lock_outline "),
LOOKS("looks"),
LOOKS_3("looks_3"),
LOOKS_4("looks_4"),
LOOKS_5("looks_5"),
LOOKS_6("looks_6"),
LOOKS_ONE("looks_one"),
LOOKS_TWO("looks_two"),
LOOP("loop"),
LOUPE("loupe"),
LOW_PRIORITY("low_priority "),
LOYALTY("loyalty"),
MAIL("mail"),
MAIL_OUTLINE("mail_outline "),
MAP("map"),
MARKUNREAD("markunread"),
MARKUNREAD_MAILBOX("markunread_mailbox"),
MEMORY("memory"),
MENU("menu"),
MERGE_TYPE("merge_type"),
MESSAGE("message"),
MIC("mic"),
MIC_NONE("mic_none"),
MIC_OFF("mic_off"),
MMS("mms"),
MODE_COMMENT("mode_comment "),
MODE_EDIT("mode_edit"),
MONETIZATION_ON("monetization_on"),
MONEY_OFF("money_off"),
MONOCHROME_PHOTOS("monochrome_photos"),
MOOD("mood"),
MOOD_BAD("mood_bad"),
MORE("more"),
MORE_HORIZ("more_horiz"),
MORE_VERT("more_vert"),
MOTORCYCLE("motorcycle"),
MOUSE("mouse"),
MOVE_TO_INBOX("move_to_inbox"),
MOVIE("movie"),
MOVIE_CREATION("movie_creation"),
MOVIE_FILTER("movie_filter "),
MULTILINE_CHART("multiline_chart"),
MUSIC_NOTE("music_note"),
MUSIC_VIDEO("music_video"),
MY_LOCATION("my_location"),
NATURE("nature"),
NATURE_PEOPLE("nature_people"),
NAVIGATE_BEFORE("navigate_before"),
NAVIGATE_NEXT("navigate_next"),
NAVIGATION("navigationDrawer"),
NEAR_ME("near_me"),
NETWORK_CELL("network_cell "),
NETWORK_CHECK("network_check"),
NETWORK_LOCKED("network_locked"),
NETWORK_WIFI("network_wifi "),
NEW_RELEASES("new_releases "),
NEXT_WEEK("next_week"),
NFC("nfc"),
NO_ENCRYPTION("no_encryption"),
NO_SIM("no_sim"),
NOT_INTERESTED("not_interested"),
NOTE("note"),
NOTE_ADD("note_add"),
NOTIFICATIONS("notifications"),
NOTIFICATIONS_ACTIVE("notifications_active"),
NOTIFICATIONS_NONE("notifications_none"),
NOTIFICATIONS_OFF("notifications_off"),
NOTIFICATIONS_PAUSED("notifications_paused"),
OFFLINE_PIN("offline_pin"),
ONDEMAND_VIDEO("ondemand_video"),
OPACITY("opacity"),
OPEN_IN_BROWSER("open_in_browser"),
OPEN_IN_NEW("open_in_new"),
OPEN_WITH("open_with"),
PAGES("pages"),
PAGEVIEW("pageview"),
PALETTE("palette"),
PAN_TOOL("pan_tool"),
PANORAMA("panorama"),
PANORAMA_FISH_EYE("panorama_fish_eye"),
PANORAMA_HORIZONTAL("panorama_horizontal"),
PANORAMA_VERTICAL("panorama_vertical"),
PANORAMA_WIDE_ANGLE("panorama_wide_angle"),
PARTY_MODE("party_mode"),
PAUSE("pause"),
PAUSE_CIRCLE_FILLED("pause_circle_filled"),
PAUSE_CIRCLE_OUTLINE("pause_circle_outline"),
PAYMENT("payment"),
PEOPLE("people"),
PEOPLE_OUTLINE("people_outline"),
PERM_CAMERA_MIC("perm_camera_mic"),
PERM_CONTACT_CALENDAR("perm_contact_calendar"),
PERM_DATA_SETTING("perm_data_setting"),
PERM_DEVICE_INFORMATION("perm_device_information"),
PERM_IDENTITY("perm_identity"),
PERM_MEDIA("perm_media"),
PERM_PHONE_MSG("perm_phone_msg"),
PERM_SCAN_WIFI("perm_scan_wifi"),
PERSON("person"),
PERSON_ADD("person_add"),
PERSON_OUTLINE("person_outline"),
PERSON_PIN("person_pin"),
PERSON_PIN_CIRCLE("person_pin_circle"),
PERSONAL_VIDEO("personal_video"),
PETS("pets"),
PHONE("phone"),
PHONE_ANDROID("phone_android"),
PHONE_BLUETOOTH_SPEAKER("phone_bluetooth_speaker"),
PHONE_FORWARDED("phone_forwarded"),
PHONE_IN_TALK("phone_in_talk"),
PHONE_IPHONE("phone_iphone "),
PHONE_LOCKED("phone_locked "),
PHONE_MISSED("phone_missed "),
PHONE_PAUSED("phone_paused "),
PHONELINK("phonelink"),
PHONELINK_ERASE("phonelink_erase"),
PHONELINK_LOCK("phonelink_lock"),
PHONELINK_OFF("phonelink_off"),
PHONELINK_RING("phonelink_ring"),
PHONELINK_SETUP("phonelink_setup"),
PHOTO("photo"),
PHOTO_ALBUM("photo_album"),
PHOTO_CAMERA("photo_camera "),
PHOTO_FILTER("photo_filter "),
PHOTO_LIBRARY("photo_library"),
PHOTO_SIZE_SELECT_ACTUAL("photo_size_select_actual"),
PHOTO_SIZE_SELECT_LARGE("photo_size_select_large"),
PHOTO_SIZE_SELECT_SMALL("photo_size_select_small"),
PICTURE_AS_PDF("picture_as_pdf"),
PICTURE_IN_PICTURE("picture_in_picture"),
PICTURE_IN_PICTURE_ALT("picture_in_picture_alt"),
PIE_CHART("pie_chart"),
PIE_CHART_OUTLINED("pie_chart_outlined"),
PIN_DROP("pin_drop"),
PLACE("place"),
PLAY_ARROW("play_arrow"),
PLAY_CIRCLE_FILLED("play_circle_filled"),
PLAY_CIRCLE_OUTLINE("play_circle_outline"),
PLAY_FOR_WORK("play_for_work"),
PLAYLIST_ADD("playlist_add "),
PLAYLIST_ADD_CHECK("playlist_add_check"),
PLAYLIST_PLAY("playlist_play"),
PLUS_ONE("plus_one"),
POLL("poll"),
POLYMER("polymer"),
POOL("pool"),
PORTABLE_WIFI_OFF("portable_wifi_off"),
PORTRAIT("portrait"),
POWER("power"),
POWER_INPUT("power_input"),
POWER_SETTINGS_NEW("power_settings_new"),
PREGNANT_WOMAN("pregnant_woman"),
PRESENT_TO_ALL("present_to_all"),
PRINT("print"),
PRIORITY_HIGH("priority_high"),
PUBLIC("public"),
PUBLISH("publish"),
QUERY_BUILDER("query_builder"),
QUESTION_ANSWER("question_answer"),
QUEUE("queue"),
QUEUE_MUSIC("queue_music"),
QUEUE_PLAY_NEXT("queue_play_next"),
RADIO("radio"),
RADIO_BUTTON_CHECKED("radio_button_checked"),
RADIO_BUTTON_UNCHECKED("radio_button_unchecked"),
RATE_REVIEW("rate_review"),
RECEIPT("receipt"),
RECENT_ACTORS("recent_actors"),
RECORD_VOICE_OVER("record_voice_over"),
RM("rm"),
REDO("redo"),
REFRESH("refresh"),
REMOVE("remove"),
REMOVE_CIRCLE("remove_circle"),
REMOVE_CIRCLE_OUTLINE("remove_circle_outline"),
REMOVE_FROM_QUEUE("remove_from_queue"),
REMOVE_RED_EYE("remove_red_eye"),
REMOVE_SHOPPING_CART("remove_shopping_cart"),
REORDER("reorder"),
REPEAT("repeat"),
REPEAT_ONE("repeat_one"),
REPLAY("replay"),
REPLAY_10("replay_10"),
REPLAY_30("replay_30"),
REPLAY_5("replay_5"),
REPLY("reply"),
REPLY_ALL("reply_all"),
REPORT("report"),
REPORT_PROBLEM("report_problem"),
RESTAURANT("restaurant"),
RESTAURANT_MENU("restaurant_menu"),
RESTORE("restore"),
RESTORE_PAGE("restore_page "),
RING_VOLUME("ring_volume"),
ROOM("room"),
ROOM_SERVICE("room_service "),
ROTATE_90_DEGREES_CCW("rotate_90_degrees_ccw"),
ROTATE_LEFT("rotate_left"),
ROTATE_RIGHT("rotate_right "),
ROUNDED_CORNER("rounded_corner"),
ROUTER("router"),
ROWING("rowing"),
RSS_FEED("rss_feed"),
RV_HOOKUP("rv_hookup"),
SATELLITE("satellite"),
SAVE("save"),
SCANNER("scanner"),
SCHEDULE("schedule"),
SCHOOL("school"),
SCREEN_LOCK_LANDSCAPE("screen_lock_landscape"),
SCREEN_LOCK_PORTRAIT("screen_lock_portrait"),
SCREEN_LOCK_ROTATION("screen_lock_rotation"),
SCREEN_ROTATION("screen_rotation"),
SCREEN_SHARE("screen_share "),
SD_CARD("sd_card"),
SD_STORAGE("sd_storage"),
SEARCH("search"),
SECURITY("security"),
SELECT_ALL("select_all"),
SEND("send"),
SENTIMENT_DISSATISFIED("sentiment_dissatisfied"),
SENTIMENT_NEUTRAL("sentiment_neutral"),
SENTIMENT_SATISFIED("sentiment_satisfied"),
SENTIMENT_VERY_DISSATISFIED("sentiment_very_dissatisfied"),
SENTIMENT_VERY_SATISFIED("sentiment_very_satisfied"),
SETTINGS("settings"),
SETTINGS_APPLICATIONS("settings_applications"),
SETTINGS_BACKUP_RESTORE("settings_backup_restore"),
SETTINGS_BLUETOOTH("settings_bluetooth"),
SETTINGS_BRIGHTNESS("settings_brightness"),
SETTINGS_CELL("settings_cell"),
SETTINGS_ETHERNET("settings_ethernet"),
SETTINGS_INPUT_ANTENNA("settings_input_antenna"),
SETTINGS_INPUT_COMPONENT("settings_input_component"),
SETTINGS_INPUT_COMPOSITE("settings_input_composite"),
SETTINGS_INPUT_HDMI("settings_input_hdmi"),
SETTINGS_INPUT_SVIDEO("settings_input_svideo"),
SETTINGS_OVERSCAN("settings_overscan"),
SETTINGS_PHONE("settings_phone"),
SETTINGS_POWER("settings_power"),
SETTINGS_REMOTE("settings_remote"),
SETTINGS_SYSTEM_DAYDREAM("settings_system_daydream"),
SETTINGS_VOICE("settings_voice"),
SHARE("share"),
SHOP("shop"),
SHOP_TWO("shop_two"),
SHOPPING_BASKET("shopping_basket"),
SHOPPING_CART("shopping_cart"),
SHORT_TEXT("short_text"),
SHOW_CHART("show_chart"),
SHUFFLE("shuffle"),
SIGNAL_CELLULAR_4_BAR("signal_cellular_4_bar"),
SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR("signal_cellular_connected_no_internet_4_bar"),
SIGNAL_CELLULAR_NO_SIM("signal_cellular_no_sim"),
SIGNAL_CELLULAR_NULL("signal_cellular_null"),
SIGNAL_CELLULAR_OFF("signal_cellular_off"),
SIGNAL_WIFI_4_BAR("signal_wifi_4_bar"),
SIGNAL_WIFI_4_BAR_LOCK("signal_wifi_4_bar_lock"),
SIGNAL_WIFI_OFF("signal_wifi_off"),
SIM_CARD("sim_card"),
SIM_CARD_ALERT("sim_card_alert"),
SKIP_NEXT("skip_next"),
SKIP_PREVIOUS("skip_previous"),
SLIDESHOW("slideshow"),
SLOW_MOTION_VIDEO("slow_motion_video"),
SMARTPHONE("smartphone"),
SMOKE_FREE("smoke_free"),
SMOKING_ROOMS("smoking_rooms"),
SMS("sms"),
SMS_FAILED("sms_failed"),
SNOOZE("snooze"),
SORT("sort"),
SORT_BY_ALPHA("sort_by_alpha"),
SPA("spa"),
SPACE_BAR("space_bar"),
SPEAKER("speaker"),
SPEAKER_GROUP("speaker_group"),
SPEAKER_NOTES("speaker_notes"),
SPEAKER_NOTES_OFF("speaker_notes_off"),
SPEAKER_PHONE("speaker_phone"),
SPELLCHECK("spellcheck"),
STAR("star"),
STAR_BORDER("star_border"),
STAR_HALF("star_half"),
STARS("stars"),
STAY_CURRENT_LANDSCAPE("stay_current_landscape"),
STAY_CURRENT_PORTRAIT("stay_current_portrait"),
STAY_PRIMARY_LANDSCAPE("stay_primary_landscape"),
STAY_PRIMARY_PORTRAIT("stay_primary_portrait"),
STOP("stop"),
STOP_SCREEN_SHARE("stop_screen_share"),
STORAGE("storage"),
STORE("store"),
STORE_MALL_DIRECTORY("store_mall_directory"),
STRAIGHTEN("straighten"),
STREETVIEW("streetview"),
STRIKETHROUGH_S("strikethrough_s"),
STYLE("style"),
SUBDIRECTORY_ARROW_LEFT("subdirectory_arrow_left"),
SUBDIRECTORY_ARROW_RIGHT("subdirectory_arrow_right"),
SUBJECT("subject"),
SUBSCRIPTIONS("subscriptions"),
SUBTITLES("subtitles"),
SUBWAY("subway"),
SUPERVISOR_ACCOUNT("supervisor_account"),
SURROUND_SOUND("surround_sound"),
SWAP_CALLS("swap_calls"),
SWAP_HORIZ("swap_horiz"),
SWAP_VERT("swap_vert"),
SWAP_VERTICAL_CIRCLE("swap_vertical_circle"),
SWITCH_CAMERA("switch_camera"),
SWITCH_VIDEO("switch_video "),
SYNC("sync"),
SYNC_DISABLED("sync_disabled"),
SYNC_PROBLEM("sync_problem "),
SYSTEM_UPDATE("system_update"),
SYSTEM_UPDATE_ALT("system_update_alt"),
TAB("tab"),
TAB_UNSELECTED("tab_unselected"),
TABLET("tablet"),
TABLET_ANDROID("tablet_android"),
TABLET_MAC("tablet_mac"),
TAG_FACES("tag_faces"),
TAP_AND_PLAY("tap_and_play "),
TERRAIN("terrain"),
TEXT_FIELDS("text_fields"),
TEXT_FORMAT("text_format"),
TEXTSMS("textsms"),
TEXTURE("texture"),
THEATERS("theaters"),
THUMB_DOWN("thumb_down"),
THUMB_UP("thumb_up"),
THUMBS_UP_DOWN("thumbs_up_down"),
TIME_TO_LEAVE("time_to_leave"),
TIMELAPSE("timelapse"),
TIMELINE("timeline"),
TIMER("timer"),
TIMER_10("timer_10"),
TIMER_3("timer_3"),
TIMER_OFF("timer_off"),
TITLE("title"),
TOC("toc"),
TODAY("today"),
TOLL("toll"),
TONALITY("tonality"),
TOUCH_APP("touch_app"),
TOYS("toys"),
TRACK_CHANGES("track_changes"),
TRAFFIC("traffic"),
TRAIN("train"),
TRAM("tram"),
TRANSFER_WITHIN_A_STATION("transfer_within_a_station"),
TRANSFORM("transform"),
TRANSLATE("translate"),
TRENDING_DOWN("trending_down"),
TRENDING_FLAT("trending_flat"),
TRENDING_UP("trending_up"),
TUNE("tune"),
TURNED_IN("turned_in"),
TURNED_IN_NOT("turned_in_not"),
TV("tv"),
UNARCHIVE("unarchive"),
UNDO("undo"),
UNFOLD_LESS("unfold_less"),
UNFOLD_MORE("unfold_more"),
UPDATE("update"),
USB("usb"),
VERIFIED_USER("verified_user"),
VERTICAL_ALIGN_BOTTOM("vertical_align_bottom"),
VERTICAL_ALIGN_CENTER("vertical_align_center"),
VERTICAL_ALIGN_TOP("vertical_align_top"),
VIBRATION("vibration"),
VIDEO_CALL("video_call"),
VIDEO_LABEL("video_label"),
VIDEO_LIBRARY("video_library"),
VIDEOCAM("videocam"),
VIDEOCAM_OFF("videocam_off "),
VIDEOGAME_ASSET("videogame_asset"),
VIEW_AGENDA("view_agenda"),
VIEW_ARRAY("view_array"),
VIEW_CAROUSEL("view_carousel"),
VIEW_COLUMN("view_column"),
VIEW_COMFY("view_comfy"),
VIEW_COMPACT("view_compact "),
VIEW_DAY("view_day"),
VIEW_HEADLINE("view_headline"),
VIEW_LIST("view_list"),
VIEW_MODULE("view_module"),
VIEW_QUILT("view_quilt"),
VIEW_STREAM("view_stream"),
VIEW_WEEK("view_week"),
VIGNETTE("vignette"),
VISIBILITY("visibility"),
VISIBILITY_OFF("visibility_off"),
VOICE_CHAT("voice_chat"),
VOICEMAIL("voicemail"),
VOLUME_DOWN("volume_down"),
VOLUME_MUTE("volume_mute"),
VOLUME_OFF("volume_off"),
VOLUME_UP("volume_up"),
VPN_KEY("vpn_key"),
VPN_LOCK("vpn_lock"),
WALLPAPER("wallpaper"),
WARNING("warning"),
WATCH("watch"),
WATCH_LATER("watch_later"),
WB_AUTO("wb_auto"),
WB_CLOUDY("wb_cloudy"),
WB_INCANDESCENT("wb_incandescent"),
WB_IRIDESCENT("wb_iridescent"),
WB_SUNNY("wb_sunny"),
WC("wc"),
WEB("web"),
WEB_ASSET("web_asset"),
WEEKEND("weekend"),
WHATSHOT("whatshot"),
WIDGETS("widgets"),
WIFI("wifi"),
WIFI_LOCK("wifi_lock"),
WIFI_TETHERING("wifi_tethering"),
WORK("work"),
WRAP_TEXT("wrap_text"),
YOUTUBE_SEARCHED_FOR("youtube_searched_for"),
ZOOM_IN("zoom_in"),
ZOOM_OUT("zoom_out"),
ZOOM_OUT_MAP("zoom_out_map ");
override val element: Element
get() = document.createElement("i").apply {
classList.add("material-icons")
textContent = ligature
}
}

View file

@ -1,39 +1,59 @@
$background-primary-color: #fff; $background-primary-color: #fff;
$background-secondary-color: #fcfcfc; $background-secondary-color: #fcfcfc;
$text-primary-color: #333; $text-primary-color: #333;
$text-secondary-color: rgba($text-primary-color, 0.5); $text-secondary-color: rgba($text-primary-color, 0.5);
$primary-color: #B11D33; $primary-color: #B11D33;
$primary-text-color: #fff; $primary-text-color: #fff;
$error-color: #F00; $error-color: #F00;
$error-text-color: #fff; $error-text-color: #fff;
$error-background-color: rgba($error-color, 0.5);
$input-border-color: #888; $input-border-color: #888;
$table-border-color: rgba($text-primary-color, 0.1); $table-border-color: rgba($text-primary-color, 0.1);
$table-header-color: rgba($text-primary-color, 0.06); $table-header-color: rgba($text-primary-color, 0.06);
$shadow-color: rgba($text-primary-color, 0.8); $shadow-color: rgba($text-primary-color, 0.8);
$icon-color-focused: rgba($text-primary-color, 0.87);
$icon-color: rgba($text-primary-color, 0.54);
$icon-color-inactive: rgba($text-primary-color, 0.38);
$bg-disabled-color: rgba($text-primary-color, .26); $bg-disabled-color: rgba($text-primary-color, .26);
$bg-enabled-color: rgba($primary-color, .5); $bg-enabled-color: rgba($primary-color, .5);
$lever-disabled-color: $background-primary-color; $lever-disabled-color: $background-primary-color;
$lever-enabled-color: $primary-color; $lever-enabled-color: $primary-color;
$error-background-color: rgba($error-color, 0.5);
@mixin color-setting { @mixin color-setting {
:root { :root {
--background-primary-color: $background-primary-color; --background-primary-color: $background-primary-color;
--background-secondary-color: $background-secondary-color; --background-secondary-color: $background-secondary-color;
--text-primary-color: $text-primary-color; --text-primary-color: $text-primary-color;
--text-secondary-color: $text-secondary-color; --text-secondary-color: $text-secondary-color;
--primary-color: $primary-color; --primary-color: $primary-color;
--primary-text-color: $primary-text-color; --primary-text-color: $primary-text-color;
--error-color: $error-color; --error-color: $error-color;
--error-text-color: $error-text-color; --error-text-color: $error-text-color;
--error-background-color: $error-background-color;
--input-border-color: $input-border-color; --input-border-color: $input-border-color;
--table-border-color: $table-border-color; --table-border-color: $table-border-color;
--table-header-color: $table-header-color; --table-header-color: $table-header-color;
--shadow-color: $shadow-color; --shadow-color: $shadow-color;
--icon-color-focused: $icon-color-focused;
--icon-color: $icon-color;
--icon-color-inactive: $icon-color-inactive;
--bg-disabled-color: $bg-disabled-color; --bg-disabled-color: $bg-disabled-color;
--bg-enabled-color: $bg-enabled-color; --bg-enabled-color: $bg-enabled-color;
--lever-disabled-color: $lever-disabled-color; --lever-disabled-color: $lever-disabled-color;
--lever-enabled-color: $lever-enabled-color; --lever-enabled-color: $lever-enabled-color;
--error-background-color: $error-background-color;
} }
} }

View file

@ -2,20 +2,30 @@
$background-primary-color: #2d2d2d; $background-primary-color: #2d2d2d;
$background-secondary-color: #373737; $background-secondary-color: #373737;
$text-primary-color: #fff; $text-primary-color: #fff;
$text-secondary-color: rgba($text-primary-color, 0.5); $text-secondary-color: rgba($text-primary-color, 0.5);
$primary-color: #dd213d; $primary-color: #dd213d;
$primary-text-color: #fff; $primary-text-color: #fff;
$error-color: #F00; $error-color: #F00;
$error-text-color: #fff; $error-text-color: #fff;
$error-background-color: rgba($error-color, 0.5);
$input-border-color: #888; $input-border-color: #888;
$table-border-color: rgba($text-primary-color, 0.1); $table-border-color: rgba($text-primary-color, 0.1);
$table-header-color: rgba($text-primary-color, 0.06); $table-header-color: rgba($text-primary-color, 0.06);
$shadow-color: rgba($text-primary-color, 0.8); $shadow-color: rgba($text-primary-color, 0.8);
$icon-color-focused: rgba($text-primary-color, 1.0);
$icon-color: rgba($text-primary-color, 0.7);
$icon-color-inactive: rgba($text-primary-color, 0.5);
$bg-disabled-color: rgba($text-primary-color, .26); $bg-disabled-color: rgba($text-primary-color, .26);
$bg-enabled-color: rgba($primary-color, .5); $bg-enabled-color: rgba($primary-color, .5);
$lever-disabled-color: $background-primary-color; $lever-disabled-color: $background-primary-color;
$lever-enabled-color: $primary-color; $lever-enabled-color: $primary-color;
$error-background-color: rgba($error-color, 0.5);
@include color-setting; @include color-setting;

View file

@ -26,6 +26,8 @@ body, html {
margin: 0; margin: 0;
padding: 0; padding: 0;
overflow-x: hidden;
& > *:last-child { & > *:last-child {
//margin-bottom: 1rem; //margin-bottom: 1rem;
} }
@ -549,18 +551,18 @@ form {
} }
.calendar-edit { .calendar-edit {
width: 16rem; width: 0;
height: 100%; height: 100%;
display: block; display: block;
position: absolute; position: absolute;
right: 0; right: 0;
top: 0; top: 0;
transition: width $transitionTime;
.calendar-edit-main { .calendar-edit-main {
position: sticky; position: sticky;
margin-left: 16rem;
opacity: 0; opacity: 0;
transition: margin-left $transitionTime, opacity $transitionTime, visibility $transitionTime; transition: opacity $transitionTime, visibility $transitionTime;
top: 1rem; top: 1rem;
visibility: hidden; visibility: hidden;
height: 100vh; height: 100vh;
@ -610,7 +612,7 @@ form {
z-index: 2; z-index: 2;
.calendar-tools { .calendar-tools {
display: none; display: block;
} }
} }
@ -635,8 +637,11 @@ form {
border-right: solid 1px var(--table-border-color); border-right: solid 1px var(--table-border-color);
} }
.calendar-edit {
width: 16rem;
}
.calendar-edit-main { .calendar-edit-main {
margin-left: 0;
opacity: 1; opacity: 1;
visibility: visible; visibility: visible;
} }
@ -644,19 +649,71 @@ form {
.calendar-tools { .calendar-tools {
position: absolute; position: absolute;
top: -3rem; top: -5rem;
right: 0; right: 0;
background-color: #fff; background-color: var(--background-primary-color);
padding: 0.2rem 0.5rem;
border-radius: $border-radius; border-radius: $border-radius;
display: none; display: none;
z-index: 10; z-index: 10;
width: max-content;
border: solid 1px var(--input-border-color); border: solid 1px var(--input-border-color);
box-shadow: 0 0.1rem 0.2rem var(--primary-text-color); box-shadow: 0 0.1rem 0.2rem var(--shadow-color);
a { div {
padding: 0.2rem; clear: left;
span {
float: left;
display: block;
width: 2rem;
line-height: 2rem;
height: 2rem;
text-align: center;
color: var(--icon-color-focused);
transition: color $transitionTime, background-color $transitionTime;
box-sizing: content-box;
i {
font-size: 1rem;
}
&:hover {
background: var(--table-header-color);
}
&.disabled {
color: var(--icon-color-inactive);
}
&:first-child {
padding-left: 0.5rem;
}
&:last-child {
padding-right: 0.5rem;
}
}
&:first-child {
span:first-child {
color: var(--text-primary-color);
width: 6rem;
&:hover {
background-color: transparent;
}
}
span {
padding-top: 0.2rem;
}
}
&:last-child {
span {
padding-bottom: 0.2rem;
}
}
} }
&::after { &::after {
@ -669,10 +726,6 @@ form {
} }
} }
.calendar[data-editable=false] .calendar-tools {
display: none !important;
}
.calendar-entry { .calendar-entry {
position: absolute; position: absolute;
display: block; display: block;
@ -706,7 +759,7 @@ form {
z-index: 2; z-index: 2;
.calendar-tools { .calendar-tools {
display: none; display: block;
} }
} }
@ -729,90 +782,39 @@ form {
@include no-select() @include no-select()
} }
.calendar-table-time-to-room { .calendar-table-box {
display: flex;
flex-wrap: nowrap;
flex-direction: column;
width: max-content;
height: max-content;
.calendar-header, .calendar-row { .calendar-header, .calendar-row {
display: flex; display: flex;
flex-wrap: nowrap; flex-wrap: nowrap;
flex-direction: row;
width: max-content; width: max-content;
} height: max-content;
.calendar-header {
line-height: 2rem;
height: 2rem;
.calendar-cell:not(:first-child) {
font-size: 0.8rem;
width: 6rem;
position: relative;
padding-left: 0.2rem;
&::before {
content: '';
height: 100%;
left: 0;
top: 0;
border-left: solid 1px var(--table-border-color);
position: absolute;
}
}
} }
.calendar-row { .calendar-row {
border-top: solid 1px var(--table-border-color);
line-height: 3rem;
height: 3rem;
.calendar-cell { .calendar-cell {
position: relative;
width: 1.5rem;
&:nth-child(2n + 2)::before {
content: '';
height: 100%;
left: 0;
top: 0;
border-left: solid 1px var(--table-border-color);
position: absolute;
}
&:hover { &:hover {
background-color: var(--table-header-color); background-color: var(--table-header-color);
} }
.calendar-entry {
top: 0.5rem !important;
bottom: 0.5rem;
width: 0;
left: 0;
height: auto !important;
}
} }
} }
.calendar-cell:first-child { &.room-to-time {
width: 6rem;
left: 0;
text-align: center;
border-right: solid 1px var(--table-border-color);
}
.calendar-link {
display: block;
width: 100%;
height: 100%;
}
}
.calendar-table-room-to-time {
.calendar-header, .calendar-row {
display: flex;
flex-wrap: nowrap;
width: max-content;
}
.calendar-header { .calendar-header {
line-height: 2rem; line-height: 2rem;
height: 2rem; height: 2rem;
width: 100%;
.calendar-cell:first-child {
flex-grow: 1;
text-align: center;
}
.calendar-cell:not(:first-child) { .calendar-cell:not(:first-child) {
width: 12rem; width: 12rem;
@ -848,10 +850,6 @@ form {
position: absolute; position: absolute;
} }
&:hover {
background-color: var(--table-header-color);
}
.calendar-entry { .calendar-entry {
top: 0.1rem; top: 0.1rem;
bottom: 0; bottom: 0;
@ -859,10 +857,12 @@ form {
left: 0.1rem !important; left: 0.1rem !important;
right: 0.1rem; right: 0.1rem;
} }
a {
position: relative;
} }
.calendar-cell:first-child {
width: 6rem;
left: 0;
text-align: center;
} }
.calendar-cell:first-child::before { .calendar-cell:first-child::before {
@ -873,17 +873,63 @@ form {
border-top: solid 1px var(--table-border-color); border-top: solid 1px var(--table-border-color);
} }
} }
.calendar-cell:first-child {
width: 6rem;
left: 0;
text-align: center;
} }
.calendar-link { &.time-to-room {
display: block; flex-direction: row;
width: 100%;
.calendar-header, .calendar-row {
flex-direction: column;
line-height: 3rem;
.calendar-cell {
height: 3rem;
}
}
.calendar-header {
.calendar-cell {
position: relative;
width: 6rem;
&:not(:first-child) {
border-top: solid 1px var(--table-border-color);
}
}
}
.calendar-row {
.calendar-cell {
position: relative;
width: 1.5rem;
&:not(:first-child) {
border-top: solid 1px var(--table-border-color);
}
.calendar-entry {
top: 0.5rem !important;
bottom: 0.5rem;
width: 0;
left: 0;
height: auto !important;
}
&:first-child {
font-size: 0.8rem;
position: relative;
padding-left: 0.2rem;
}
}
&:nth-child(2n + 2) .calendar-cell::before {
content: '';
height: 100%; height: 100%;
left: 0;
top: 0;
border-left: solid 1px var(--table-border-color);
position: absolute;
}
}
} }
} }

View file

@ -59,6 +59,8 @@ object DbSchedule : Table() {
val roomId = long("room_id").index() val roomId = long("room_id").index()
val day = integer("day").index() val day = integer("day").index()
val time = integer("time_slot") val time = integer("time_slot")
val lookRoom = bool("look_room").default(false)
val lookTime = bool("look_time").default(false)
val createdAt = long("createdAt") val createdAt = long("createdAt")
val updatedAt = long("updatedAt") val updatedAt = long("updatedAt")

View file

@ -24,6 +24,8 @@ object ScheduleRepository : Repository<Schedule> {
val roomId = row[DbSchedule.roomId] val roomId = row[DbSchedule.roomId]
val day = row[DbSchedule.day] val day = row[DbSchedule.day]
val time = row[DbSchedule.time] val time = row[DbSchedule.time]
val lookRoom = row[DbSchedule.lookRoom]
val lookTime = row[DbSchedule.lookTime]
val createdAt = row[DbSchedule.createdAt] val createdAt = row[DbSchedule.createdAt]
val updatedAt = row[DbSchedule.updatedAt] val updatedAt = row[DbSchedule.updatedAt]
@ -33,7 +35,7 @@ object ScheduleRepository : Repository<Schedule> {
val room = RoomRepository.get(roomId) val room = RoomRepository.get(roomId)
?: throw IllegalStateException("Room for schedule does not exist!") ?: throw IllegalStateException("Room for schedule does not exist!")
return Schedule(id, workGroup, room, day, time, createdAt, updatedAt) return Schedule(id, workGroup, room, day, time, lookRoom, lookTime, createdAt, updatedAt)
} }
override suspend fun get(id: Long): Schedule? { override suspend fun get(id: Long): Schedule? {
@ -55,6 +57,8 @@ object ScheduleRepository : Repository<Schedule> {
it[roomId] = model.room.id ?: throw IllegalArgumentException("Room does not exist!") it[roomId] = model.room.id ?: throw IllegalArgumentException("Room does not exist!")
it[day] = model.day it[day] = model.day
it[time] = model.time it[time] = model.time
it[lookRoom] = model.lookRoom
it[lookTime] = model.lookTime
it[createdAt] = now it[createdAt] = now
it[updatedAt] = now it[updatedAt] = now
@ -77,6 +81,8 @@ object ScheduleRepository : Repository<Schedule> {
it[roomId] = model.room.id ?: throw IllegalArgumentException("Room does not exist!") it[roomId] = model.room.id ?: throw IllegalArgumentException("Room does not exist!")
it[day] = model.day it[day] = model.day
it[time] = model.time it[time] = model.time
it[lookRoom] = model.lookRoom
it[lookTime] = model.lookTime
it[updatedAt] = now it[updatedAt] = now
} }

View file

@ -3,23 +3,16 @@ package de.kif.backend.route
import com.soywiz.klock.* import com.soywiz.klock.*
import com.soywiz.klock.locale.german import com.soywiz.klock.locale.german
import de.kif.backend.Configuration import de.kif.backend.Configuration
import de.kif.backend.authenticateOrRedirect
import de.kif.backend.isAuthenticated import de.kif.backend.isAuthenticated
import de.kif.backend.repository.RoomRepository import de.kif.backend.repository.RoomRepository
import de.kif.backend.repository.ScheduleRepository import de.kif.backend.repository.ScheduleRepository
import de.kif.backend.repository.WorkGroupRepository
import de.kif.backend.view.MainTemplate
import de.kif.backend.view.MenuTemplate import de.kif.backend.view.MenuTemplate
import de.kif.backend.view.TableTemplate
import de.kif.backend.view.respondMain import de.kif.backend.view.respondMain
import de.kif.common.CALENDAR_GRID_WIDTH import de.kif.common.CALENDAR_GRID_WIDTH
import de.kif.common.Search
import de.kif.common.model.Permission import de.kif.common.model.Permission
import de.kif.common.model.Room import de.kif.common.model.Room
import de.kif.common.model.Schedule import de.kif.common.model.Schedule
import io.ktor.application.call import io.ktor.application.call
import io.ktor.html.insert
import io.ktor.html.respondHtmlTemplate
import io.ktor.response.respondRedirect import io.ktor.response.respondRedirect
import io.ktor.routing.Route import io.ktor.routing.Route
import io.ktor.routing.get import io.ktor.routing.get
@ -59,116 +52,22 @@ private fun DIV.calendarCell(schedule: Schedule?) {
attributes["data-id"] = schedule.id.toString() attributes["data-id"] = schedule.id.toString()
+schedule.workGroup.name +schedule.workGroup.name
div("calendar-tools") {
a(
classes = "calendar-tools-m10",
href = "/calendar/${schedule.day}/${schedule.id}/delete?redirect=/calendar/${schedule.day}/${schedule.room.id}/${schedule.time - 10}/${schedule.workGroup.id}"
) { +"-10" }
a(
classes = "calendar-tools-m5",
href = "/calendar/${schedule.day}/${schedule.id}/delete?redirect=/calendar/${schedule.day}/${schedule.room.id}/${schedule.time - 5}/${schedule.workGroup.id}"
) { +"-05" }
a(
classes = "calendar-tools-reset",
href = "/calendar/${schedule.day}/${schedule.id}/delete?redirect=/calendar/${schedule.day}/${schedule.room.id}/${schedule.time / CALENDAR_GRID_WIDTH * CALENDAR_GRID_WIDTH}/${schedule.workGroup.id}"
) { +"reset" }
a(
classes = "calendar-tools-p5",
href = "/calendar/${schedule.day}/${schedule.id}/delete?redirect=/calendar/${schedule.day}/${schedule.room.id}/${schedule.time + 5}/${schedule.workGroup.id}"
) { +"+05" }
a(
classes = "calendar-tools-p10",
href = "/calendar/${schedule.day}/${schedule.id}/delete?redirect=/calendar/${schedule.day}/${schedule.room.id}/${schedule.time + 10}/${schedule.workGroup.id}"
) { +"+10" }
a(
classes = "calendar-tools-del",
href = "/calendar/${schedule.day}/${schedule.id}/delete"
) { +"del" }
}
} }
} }
} }
private fun DIV.renderTimeToRoom( private fun DIV.renderCalendar(
orientation: CalendarOrientation,
day: Int, day: Int,
from: Int, from: Int,
to: Int, to: Int,
rooms: List<Room>, rooms: List<Room>,
schedules: Map<Room, Map<Int, Schedule>>, schedules: Map<Room, Map<Int, Schedule>>
allowEdit: Boolean
) { ) {
val gridLabelWidth = 60 val gridLabelWidth = 60
val minutesOfDay = to - from val minutesOfDay = to - from
div("calendar-table-time-to-room") { div("calendar-table-box ${orientation.name.toLowerCase().replace("_", "-")}") {
div("calendar-header") {
div("calendar-cell") {
span {
+"Room"
}
}
for (i in 0 until minutesOfDay / gridLabelWidth) {
div("calendar-cell") {
span {
val time = ((i * gridLabelWidth + from) % MINUTES_OF_DAY).let {
if (it < 0) it + MINUTES_OF_DAY else it
}
val minutes = (time % 60).toString().padStart(2, '0')
val hours = (time / 60).toString().padStart(2, '0')
+"$hours:$minutes"
}
}
}
}
for (room in rooms) {
div("calendar-row") {
div("calendar-cell") {
span {
+room.name
}
}
for (i in 0 until minutesOfDay / CALENDAR_GRID_WIDTH) {
val start = i * CALENDAR_GRID_WIDTH + from
val end = (i + 1) * CALENDAR_GRID_WIDTH + from - 1
div("calendar-cell") {
val time = i * CALENDAR_GRID_WIDTH
val minutes = (time % 60).toString().padStart(2, '0')
val hours = (time / 60).toString().padStart(2, '0')
title = "$hours:$minutes"
attributes["data-time"] = start.toString()
attributes["data-room"] = room.id.toString()
attributes["data-day"] = day.toString()
val schedule = (start..end).mapNotNull { schedules[room]?.get(it) }.firstOrNull()
calendarCell(schedule)
val href = if (allowEdit) "/calendar/$day/${room.id}/$start" else null
a(href, classes = "calendar-link")
}
}
}
}
}
}
private fun DIV.renderRoomToTime(
day: Int,
from: Int,
to: Int,
rooms: List<Room>,
schedules: Map<Room, Map<Int, Schedule>>,
allowEdit: Boolean
) {
val gridLabelWidth = 60
val minutesOfDay = to - from
div("calendar-table-room-to-time") {
div("calendar-header") { div("calendar-header") {
div("calendar-cell") { div("calendar-cell") {
span { span {
@ -210,14 +109,11 @@ private fun DIV.renderRoomToTime(
attributes["data-time"] = start.toString() attributes["data-time"] = start.toString()
attributes["data-room"] = room.id.toString() attributes["data-room"] = room.id.toString()
attributes["data-day"] = day.toString() attributes["data-day"] = day.toString()
title = timeString title = room.name + " - " + timeString
val schedule = (start..end).mapNotNull { schedules[room]?.get(it) }.firstOrNull() val schedule = (start..end).mapNotNull { schedules[room]?.get(it) }.firstOrNull()
calendarCell(schedule) calendarCell(schedule)
val href = if (allowEdit) "/calendar/$day/${room.id}/$start" else null
a(href, classes = "calendar-link")
} }
} }
} }
@ -351,24 +247,14 @@ fun Route.calendar() {
attributes["data-editable"] = editable.toString() attributes["data-editable"] = editable.toString()
div("calendar-table") { div("calendar-table") {
when (orientation) { renderCalendar(
CalendarOrientation.ROOM_TO_TIME -> renderRoomToTime( orientation,
day, day,
min, min,
max, max,
rooms, rooms,
schedules, schedules
editable
) )
CalendarOrientation.TIME_TO_ROOM -> renderTimeToRoom(
day,
min,
max,
rooms,
schedules,
editable
)
}
} }
if (editable) { if (editable) {
@ -390,119 +276,6 @@ fun Route.calendar() {
} }
} }
} }
get("/calendar/{day}/{room}/{time}") {
authenticateOrRedirect(Permission.SCHEDULE) { user ->
val day = call.parameters["day"]?.toIntOrNull() ?: return@get
val time = call.parameters["time"]?.toIntOrNull() ?: return@get
val roomId = call.parameters["room"]?.toLongOrNull() ?: return@get
val search = call.parameters["search"] ?: ""
val list = WorkGroupRepository.all()
val room = RoomRepository.get(roomId) ?: return@get
respondMain {
menuTemplate {
this.user = user
active = MenuTemplate.Tab.WORK_GROUP
}
content {
h1 { +"Select work groups" }
insert(TableTemplate()) {
searchValue = search
action {
a("/calendar/$day") {
button(classes = "form-btn btn-primary") {
+"Cancel"
}
}
}
header {
th {
+"Name"
}
th {
+"Interested"
}
th {
+"Track"
}
th {
+"Projector"
}
th {
+"Resolution"
}
th {
+"Length"
}
}
for (u in list) {
val s = u.createSearch()
if (Search.match(search, s)) {
val href = "/calendar/$day/${room.id}/$time/${u.id}"
entry {
attributes["data-search"] = s.stringify()
td {
a(href) {
+u.name
}
}
td {
+u.interested.toString()
}
td {
+(u.track?.name ?: "")
}
td {
+u.projector.toString()
}
td {
+u.resolution.toString()
}
td {
+u.length.toString()
}
}
}
}
}
}
}
}
}
get("/calendar/{day}/{room}/{time}/{workgroup}") {
authenticateOrRedirect(Permission.SCHEDULE) { user ->
val day = call.parameters["day"]?.toIntOrNull() ?: return@get
val time = call.parameters["time"]?.toIntOrNull() ?: return@get
val roomId = call.parameters["room"]?.toLongOrNull() ?: return@get
val workGroupId = call.parameters["workgroup"]?.toLongOrNull() ?: return@get
val room = RoomRepository.get(roomId) ?: return@get
val workGroup = WorkGroupRepository.get(workGroupId) ?: return@get
val schedule = Schedule(null, workGroup, room, day, time)
ScheduleRepository.create(schedule)
val redirect = call.parameters["redirect"]
call.respondRedirect(redirect ?: "/calendar/$day")
}
}
get("/calendar/{day}/{schedule}/delete") {
authenticateOrRedirect(Permission.SCHEDULE) { user ->
val day = call.parameters["day"]?.toIntOrNull() ?: return@get
val scheduleId = call.parameters["schedule"]?.toLongOrNull() ?: return@get
ScheduleRepository.delete(scheduleId)
val redirect = call.parameters["redirect"]
call.respondRedirect(redirect ?: "/calendar/$day")
}
}
} }
enum class CalendarOrientation { enum class CalendarOrientation {