Fix import, add wall

This commit is contained in:
Lars Westermann 2019-06-09 19:21:20 +02:00
parent 8a926aeb35
commit 19956ebafb
Signed by: lars.westermann
GPG key ID: 9D417FA5BB9D5E1D
19 changed files with 749 additions and 218 deletions

View file

@ -23,6 +23,37 @@ data class Post(
)
)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as Post
if (id != other.id) return false
if (name != other.name) return false
if (content != other.content) return false
if (url != other.url) return false
if (image != other.image) return false
if (pinned != other.pinned) return false
if (hideOnProjector != other.hideOnProjector) return false
return true
}
fun equalsIgnoreId(other: Post): Boolean = copy(id = null) == other.copy(id = null)
override fun hashCode(): Int {
var result = id?.hashCode() ?: 0
result = 31 * result + name.hashCode()
result = 31 * result + content.hashCode()
result = 31 * result + url.hashCode()
result = 31 * result + (image?.hashCode() ?: 0)
result = 31 * result + pinned.hashCode()
result = 31 * result + hideOnProjector.hashCode()
return result
}
companion object {
private const val chars = "abcdefghijklmnopqrstuvwxyz"
private const val length = 32

View file

@ -17,6 +17,8 @@ data class Room(
override val updateAt: Long = 0
) : Model {
override fun createSearch() = SearchElement(
mapOf(
"name" to name
@ -26,4 +28,36 @@ data class Room(
"places" to places.toDouble()
)
)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as Room
if (id != other.id) return false
if (name != other.name) return false
if (places != other.places) return false
if (projector != other.projector) return false
if (internet != other.internet) return false
if (whiteboard != other.whiteboard) return false
if (blackboard != other.blackboard) return false
if (accessible != other.accessible) return false
return true
}
fun equalsIgnoreId(other: Room): Boolean = copy(id = null) == other.copy(id = null)
override fun hashCode(): Int {
var result = id?.hashCode() ?: 0
result = 31 * result + name.hashCode()
result = 31 * result + places
result = 31 * result + projector.hashCode()
result = 31 * result + internet.hashCode()
result = 31 * result + whiteboard.hashCode()
result = 31 * result + blackboard.hashCode()
result = 31 * result + accessible.hashCode()
return result
}
}

View file

@ -16,6 +16,7 @@ data class Schedule(
override val updateAt: Long = 0
) : Model {
override fun createSearch() = SearchElement(
mapOf(
"workgroup" to workGroup.name,
@ -29,6 +30,35 @@ data class Schedule(
fun getAbsoluteStartTime(): Int = day * 60 * 24 + time
fun getAbsoluteEndTime(): Int = getAbsoluteStartTime() + workGroup.length
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as Schedule
if (id != other.id) return false
if (workGroup != other.workGroup) return false
if (room != other.room) return false
if (day != other.day) return false
if (time != other.time) return false
if (lockRoom != other.lockRoom) return false
if (lockTime != other.lockTime) return false
return true
}
fun equalsIgnoreId(other: Schedule): Boolean = copy(id = null) == other.copy(id = null)
override fun hashCode(): Int {
var result = id?.hashCode() ?: 0
result = 31 * result + workGroup.hashCode()
result = 31 * result + room.hashCode()
result = 31 * result + day
result = 31 * result + time
result = 31 * result + lockRoom.hashCode()
result = 31 * result + lockTime.hashCode()
return result
}
companion object {
fun timeOfDayToString(time: Int): String {

View file

@ -12,9 +12,33 @@ data class Track(
override val updateAt: Long = 0
) : Model {
override fun createSearch() = SearchElement(
mapOf(
"name" to name
)
)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as Track
if (id != other.id) return false
if (name != other.name) return false
if (color != other.color) return false
return true
}
fun equalsIgnoreId(other: Track): Boolean = copy(id = null) == other.copy(id = null)
override fun hashCode(): Int {
var result = id?.hashCode() ?: 0
result = 31 * result + name.hashCode()
result = 31 * result + color.hashCode()
return result
}
}

View file

@ -13,6 +13,8 @@ data class User(
override val updateAt: Long = 0
) : Model {
fun checkPermission(permission: Permission): Boolean {
return permission in permissions || Permission.ADMIN in permissions
}
@ -22,4 +24,28 @@ data class User(
"username" to username
)
)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as User
if (id != other.id) return false
if (username != other.username) return false
if (password != other.password) return false
if (permissions != other.permissions) return false
return true
}
fun equalsIgnoreId(other: User): Boolean = copy(id = null) == other.copy(id = null)
override fun hashCode(): Int {
var result = id?.hashCode() ?: 0
result = 31 * result + username.hashCode()
result = 31 * result + password.hashCode()
result = 31 * result + permissions.hashCode()
return result
}
}

View file

@ -37,4 +37,50 @@ data class WorkGroup(
"length" to length.toDouble()
)
)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as WorkGroup
if (id != other.id) return false
if (name != other.name) return false
if (description != other.description) return false
if (interested != other.interested) return false
if (track != other.track) return false
if (projector != other.projector) return false
if (resolution != other.resolution) return false
if (internet != other.internet) return false
if (whiteboard != other.whiteboard) return false
if (blackboard != other.blackboard) return false
if (accessible != other.accessible) return false
if (length != other.length) return false
if (language != other.language) return false
if (leader != other.leader) return false
if (constraints != other.constraints) return false
return true
}
fun equalsIgnoreId(other: WorkGroup): Boolean = copy(id = null) == other.copy(id = null)
override fun hashCode(): Int {
var result = id?.hashCode() ?: 0
result = 31 * result + name.hashCode()
result = 31 * result + description.hashCode()
result = 31 * result + interested
result = 31 * result + (track?.hashCode() ?: 0)
result = 31 * result + projector.hashCode()
result = 31 * result + resolution.hashCode()
result = 31 * result + internet.hashCode()
result = 31 * result + whiteboard.hashCode()
result = 31 * result + blackboard.hashCode()
result = 31 * result + accessible.hashCode()
result = 31 * result + length
result = 31 * result + language.hashCode()
result = 31 * result + leader.hashCode()
result = 31 * result + constraints.hashCode()
return result
}
}

View file

@ -1,7 +1,8 @@
package de.kif.frontend.views.board
import de.kif.common.formatDateTime
import de.westermann.kwebview.iterator
import com.soywiz.klock.DateFormat
import com.soywiz.klock.KlockLocale
import com.soywiz.klock.locale.german
import de.westermann.kwebview.interval
import org.w3c.dom.HTMLElement
import org.w3c.dom.get
@ -9,21 +10,29 @@ import kotlin.browser.document
import kotlin.js.Date
fun initBoard() {
val boardSchedules = document.getElementsByClassName("board-schedules")[0] as HTMLElement
//val boardSchedules = document.getElementsByClassName("board-schedules")[0] as HTMLElement
val dateView = document.getElementsByClassName("board-header-date")[0] as HTMLElement
val referenceTime = boardSchedules.dataset["reference"]?.toLongOrNull() ?: 0L
//val referenceTime = boardSchedules.dataset["reference"]?.toLongOrNull() ?: 0L
/*
val scheduleList = mutableListOf<BoardSchedule>()
for (bs in boardSchedules.getElementsByClassName("board-schedule").iterator()) {
scheduleList += BoardSchedule(bs)
}
*/
interval(1000) {
val currentTime = Date.now().toLong()
dateView.innerText = formatDateTime(currentTime)
val currentTime = Date().let {
it.getHours().toString().padStart(2, '0') + ":" + it.getMinutes().toString().padStart(2, '0')
}
dateView.innerText = currentTime
/*
val now = referenceTime - currentTime / 1000
scheduleList.forEach { it.updateTime(now) }
*/
}
}

View file

@ -13,33 +13,43 @@ import kotlin.browser.window
class Calendar(calendar: HTMLElement) : View(calendar) {
var autoScroll = true
val day: Int = calendar.dataset["day"]?.toIntOrNull() ?: -1
private val htmlTag = document.body as HTMLElement
val calendarTable = calendar.getElementsByClassName("calendar-table")[0] as HTMLElement
val calendarTableHeader = calendar.getElementsByClassName("calendar-header")[0] as HTMLElement
private val calendarTableHeader = calendar.getElementsByClassName("calendar-header")[0] as HTMLElement
fun scrollVerticalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
htmlTag.scrollBy(ScrollToOptions(0.0, pixel, scrollBehavior))
scrollAllVerticalBy(pixel, scrollBehavior)
}
fun scrollHorizontalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
calendarTable.scrollBy(ScrollToOptions(pixel, 0.0, scrollBehavior))
scrollAllHorizontalBy(pixel, scrollBehavior)
}
fun scrollVerticalTo(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
htmlTag.scrollTo(ScrollToOptions(0.0, pixel, scrollBehavior))
scrollAllVerticalTo(pixel, scrollBehavior)
}
fun scrollHorizontalTo(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
calendarTable.scrollTo(ScrollToOptions(pixel, 0.0, scrollBehavior))
scrollAllHorizontalTo(pixel, scrollBehavior)
}
val editable = calendar.dataset["editable"]?.toBoolean() ?: false
val body = CalendarBody(this, calendar.getElementsByClassName("calendar-body")[0] as HTMLElement)
val orientation: Orientation = if (document.getElementsByClassName("time-to-room").length > 0) {
Orientation.TIME_TO_ROOM
} else {
Orientation.ROOM_TO_TIME
}
init {
scroll += calendarTable
if (editable) {
CalendarEdit(this, calendar.querySelector(".calendar-edit") as HTMLElement)
}
@ -60,6 +70,8 @@ class Calendar(calendar: HTMLElement) : View(calendar) {
}
onWheel {
autoScroll = false
val multiplier = when (it.deltaMode) {
1 -> 16.0
2 -> window.innerHeight.toDouble()
@ -95,8 +107,56 @@ class Calendar(calendar: HTMLElement) : View(calendar) {
}
}
}
enum class Orientation {
/**
* Columns contains time
* Rows contains rooms
*
* Like the old kif tool
*/
TIME_TO_ROOM,
/**
* Columns contains rooms
* Rows contains time
*
* Like the congress schedule
*/
ROOM_TO_TIME
}
companion object {
private var scroll = listOf<HTMLElement>()
private fun scrollAllVerticalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
println("scroll ${scroll.size} elemenets")
for (calendarTable in scroll) {
calendarTable.scrollBy(ScrollToOptions(0.0, pixel, scrollBehavior))
}
}
private fun scrollAllHorizontalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
for (calendarTable in scroll) {
calendarTable.scrollBy(ScrollToOptions(pixel, 0.0, scrollBehavior))
}
}
private fun scrollAllVerticalTo(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
for (calendarTable in scroll) {
calendarTable.scrollTo(ScrollToOptions(0.0, pixel, scrollBehavior))
}
}
private fun scrollAllHorizontalTo(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
for (calendarTable in scroll) {
calendarTable.scrollTo(ScrollToOptions(pixel, 0.0, scrollBehavior))
}
}
}
}
fun initCalendar() {
Calendar(document.getElementsByClassName("calendar")[0] as? HTMLElement ?: return)
document.getElementsByClassName("calendar").iterator().forEach { Calendar(it) }
}

View file

@ -3,9 +3,13 @@ package de.kif.frontend.views.calendar
import de.kif.frontend.launch
import de.kif.frontend.repository.ScheduleRepository
import de.westermann.kwebview.ViewCollection
import de.westermann.kwebview.async
import de.westermann.kwebview.interval
import de.westermann.kwebview.iterator
import org.w3c.dom.HTMLElement
import org.w3c.dom.INSTANT
import org.w3c.dom.SMOOTH
import org.w3c.dom.ScrollBehavior
import kotlin.browser.document
import kotlin.js.Date
import kotlin.math.max
@ -81,6 +85,44 @@ class CalendarBody(val calendar: Calendar, view: HTMLElement) : ViewCollection<C
}
}
fun update(scroll: ScrollBehavior) {
val currentTime = Date().let {
it.getHours() * 60 + it.getMinutes()
}
val rowTime = (currentTime / 15) * 15
var activeRow: CalendarRow? = null
for (row in this) {
if (row.time == rowTime) {
row.classList.clear()
for (str in row.classList) {
if ("now" in str) {
row.classList -= str
}
}
row.classList += "calendar-row"
row.classList += "calendar-now"
row.classList += "calendar-now-${currentTime - rowTime}"
activeRow = row
} else {
for (str in row.classList) {
if ("now" in str) {
row.classList -= str
}
}
}
}
if (calendar.autoScroll && activeRow != null) {
if (calendar.orientation == Calendar.Orientation.ROOM_TO_TIME) {
calendar.scrollVerticalTo((activeRow.offsetTop).toDouble(), scroll)
} else {
calendar.scrollHorizontalTo((activeRow.offsetLeft - 100).toDouble(), scroll)
}
}
}
init {
calendarEntries = document.getElementsByClassName("calendar-entry")
.iterator().asSequence().map { CalendarEntry(this, it) }.toList()
@ -118,6 +160,7 @@ class CalendarBody(val calendar: Calendar, view: HTMLElement) : ViewCollection<C
updateRows()
}
}
ScheduleRepository.onDelete {
for (entry in calendarEntries) {
if (entry.scheduleId == it) {
@ -131,31 +174,12 @@ class CalendarBody(val calendar: Calendar, view: HTMLElement) : ViewCollection<C
}
}
interval(1000) {
val currentTime = Date().let {
it.getHours() * 60 + it.getMinutes()
}
val rowTime = (currentTime / 15) * 15
async {
update(ScrollBehavior.INSTANT)
}
for (row in this) {
if (row.time == rowTime) {
row.classList.clear()
for (str in row.classList) {
if ("now" in str) {
row.classList -= str
}
}
row.classList += "calendar-row"
row.classList += "calendar-now"
row.classList += "calendar-now-${currentTime - rowTime}"
} else {
for (str in row.classList) {
if ("now" in str) {
row.classList -= str
}
}
}
}
interval(1000) {
update(ScrollBehavior.SMOOTH)
}
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -1,90 +1,73 @@
@import "../config";
.board-header {
line-height: 3rem;
flex-grow: 1;
font-family: "Bungee", sans-serif;
font-weight: normal;
font-size: 1.1rem;
padding-left: 0.3rem;
}
.board-card {
background-color: var(--background-card-color);
box-shadow: 0 0.1rem 0.2rem var(--shadow-color);
border-radius: $border-radius;
overflow: hidden;
}
.board {
padding: 1rem 0.4rem 2rem;
display: flex;
top: 0;
left: 0;
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
height: calc(100vh - 0.5rem);
& > div {
flex-grow: 1;
flex-basis: 0;
padding: 0 0.4rem;
&:nth-child(1) {
flex-grow: 5;
}
&:nth-child(2) {
flex-grow: 4;
}
&:nth-child(3) {
flex-grow: 4;
}
}
}
.board-twitter {
.board-card {
height: calc(100% - 1.3rem);
& > * {
margin-top: -1px !important;
}
}
}
.board-post {
margin-bottom: 0.5rem;
.post-name {
top: 0.5rem;
}
padding-top: 2.5rem;
padding-bottom: 0.5rem;
}
.board-schedule-box {
margin-bottom: 0.5rem;
padding: 1rem 1rem 0.5rem;
table {
border-collapse: collapse;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
& > div {
position: relative;
overflow: hidden;
&:first-child {
width: 70%;
float: left;
}
&:last-child {
width: 30%;
float: right;
}
}
}
}
.board-card-header {
font-family: 'Montserrat', sans-serif;
font-weight: 600;
line-height: 1.5rem;
.board-header {
height: 8rem !important;
& > div {
height: 100%;
}
}
.board-content {
top: 8rem !important;
bottom: 0;
height: auto !important;
}
.board-logo {
img {
height: 6rem;
width: 6rem;
position: absolute;
top: 50%;
left: 4rem;
margin-top: -3rem;
margin-left: -3rem;
}
}
.board-running {
column-count: 2;
}
.board-schedule {
line-height: 1.3rem;
height: 2rem;
&:not(:last-child) {
border-bottom: solid 1px var(--table-border-color)
}
min-width: 10rem;
display: flex;
border-bottom: solid 1px var(--table-border-color)
}
.board-schedule-color {
@ -112,4 +95,46 @@
width: 4rem;
text-align: right;
color: var(--text-secondary-color)
}
}
.board-calendar {
height: 100% !important;
margin-top: 0 !important;
.calendar-table {
overflow: hidden;
}
.calendar-table-box {
width: 100%;
}
.calendar-row {
width: 100% !important;
height: 0.7rem !important;
}
.calendar-cell {
&:not(:first-child) {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
}
.calendar-entry::after {
content: none;
}
}
.board-header-date {
position: absolute;
line-height: 2rem;
font-size: 2rem;
top: 50%;
margin-top: -1rem;
left: 8rem;
}
.board-twitter {
& > * {
margin-top: -1px !important;
}
}

View file

@ -50,15 +50,16 @@
width: 100%;
position: relative;
margin-top: 1rem;
height: 100vh;
}
.calendar-table {
width: 100%;
overflow-x: scroll;
overflow-y: visible;
overflow: scroll;
padding-bottom: 1rem;
position: relative;
transition: width $transitionTime;
height: 100%;
}
.calendar-edit {
@ -301,7 +302,6 @@
flex-wrap: nowrap;
flex-direction: column;
width: max-content;
height: max-content;
.calendar-header, .calendar-row {
display: flex;
@ -325,10 +325,15 @@
line-height: 2rem;
height: 2rem;
width: 100%;
position: sticky;
top: 0;
background-color: var(--background-secondary-color);
z-index: 5;
border-bottom: solid 1px var(--table-border-color);
.calendar-cell:first-child {
flex-grow: 1;
text-align: center;
width: 6rem;
}
.calendar-cell:not(:first-child) {
@ -347,6 +352,10 @@
}
}
.calendar-body {
margin-top: -1px;
}
.calendar-row {
line-height: 2rem;
height: 1.3rem;
@ -438,6 +447,7 @@
}
.calendar-header {
.calendar-cell {
position: relative;
width: 6rem;

View file

@ -0,0 +1,78 @@
@import "../config";
.wall {
top: 0;
left: 0;
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
}
.wall-box {
width: 100%;
height: calc(33.3333% - 1rem);
overflow: hidden;
border-bottom: solid 2px var(--input-border-color);
&:first-child {
height: calc(33.3333% + 2rem);
}
&:not(:first-child) {
.calendar-row, .calendar-header {
.calendar-cell:first-child {
display: none;
}
}
}
.calendar-row, .calendar-header {
height: 100%;
display: flex;
flex-direction: column;
line-height: 2rem;
}
.calendar-entry {
top: 0 !important;
margin-top: -0.5rem !important;
bottom: 0 !important;
}
.calendar-entry::after {
content: none;
}
.calendar-table-box {
height: 100%;
}
.calendar-body {
display: flex;
}
.calendar-row {
width: 100%;
flex-basis: 0;
flex-grow: 1;
flex-shrink: 1;
}
.calendar-cell {
flex-basis: 0;
flex-grow: 1;
flex-shrink: 1;
line-height: 2rem;
width: 100%;
}
}
.wall-calendar {
margin-top: 0 !important;
height: 100% !important;
.calendar-table {
overflow: hidden;
padding: 0;
}
}

View file

@ -3,12 +3,13 @@
@include color-setting;
@import "components/board";
@import "components/calendar";
@import "components/form";
@import "components/menu";
@import "components/overview";
@import "components/table-layout";
@import "components/board";
@import "components/wall";
body, html {
color: var(--text-primary-color);
@ -143,6 +144,7 @@ a {
margin-top: -2rem;
position: absolute;
top: 48%;
left: 0;
span {
display: block;

View file

@ -64,6 +64,7 @@ fun Application.main() {
account()
board()
wall()
workGroup()
track()

View file

@ -2,6 +2,7 @@ package de.kif.backend.route
import de.kif.backend.Configuration
import de.kif.backend.repository.PostRepository
import de.kif.backend.repository.RoomRepository
import de.kif.backend.repository.ScheduleRepository
import de.kif.backend.view.respondMain
import de.kif.common.model.Schedule
@ -11,10 +12,11 @@ import kotlinx.css.CSSBuilder
import kotlinx.css.Color
import kotlinx.html.*
import java.util.*
import kotlin.math.max
import kotlin.math.min
fun Route.board() {
get("/brett") {
val postList = PostRepository.all().asReversed()
val scheduleList = ScheduleRepository.all().map {
it to it.getAbsoluteStartTime() * 60
}.sortedBy { it.second }
@ -22,53 +24,114 @@ fun Route.board() {
val referenceTime = Configuration.Schedule.referenceDate.time / 1000
val now = referenceTime - (Date().time / 1000)
val refDate = Configuration.Schedule.referenceDate
val todayDate = Date()
val refDay = refDate.time / (1000 * 60 * 60 * 24)
val todayDay = todayDate.time / (1000 * 60 * 60 * 24)
val day = (todayDay - refDay).toInt()
val list = ScheduleRepository.getByDay(day)
val rooms = RoomRepository.all()
val schedules = list.groupBy { it.room }.mapValues { (_, it) ->
it.associateBy {
it.time
}
}
var max = 0
var min = 24 * 60
for (s in list) {
max = max(max, s.time + s.workGroup.length)
min = min(min, s.time)
}
if (min > max) {
val h1 = max
max = min
min = h1
}
if (true) {
min = min(min, 0)
max = max(max, 24 * 60)
}
min = (min / 60 - 1) * 60
max = (max / 60 + 2) * 60
respondMain(true, true) { theme ->
content {
div("board") {
div("board-schedules") {
attributes["data-reference"] = referenceTime.toString()
div("board-header") {
+"Arbeitskreise"
}
div("board-card board-schedule-box") {
div("board-card-header") {
+"Aktuell"
}
table {
div("board-header") {
div("board-running") {
for ((schedule, time) in scheduleList) {
createBoardSchedule(schedule, time)
}
}
}
div("board-schedule") {
attributes["data-id"] = schedule.id.toString()
div("board-card board-schedule-box") {
div("board-card-header") {
+"Später"
}
table {
for ((schedule, time) in scheduleList) {
createBoardSchedule(schedule, time)
div("board-schedule-color") {
span {
attributes["style"] = CSSBuilder().apply {
val c = schedule.workGroup.track?.color
if (c != null) {
backgroundColor = Color(c.toString())
}
}.toString()
}
}
div("board-schedule-time") {
attributes["data-time"] = time.toString()
attributes["data-duration"] = schedule.workGroup.length.toString()
val startTime = (time % MINUTES_OF_DAY).let {
if (it < 0) it + MINUTES_OF_DAY else it
}
val sm = (startTime % 60).toString().padStart(2, '0')
val sh = (startTime / 60).toString().padStart(2, '0')
val startTimeString = "$sh:$sm"
val endTime = ((time + schedule.workGroup.length) % MINUTES_OF_DAY).let {
if (it < 0) it + MINUTES_OF_DAY else it
}
val em = (endTime % 60).toString().padStart(2, '0')
val eh = (endTime / 60).toString().padStart(2, '0')
val endTimeString = "$eh:$em"
+"$startTimeString - $endTimeString"
}
div("board-schedule-name") {
+schedule.workGroup.name
}
div("board-schedule-room") {
+schedule.room.name
}
}
}
}
}
div("board-posts") {
div("board-header") {
+"Neuigkeiten"
}
for (post in postList) {
createPost(post, false, "board-card board-post")
div("board-logo") {
img("KIF 47.0", "/static/images/logo.svg")
div("board-header-date") {
}
}
}
div("board-twitter") {
div("board-header") {
+"Twitter"
div("board-content") {
div("board-calendar calendar") {
div("calendar-table") {
renderCalendar(
CalendarOrientation.ROOM_TO_TIME,
day,
min,
max,
rooms,
schedules
)
}
}
div("board-card") {
div("board-twitter") {
unsafe {
raw("""
<a
@ -91,50 +154,3 @@ fun Route.board() {
}
}
}
private fun TABLE.createBoardSchedule(schedule: Schedule, time: Int) {
tr("board-schedule") {
attributes["data-id"] = schedule.id.toString()
td("board-schedule-color") {
span {
attributes["style"] = CSSBuilder().apply {
val c = schedule.workGroup.track?.color
if (c != null) {
backgroundColor = Color(c.toString())
}
}.toString()
}
}
td("board-schedule-time") {
attributes["data-time"] = time.toString()
attributes["data-duration"] = schedule.workGroup.length.toString()
val startTime = (time % MINUTES_OF_DAY).let {
if (it < 0) it + MINUTES_OF_DAY else it
}
val sm = (startTime % 60).toString().padStart(2, '0')
val sh = (startTime / 60).toString().padStart(2, '0')
val startTimeString = "$sh:$sm"
val endTime = ((time + schedule.workGroup.length) % MINUTES_OF_DAY).let {
if (it < 0) it + MINUTES_OF_DAY else it
}
val em = (endTime % 60).toString().padStart(2, '0')
val eh = (endTime / 60).toString().padStart(2, '0')
val endTimeString = "$eh:$em"
+"$startTimeString - $endTimeString"
}
td("board-schedule-name") {
+schedule.workGroup.name
}
td("board-schedule-room") {
+schedule.room.name
}
}
}

View file

@ -58,7 +58,7 @@ private fun DIV.calendarCell(schedule: Schedule?) {
}
}
private fun DIV.renderCalendar(
fun DIV.renderCalendar(
orientation: CalendarOrientation,
day: Int,
from: Int,

View file

@ -0,0 +1,79 @@
package de.kif.backend.route
import de.kif.backend.repository.RoomRepository
import de.kif.backend.repository.ScheduleRepository
import de.kif.backend.view.respondMain
import de.kif.common.model.Room
import de.kif.common.model.Schedule
import io.ktor.routing.Route
import io.ktor.routing.get
import kotlinx.html.div
import kotlin.math.max
import kotlin.math.min
data class WallData(
val number: Int,
val schedules: Map<Room, Map<Int, Schedule>>,
val max: Int,
val min: Int
)
suspend fun genWallData(day: Int): WallData {
val list = ScheduleRepository.getByDay(day)
val schedules = RoomRepository.all().associateWith { emptyMap<Int, Schedule>() } + list.groupBy { it.room }.mapValues { (_, it) ->
it.associateBy {
it.time
}
}
var max = 0
var min = 24 * 60
for (s in list) {
max = max(max, s.time + s.workGroup.length)
min = min(min, s.time)
}
if (min > max) {
val h1 = max
max = min
min = h1
}
min = (min / 60 - 1) * 60
max = (max / 60 + 2) * 60
return WallData(day, schedules, max, min)
}
fun Route.wall() {
get("/wand") {
val days = (0..2).map { genWallData(it) }
val min = days.map { it.min }.min() ?: days.first().min
val max = days.map { it.max }.max() ?: days.first().max
respondMain(true, true) {
content {
div("wall") {
for (day in days) {
div("wall-box") {
div("wall-calendar calendar") {
div("calendar-table") {
renderCalendar(
CalendarOrientation.TIME_TO_ROOM,
day.number,
min,
max,
day.schedules.keys.toList().sortedBy { it.id },
day.schedules
)
}
}
}
}
}
}
}
}
}

View file

@ -49,33 +49,62 @@ data class Backup(
suspend fun import(data: String) {
val backup = Message.json.parse(serializer(), data)
backup.users.forEach { UserRepository.create(it) }
backup.posts.forEach { PostRepository.create(it) }
backup.users.forEach { UserRepository.create(it); println("Import user ${it.username}") }
backup.posts.forEach { PostRepository.create(it); println("Import post") }
backup.rooms.forEach { RoomRepository.create(it) }
val roomMap = RoomRepository.all().associateWith { it.id!! }
val oldRooms = RoomRepository.all()
val newRooms = backup.rooms.filterNot { oldRooms.any { i -> i.equalsIgnoreId(it) } }
val roomMap = (oldRooms.associateWith { it.id!! } +
newRooms.map {
val id = RoomRepository.create(it)
println("Import room ${it.name}")
it to id
}).toList()
backup.tracks.forEach { TrackRepository.create(it) }
val trackMap =TrackRepository.all().associateWith { it.id!! }
val oldTracks = TrackRepository.all()
val newTracks = backup.tracks.filterNot { oldTracks.any { i -> i.equalsIgnoreId(it) } }
val trackMap = (oldTracks.associateWith { it.id!! } +
newTracks.map {
val id = TrackRepository.create(it)
println("Import track ${it.name}")
it to id
}).toList()
backup.workGroups.forEach {
var workGroup = it
val track = workGroup.track
if (track != null) {
workGroup = workGroup.copy(track = track.copy(id = trackMap[track] ?: return@forEach))
}
val oldWorkGroups = WorkGroupRepository.all()
val newWorkGroups = backup.workGroups.filterNot { oldWorkGroups.any { i -> i.equalsIgnoreId(it) } }
val workGroupMap = (oldWorkGroups.associateWith { it.id!! } +
newWorkGroups.mapNotNull {
var workGroup = it
val track = workGroup.track
if (track != null) {
workGroup = workGroup.copy(track = track.copy(id = trackMap.firstOrNull { (i,_) -> i.equalsIgnoreId(track) }?.second ?: run {
println("Cannot import work group, due to missing track")
return@mapNotNull null
}))
}
WorkGroupRepository.create(workGroup)
}
val workGroupMap = WorkGroupRepository.all().associateWith { it.id!! }
val id = WorkGroupRepository.create(workGroup)
println("Import work group ${it.name}")
it to id
}).toList()
backup.schedules.forEach {
val oldSchedules = ScheduleRepository.all()
val newSchedules = backup.schedules.filterNot { oldSchedules.any { i -> i.equalsIgnoreId(it) } }
newSchedules.forEach {
ScheduleRepository.create(
it.copy(
room = it.room.copy(id = roomMap[it.room] ?: return@forEach),
workGroup = it.workGroup.copy(id = workGroupMap[it.workGroup] ?: return@forEach)
room = it.room.copy(id = roomMap.firstOrNull { (i,_) -> i.equalsIgnoreId(it.room) }?.second ?: run {
println("Cannot import schedule, due to missing room")
return@forEach
}),
workGroup = it.workGroup.copy(id = workGroupMap.firstOrNull { (i,_) -> i.equalsIgnoreId(it.workGroup) }?.second ?: run {
println("Cannot import schedule, due to missing work group")
return@forEach
})
)
)
println("Import schedule day=${it.day}, time=${it.time}, work group=${it.workGroup.name}")
}
}