Refactored transition code and added settings from alert settings configuration

This commit is contained in:
Nico Opiyo 2019-02-22 14:31:38 +03:00
parent 5e46c4f346
commit d44e54c1b3
6 changed files with 179 additions and 171 deletions

View File

@ -0,0 +1,57 @@
/* Animation key frames for horizontal scrolling of alert */
@keyframes alert-scrolling-text {
from { margin-left: 100%; }
to { margin-left: -300% }
}
.horizontal-scroll-animation {
animation-duration: 10s;
animation-iteration-count: 1;
animation-timing-function: linear;
animation-name: alert-scrolling-text;
}
/* ALERT STYLING */
.normal {
position: absolute;
margin: 0;
padding: 0;
left: 0;
z-index: 10;
width: 100%;
height: 0%;
vertical-align: middle;
overflow: hidden;
visibility:hidden;
}
.normal.middle {
top: 50%;
left: 50%;
margin-right: -50%;
transform: translate(-50%, -50%);
bottom: initial;
}
.normal.top {
top: 0;
bottom: initial;
}
.normal.bottom {
top: initial;
bottom: 0;
}
#alert {
position: relative;
top: 50%;
transform: translateY(-50%);
margin: 0% 0% 0% 100%;
z-index: 11;
overflow: visible;
white-space: nowrap;
color: #ffffff;
visibility: hidden;
}

View File

@ -3,6 +3,7 @@
<head> <head>
<title>Display Window</title> <title>Display Window</title>
<link href="reveal.css" rel="stylesheet"> <link href="reveal.css" rel="stylesheet">
<link href="display.css" rel="stylesheet">
<style type="text/css"> <style type="text/css">
body { body {
background: transparent !important; background: transparent !important;
@ -25,90 +26,19 @@
z-index: -1; z-index: -1;
} }
/* Animation key frames for horizontal scrolling of alert */
@keyframes alert-scrolling-text {
from { margin-left: 100%; }
to { margin-left: -300% }
}
/* Middle fade-in alert animation */
@keyframes middle-fade-in {
from { opacity: 0;}
to { opacity: 1;}
}
/* Middle fade-out alert animation */
@keyframes middle-fade-out {
from { opacity: 1;}
to { opacity: 0;}
}
/* Fade in when alert location is in the middle */
.middle-entrance-animation {
animation-duration: 2s;
animation-timing-function: linear;
animation-name: middle-fade-in;
}
/* Fade out when alert location is in the middle */
.middle-exit-animation {
animation-duration: 2s;
animation-timing-function: linear;
animation-name: middle-fade-out;
}
.horizontal-scroll-animation {
animation-duration: 10s;
animation-iteration-count: 1;
animation-timing-function: linear;
animation-name: alert-scrolling-text;
}
/* ALERT STYLING */
#alert-background {
position: absolute;
margin: 0;
padding: 0;
left: 0px;
right: 0px;
z-index: 10;
width: 100%;
height: 0%;
vertical-align: middle;
color: #ffffff;
background-color: #660000;
overflow: hidden;
visibility:hidden;
}
#alert {
position: relative;
top: 50%;
transform: translateY(-50%);
margin-top: 0%;
margin-right: 0%;
margin-left: 100%;
margin-bottom: 0%;
z-index: 11;
overflow: visible;
white-space: nowrap;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 100pt;
color: #ffffff;
visibility: hidden;
}
</style> </style>
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script> <script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script type="text/javascript" src="reveal.js"></script> <script type="text/javascript" src="reveal.js"></script>
<script type="text/javascript" src="display.js"></script> <script type="text/javascript" src="display.css"></script>
</head> </head>
<body> <body>
<div class="reveal"> <div class="reveal">
<div id="global-background" class="slide-background present" data-loaded="true"></div> <div id="global-background" class="slide-background present" data-loaded="true"></div>
<div id="alert-background"><p id="alert">Testing alerts</p></div> <div id="alert-background" class="normal"><p id="alert">Testing alerts</p></div>
<div class="slides"></div> <div class="slides"></div>
<div class="footer"></div> <div class="footer"></div>
</div> </div>
<script type="text/javascript" src="display.js"></script>
</body> </body>
</html> </html>

View File

@ -67,17 +67,15 @@ var TransitionState = {
*/ */
var AnimationState = { var AnimationState = {
NoAnimation: "noAnimation", NoAnimation: "noAnimation",
ScrollingAnimation: "scrollingAnimation", ScrollingAnimation: "scrollingAnimation"
FadeInAnimation: "fadeInAnimation",
FadeOutAnimation: "fadeOutAnimation"
}; };
/** /**
* Alert location enumeration * Alert location enumeration
*/ */
var AlertLocation = { var AlertLocation = {
Top: "0", Top: 0,
Middle: "1", Middle: 1,
Bottom: "2" Bottom: 2
}; };
/** /**
@ -411,119 +409,97 @@ var Display = {
* @param {string} text - The alert text * @param {string} text - The alert text
* @param {int} location - The location of the text (top, middle or bottom) * @param {int} location - The location of the text (top, middle or bottom)
*/ */
alert: function (text, location) { alert: function (text, alert_settings) {
console.debug(" alert text: " + text + ", location: " + location); console.debug(" alert text: " + text + ", alert settings: " + alert_settings);
if (text == "") { if (text == "") {
return null; return null;
} }
var settings = JSON.parse(alert_settings);
var alertBackground = $("#alert-background")[0]; var alertBackground = $("#alert-background")[0];
var alertText = $("#alert")[0]; var alertText = $("#alert")[0];
alertText.innerHTML = text;
alertText.innerHTML = text; /* Start the entrance transition */
Display._transitionState = Display.doEntranceTransition(settings);
/* Bring in the transition background */ // TODO: Add functinoality for no scroll and queue if not all alerts have been displayed
Display._transitionState = Display.doEntranceTransition(location);
alertBackground.addEventListener('transitionend', function (e) { alertBackground.addEventListener('transitionend', function (e) {
e.stopPropagation(); e.stopPropagation();
if (Display._transitionState == TransitionState.EntranceTransition) { if (Display._transitionState === TransitionState.EntranceTransition) {
alertText.style.visibility = "visible"; alertText.style.visibility = "visible";
alertText.classList.add("horizontal-scroll-animation"); alertText.classList.add("horizontal-scroll-animation");
Display._animationState = AnimationState.ScrollingAnimation;
Display._transitionState = TransitionState.NoTransition
} }
else if (Display._transitionState == TransitionState.ExitTransition) { else if (Display._transitionState === TransitionState.ExitTransition) {
Display._transitionState = TransitionState.NoTransition; Display._transitionState = TransitionState.NoTransition;
alertBackground.style.visibility = "hidden";
alertText.style.visibility = "hidden"; alertText.style.visibility = "hidden";
alertBackground.style.top = ""; alertBackground.classList = "";
alertBackground.style.bottom = ""; alertBackground.classList.add("normal");
alertBackground.style.height = "";
alertBackground.style.transition = "";
alertBackground.classList.remove("middle-exit-animation");
} }
}); });
alertBackground.addEventListener('animationend', function () { alertBackground.addEventListener('animationend', function (e) {
e.stopPropagation();
if (Display._animationState == AnimationState.FadeInAnimation) { if (Display._animationState === AnimationState.ScrollingAnimation) {
alertText.style.visibility = "visible";
alertText.classList.add("horizontal-scroll-animation");
alertText.classList.remove("middle-entrance-animation");
Display._animationState = AnimationState.ScrollingAnimation;
}
else if (Display._animationState == AnimationState.FadeOutAnimation) {
alertBackground.style.visibility = "hidden";
alertBackground.classList.remove("middle-exit-animation");
Display._animationState = AnimationState.NoAnimation;
}
else if (alertText.classList.contains("horizontal-scroll-animation")) {
alertText.classList.remove("horizontal-scroll-animation"); alertText.classList.remove("horizontal-scroll-animation");
alertText.style.visibility = "hidden"; alertText.style.visibility = "hidden";
Display._animationState = AnimationState.NoAnimation; Display._animationState = AnimationState.NoAnimation;
Display._transitionState = Display.doExitTransition(location); Display._transitionState = Display.doExitTransition();
} }
}); });
/* /*
* The implementation should show an alert. * The implementation should show an alert.
* It should be able to handle receiving a new alert before a previous one is "finished", basically queueing it. * It should be able to handle receiving a new alert before a previous one is "finished", basically queueing it.
*/ */
return location; return settings.location;
}, },
/** /**
* Start background entrance transition for display of alert * Start background entrance transition for display of alert
* @param {string} location - String showing the location of the alert on screen * @param {number} location - Number showing the location of the alert on screen
*/ */
doEntranceTransition: function (location) { doEntranceTransition: function (settings) {
var alertBackground = $("#alert-background")[0]; var alertBackground = $("#alert-background")[0];
var alertText = $("#alert")[0];
switch (location) { switch (settings.location) {
case AlertLocation.Top: case AlertLocation.Top:
alertBackground.style.bottom = ''; alertBackground.classList.add("top");
alertBackground.style.top = '0px';
alertBackground.style.height = "25%";
alertBackground.style.transition = "2s linear";
break; break;
case AlertLocation.Middle: case AlertLocation.Middle:
alertBackground.style.top = ((window.innerHeight - alertBackground.clientHeight) / 2) + 'px'; // alertBackground.style.top = ((window.innerHeight - alertBackground.clientHeight) / 2) + 'px';
alertBackground.style.height = "25%"; alertBackground.classList.add("middle");
alertBackground.classList.add("middle-entrance-animation");
Display._animationState = AnimationState.FadeInAnimation;
break; break;
case AlertLocation.Bottom: case AlertLocation.Bottom:
default: default:
alertBackground.style.top = ''; alertBackground.classList.add("bottom");
alertBackground.style.bottom = '0px';
alertBackground.style.height = "25%";
alertBackground.style.transition= "2s linear";
break; break;
} }
alertBackground.style.visibility = "visible"; alertText.style.color = settings.font_color;
alertText.style.fontFamily = settings.font_face;
alertText.style.fontSize = settings.font_size + "pt";
alertBackground.style.backgroundColor = settings.background_color;
// Wait for styles to be set first before starting transitions
setTimeout( function() {
alertBackground.style.height = "25%";
alertBackground.style.transition = "2s linear";
alertBackground.style.visibility = "visible";
}, 200);
return TransitionState.EntranceTransition; return TransitionState.EntranceTransition;
}, },
/** /**
* Start background exit transition once alert has been displayed * Start background exit transition once alert has been displayed
* @param {string} location - Integer showing the location of the alert on screen * @param {string} location - Integer showing the location of the alert on screen
*/ */
doExitTransition: function (location) { doExitTransition: function () {
var alertBackground = $("#alert-background")[0]; var alertBackground = $("#alert-background")[0];
alertBackground.style.height = "0%";
if (location == AlertLocation.Top || location == AlertLocation.Bottom) { alertBackground.style.transition = '2s linear';
alertBackground.style.height = "0%";
alertBackground.style.transition = '2s linear';
}
else if (location == AlertLocation.Middle) {
alertBackground.classList.add("middle-exit-animation");
alertBackground.style.height = "0%";
Display._animationState = AnimationState.FadeOutAnimation;
}
return TransitionState.ExitTransition; return TransitionState.ExitTransition;
}, },
/** /**

View File

@ -397,8 +397,9 @@ class DisplayWindow(QtWidgets.QWidget):
self.scale = scale self.scale = scale
self.run_javascript('Display.setScale({scale});'.format(scale=scale * 100)) self.run_javascript('Display.setScale({scale});'.format(scale=scale * 100))
def alert(self, text, location): def alert(self, text, settings):
""" """
Set an alert Set an alert
""" """
self.run_javascript('Display.alert("{text}", "{location}");'.format(text=text, location=location)) self.run_javascript('Display.alert("{text}", \'{settings}\');'.format(text=text, settings=settings))
# TODO: Add option scrolling option

View File

@ -23,6 +23,8 @@
The :mod:`~openlp.plugins.alerts.lib.alertsmanager` module contains the part of the plugin which manages storing and The :mod:`~openlp.plugins.alerts.lib.alertsmanager` module contains the part of the plugin which manages storing and
displaying of alerts. displaying of alerts.
""" """
import json
from PyQt5 import QtCore from PyQt5 import QtCore
from openlp.core.common.i18n import translate from openlp.core.common.i18n import translate
@ -83,8 +85,16 @@ class AlertsManager(QtCore.QObject, RegistryBase, LogMixin, RegistryProperties):
not Settings().value('core/display on monitor')): not Settings().value('core/display on monitor')):
return return
text = self.alert_list.pop(0) text = self.alert_list.pop(0)
alert_tab = self.parent().settings_tab # Put alert settings together for dict
self.live_controller.displays[0].alert(text, alert_tab.location) alert_settings = {
'background_color': Settings().value('alerts/background color'),
'location': Settings().value('alerts/location'),
'font_face': Settings().value('alerts/font face'),
'font_size': Settings().value('alerts/font size'),
'font_color': Settings().value('alerts/font color'),
'timeout': Settings().value().value('alerts/timeout')
}
self.live_controller.displays[0].alert(text, json.dumps(alert_settings))
# Check to see if we have a timer running. # Check to see if we have a timer running.
#if self.timer_id == 0: #if self.timer_id == 0:
# self.timer_id = self.startTimer(int(alert_tab.timeout) * 1000) # self.timer_id = self.startTimer(int(alert_tab.timeout) * 1000)

View File

@ -154,7 +154,7 @@ describe("The Display object", function () {
}); });
describe("Display.alert", function () { describe("Display.alert", function () {
var alertBackground, alert; var alertBackground, alert, settings;
beforeEach(function () { beforeEach(function () {
document.body.innerHTML = ""; document.body.innerHTML = "";
@ -164,60 +164,91 @@ describe("Display.alert", function () {
alert = document.createElement("p"); alert = document.createElement("p");
alert.setAttribute("id","alert"); alert.setAttribute("id","alert");
alertBackground.appendChild(alert); alertBackground.appendChild(alert);
settings = '{ \
"location": 1, "font_face": "Segoe UI, Tahoma, Geneva, Verdana, sans-serif", \
"font_size": 40, "font_color": "#ffffff", "background_color": "#660000" \
}';
}); });
it("should return null if called without any text", function () { it("should return null if called without any text", function () {
expect(Display.alert("","2")).toBeNull(); expect(Display.alert("",settings)).toBeNull();
}); });
it("should set correct alert text", function () { it("should set the correct alert text", function () {
Display.alert("OPEN-LP-3.0 Alert Test", "2"); Display.alert("OPEN-LP-3.0 Alert Test", settings);
expect(alert.innerHTML).toEqual("OPEN-LP-3.0 Alert Test"); expect(alert.innerHTML).toEqual("OPEN-LP-3.0 Alert Test");
}); });
it("should set the correct alert position", function () { it("should set the correct alert position", function () {
expect(Display.alert("Alert Location Test","2")).toEqual("2"); expect(Display.alert("Alert Location Test", settings)).toEqual(1);
}); });
}); });
describe("The doEntranceTransition", function () { describe("The doEntranceTransition", function () {
var alertBackground; var alertBackground, alertText;
// TODO: Fix tests to accommodate new behaviour with CSS classes and settings modification
beforeEach(function() { beforeEach(function() {
document.body.innerHTML = ""; document.body.innerHTML = "";
alertBackground = document.createElement("div"); alertBackground = document.createElement("div");
alertBackground.setAttribute("id", "alert-background"); alertBackground.setAttribute("id", "alert-background");
document.body.appendChild(alertBackground); document.body.appendChild(alertBackground);
alertText = document.createElement("p");
alertText.setAttribute("id","alert");
alertBackground.appendChild(alertText);
alertBackground.style.top = '0px'; alertBackground.style.top = '0px';
alertBackground.style.height = "0%"; alertBackground.style.height = "0%";
}); });
it("should set the correct styles for the alert when location is top of the page", function () { it("should set the correct styles for the alert when location is top of the page", function () {
Display.doEntranceTransition("0"); var settings = {
expect(alertBackground.style.bottom).toEqual(''); "location": 0, "font_face": "Segoe UI, Tahoma, Geneva, Verdana, sans-serif",
expect(alertBackground.style.top).toEqual('0px'); "font_size": 40, "font_color": "#ffffff", "background_color": "#660000"
expect(alertBackground.style.transition).toEqual("2s linear"); };
expect(alertBackground.style.height).toEqual("25%");
expect(alertBackground.style.visibility).toEqual("visible"); Display.doEntranceTransition(settings);
setTimeout( function() {
expect(alertBackground.style.bottom).toEqual('');
expect(alertBackground.style.top).toEqual('0px');
expect(alertBackground.style.transition).toEqual("2s linear");
expect(alertBackground.style.height).toEqual("25%");
expect(alertBackground.style.visibility).toEqual("visible");
}, 500);
}); });
it("should set the correct styles for the alert when location is middle of the page", function () { it("should set the correct styles for the alert when location is middle of the page", function () {
Display.doEntranceTransition("1"); var settings = {
"location": 0, "font_face": "Segoe UI, Tahoma, Geneva, Verdana, sans-serif",
"font_size": 40, "font_color": "#ffffff", "background_color": "#660000"
};
Display.doEntranceTransition(settings);
//To be replaced
var middlePosition = ((window.innerHeight - alertBackground.clientHeight) / 2) + 'px'; var middlePosition = ((window.innerHeight - alertBackground.clientHeight) / 2) + 'px';
expect(alertBackground.style.top).toEqual(middlePosition); expect(alertBackground.style.top).toEqual(middlePosition);
expect(alertBackground.classList.contains("middle-entrance-animation"));
expect(alertBackground.style.height).toEqual("25%"); expect(alertBackground.style.height).toEqual("25%");
expect(alertBackground.style.visibility).toEqual("visible"); expect(alertBackground.style.visibility).toEqual("visible");
}); });
it("should set the correct styles for the alert when location is bottom of the page", function () { it("should set the correct styles for the alert when location is bottom of the page", function () {
Display.doEntranceTransition("2"); var settings = {
expect(alertBackground.style.top).toEqual(''); "location": 0, "font_face": "Segoe UI, Tahoma, Geneva, Verdana, sans-serif",
expect(alertBackground.style.bottom).toEqual('0px'); "font_size": 40, "font_color": "#ffffff", "background_color": "#660000"
expect(alertBackground.style.transition).toEqual("2s linear"); };
expect(alertBackground.style.height).toEqual("25%");
expect(alertBackground.style.visibility).toEqual("visible"); Display.doEntranceTransition(settings);
setTimeout(function() {
expect(alertBackground.style.top).toEqual('');
expect(alertBackground.style.bottom).toEqual('0px');
expect(alertBackground.style.transition).toEqual("2s linear");
expect(alertBackground.style.height).toEqual("25%");
expect(alertBackground.style.visibility).toEqual("visible");
}, 500);
}); });
}); });
@ -232,19 +263,22 @@ describe("The doExitTransition", function () {
}); });
it("should remove the styles correctly when the location is the top of the page", function () { it("should remove the styles correctly when the location is the top of the page", function () {
Display.doExitTransition("0"); Display.doExitTransition(0);
expect(alertBackground.style.height).toEqual('0%'); expect(alertBackground.style.height).toEqual('0%');
expect(alertBackground.style.transition).toEqual("2s linear"); expect(alertBackground.style.transition).toEqual("2s linear");
}); });
it("should remove the styles correctly when the location is middle of the page", function () { it("should remove the styles correctly when the location is middle of the page", function () {
Display.doExitTransition("1"); Display.doExitTransition(1);
expect(alertBackground.style.height).toEqual('0%'); expect(alertBackground.style.height).toEqual('0%');
expect(alertBackground.classList.contains("middle-exit-animation")); expect(alertBackground.classList.contains("middle-exit-animation"));
}); });
it("should remove the styles correctly when the location is the bottom of the page", function () { it("should remove the styles correctly when the location is the bottom of the page", function () {
Display.doExitTransition("2"); Display.doExitTransition(2);
expect(alertBackground.style.height).toEqual('0%'); expect(alertBackground.style.height).toEqual('0%');
expect(alertBackground.style.transition).toEqual("2s linear"); expect(alertBackground.style.transition).toEqual("2s linear");
}); });