Skip to content

Commit

Permalink
implement GraniteQRCodeGenerator and QR-button in AdminView
Browse files Browse the repository at this point in the history
  external url of service must be configured in application.conf
  • Loading branch information
otto-ringhofer committed Jul 27, 2018
1 parent ac8e05f commit 5adb270
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 20 deletions.
3 changes: 3 additions & 0 deletions project/GraniteQRCodeGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ object GraniteQRCodeGenerator {
val qrcodeVersion = "1.1.4"

/** Granite QRCode Generator
*
* https://www.webcomponents.org/element/LostInBrittany/granite-qrcode-generator
*
* https://mvnrepository.com/artifact/org.webjars.bowergithub.lostinbrittany/granite-qrcode-generator/1.1.4
*
* https://lostinbrittany.github.io/granite-qrcode-generator/components/granite-qrcode-generator/
*
* intransitive, because of the reference to org.webjars.bowergithub.lifthrasiir » qr.js [0.0.20110119...
* is not available in repositories
*
Expand Down
3 changes: 1 addition & 2 deletions src/main/resources/application.conf
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
raffle {

external-url = "http://localhost:8080/"
manager-name = "raffle-manager"

}
33 changes: 26 additions & 7 deletions src/main/scala/org/scala_vienna/raffle/AdminView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import com.vaadin.flow.component.AttachEvent
import com.vaadin.flow.component.button.Button
import com.vaadin.flow.component.html.H1
import com.vaadin.flow.component.notification.Notification
import com.vaadin.flow.component.orderedlayout.VerticalLayout
import com.vaadin.flow.component.orderedlayout.{HorizontalLayout, VerticalLayout}
import com.vaadin.flow.component.page.Push
import com.vaadin.flow.router.{BeforeEvent, HasUrlParameter, Route}
import com.vaadin.flow.shared.communication.PushMode
import com.vaadin.flow.shared.ui.Transport
import com.vaadin.flow.theme.Theme
import com.vaadin.flow.theme.lumo.Lumo
import org.vaadin.addons.vaactor.Vaactor
import org.vaadin.addons.vaactor.{Vaactor, loadedConfig}

/** View for administrator of a raffle
*
Expand Down Expand Up @@ -44,17 +44,36 @@ class AdminView extends VerticalLayout
Manager ! Manager.LookupKey(raffleKey.value) // must no receive anything before attach
}

private def qrCode(id: String): GraniteQRCodeGenerator = {
val url = loadedConfig.getString("raffle.external-url")
val path = ui.getRouter.getUrl(classOf[ParticipantView], id)
new GraniteQRCodeGenerator(url + path)
.withMode(GraniteQRCodeGenerator.Octet)
.withEcclevel(GraniteQRCodeGenerator.High)
}

private def processManager(reply: Manager.Reply): Unit = reply match {
case r: Manager.Raffle =>
raffle.value = r
title.setText(s"Vaactor Raffle ${raffle.value.id}")
add(
new AdminComponent(raffle.value),
new Button("Close raffle", _ =>
ConfirmDialog("This will terminate the raffle! - Continue?")
.onOK(_ => Manager ! Manager.Close(raffle.value.id))
.onCancel(_ => {})
.open()
new HorizontalLayout(
new Button("QR Code", _ =>
ConfirmDialog(qrCode(raffle.value.id))
.withButton("Magnify", _ =>
ConfirmDialog(qrCode(raffle.value.id).withModulesize(12))
.onCancel(_ => {})
.open()
)
.onCancel(_ => {})
.open()
), new Button("Close raffle", _ =>
ConfirmDialog("This will terminate the raffle! - Continue?")
.onOK(_ => Manager ! Manager.Close(raffle.value.id))
.onCancel(_ => {})
.open()
)
)
)
case Manager.Error(msg) =>
Expand Down
18 changes: 11 additions & 7 deletions src/main/scala/org/scala_vienna/raffle/ConfirmDialog.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,37 @@ import com.vaadin.flow.component.button.Button
import com.vaadin.flow.component.dialog.Dialog
import com.vaadin.flow.component.html.H2
import com.vaadin.flow.component.orderedlayout.HorizontalLayout
import com.vaadin.flow.component.{ClickEvent, ComponentEventListener}
import com.vaadin.flow.component.{ClickEvent, Component, ComponentEventListener}

object ConfirmDialog {

def apply(msg: String): ConfirmDialog = new ConfirmDialog(msg)
def apply(content: Component): ConfirmDialog = new ConfirmDialog(content)

def apply(msg: String): ConfirmDialog = new ConfirmDialog(new H2(msg))

}

class ConfirmDialog private(msg: String) extends Dialog {
class ConfirmDialog private(content: Component) extends Dialog {

val buttons = new HorizontalLayout()

setCloseOnEsc(false)
setCloseOnOutsideClick(false)

add(new H2(msg), buttons)
add(content, buttons)

def addButton(text: String, clickListener: ComponentEventListener[ClickEvent[Button]]): this.type = {
def withButton(text: String, clickListener: ComponentEventListener[ClickEvent[Button]]): this.type = {
buttons.add(new Button(text, { event: ClickEvent[Button] =>
clickListener.onComponentEvent(event)
close()
}))
this
}

def onOK(clickListener: ComponentEventListener[ClickEvent[Button]]): this.type = addButton("OK", clickListener)
def onOK(clickListener: ComponentEventListener[ClickEvent[Button]]): this.type =
withButton("OK", clickListener)

def onCancel(clickListener: ComponentEventListener[ClickEvent[Button]]): this.type = addButton("Cancel", clickListener)
def onCancel(clickListener: ComponentEventListener[ClickEvent[Button]]): this.type =
withButton("Cancel", clickListener)

}
3 changes: 0 additions & 3 deletions src/main/scala/org/scala_vienna/raffle/CreatorView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,9 @@ import org.vaadin.addons.vaactor.Vaactor
)
class CreatorView extends VerticalLayout with Vaactor.HasActor {

val qrCode = new GraniteQRCodeGenerator()

add(
new H1("Vaactor Raffle"),
new Button("Create raffle", { _ => Manager ! Manager.Create }),
new Button("QR-Code", _ => add(qrCode))
)

override def receive: Receive = {
Expand Down
185 changes: 184 additions & 1 deletion src/main/scala/org/scala_vienna/raffle/GraniteQRCodeGenerator.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,193 @@
package org.scala_vienna.raffle

import com.vaadin.flow.component.dependency.HtmlImport
import com.vaadin.flow.component.{Component, Tag}
import com.vaadin.flow.component.{Component, PropertyDescriptor, PropertyDescriptors, Tag}
import org.scala_vienna.raffle.GraniteQRCodeGenerator._

/** Scala/Vaadin-Flow API for web component Granite QRCode Generator
*
* https://www.webcomponents.org/element/LostInBrittany/granite-qrcode-generator
*
* https://lostinbrittany.github.io/granite-qrcode-generator/components/granite-qrcode-generator/
*
*/
object GraniteQRCodeGenerator {

type JBoolean = java.lang.Boolean

sealed trait Mode {
val attr: String
}

case object Numeric extends Mode {
val attr = "numeric"
}

case object Alphanumeric extends Mode {
val attr = "alphanumeric"
}

case object Octet extends Mode {
val attr = "octet"
}

sealed trait EccLevel {
val attr: String
}

case object Low extends EccLevel {
val attr = "L"
}

case object Medium extends EccLevel {
val attr = "M"
}

case object Quartile extends EccLevel {
val attr = "Q"
}

case object High extends EccLevel {
val attr = "H"
}

val autoProperty: PropertyDescriptor[JBoolean, JBoolean] =
PropertyDescriptors.propertyWithDefault("auto", false)

val dataProperty: PropertyDescriptor[String, String] =
PropertyDescriptors.propertyWithDefault("data", "")

val ecclevelProperty: PropertyDescriptor[String, String] =
PropertyDescriptors.propertyWithDefault("ecclevel", Low.attr)

val marginProperty: PropertyDescriptor[Integer, Integer] =
PropertyDescriptors.propertyWithDefault("margin", 4)

val maskProperty: PropertyDescriptor[Integer, Integer] =
PropertyDescriptors.propertyWithDefault("mask", -1)

val modeProperty: PropertyDescriptor[String, String] =
PropertyDescriptors.propertyWithDefault("mode", Numeric.attr)

val modulesizeProperty: PropertyDescriptor[Integer, Integer] =
PropertyDescriptors.propertyWithDefault("modulesize", 5)

val versionProperty: PropertyDescriptor[Integer, Integer] =
PropertyDescriptors.propertyWithDefault("version", -1)

}

@Tag("granite-qrcode-generator")
@HtmlImport("bower_components/granite-qrcode-generator/granite-qrcode-generator.html")
class GraniteQRCodeGenerator extends Component {

def this(data: String) {
this()
auto = true
this.data = data
}

// property auto
def auto: Boolean = autoProperty.get(this)

def auto_=(v: Boolean): Unit = autoProperty.set(this, v)

def withAuto(v: Boolean): this.type = {
auto = v
this
}

// property data
def data: String = dataProperty.get(this)

def data_=(v: String): Unit = dataProperty.set(this, v)

def withData(v: String): this.type = {
data = v
this
}

// property ecclevel
def ecclevel: EccLevel = ecclevelProperty.get(this) match {
case Low.attr => Low
case Medium.attr => Medium
case Quartile.attr => Quartile
case High.attr => High
case _ => Low
}

def ecclevel_=(v: EccLevel): Unit = ecclevelProperty.set(this, v.attr)

def withEcclevel(v: EccLevel): this.type = {
ecclevel = v
this
}

// property margin
def margin: Int = marginProperty.get(this)

def margin_=(v: Int): Unit =
if (v < 4)
throw new IllegalArgumentException(s"Margin $v lower than minimum value of 4")
else marginProperty.set(this, v)

def withMargin(v: Int): this.type = {
margin = v
this
}

// property mask
def mask: Int = maskProperty.get(this)

def mask_=(v: Int): Unit =
if (v < -1 || v == 0 || v > 7)
throw new IllegalArgumentException(s"Mask $v must be between 1 and 7 (or -1)")
else maskProperty.set(this, v)

def withMask(v: Int): this.type = {
mask = v
this
}

// property mode
def mode: Mode = modeProperty.get(this) match {
case Numeric.attr => Numeric
case Alphanumeric.attr => Alphanumeric
case Octet.attr => Octet
case _ => Numeric
}

def mode_=(v: Mode): Unit = modeProperty.set(this, v.attr)

def withMode(v: Mode): this.type = {
mode = v
this
}

// property modulesize
def modulesize: Int = modulesizeProperty.get(this)

def modulesize_=(v: Int): Unit =
if (v <= 0)
throw new IllegalArgumentException(s"Modulesize $v must be positive")
else modulesizeProperty.set(this, v)

def withModulesize(v: Int): this.type = {
modulesize = v
this
}

// property version
def version: Int = versionProperty.get(this)

def version_=(v: Int): Unit =
if (v < -1 || v == 0 || v > 40)
throw new IllegalArgumentException(s"Version $v must be between 1 and 40 (or -1)")
else versionProperty.set(this, v)

def withVersion(v: Int): this.type = {
version = v
this
}

}

0 comments on commit 5adb270

Please sign in to comment.