openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #34290
[Merge] lp:~ic90/openlp/animated-alerts into lp:openlp
Nico Opiyo has proposed merging lp:~ic90/openlp/animated-alerts into lp:openlp.
Commit message:
Added scrolling alerts
Requested reviews:
Nico Opiyo (ic90)
Raoul Snyman (raoul-snyman)
Tomas Groth (tomasgroth)
For more details, see:
https://code.launchpad.net/~ic90/openlp/animated-alerts/+merge/369540
Refactored the tests and optimized alert display code plus fixed spacing
--
Your team OpenLP Core is subscribed to branch lp:openlp.
=== added file 'openlp/core/display/html/display.css'
--- openlp/core/display/html/display.css 1970-01-01 00:00:00 +0000
+++ openlp/core/display/html/display.css 2019-07-01 17:51:00 +0000
@@ -0,0 +1,80 @@
+@keyframes alert-scrolling-text {
+ 0% { transform: translateX(100%); opacity: 1; }
+ 99% { opacity: 1; }
+ 100% { transform: translateX(-101%); opacity: 0;}
+}
+
+/* ALERT BACKGROUND STYLING */
+.bg-default {
+ position: absolute;
+ margin: 0;
+ padding: 0;
+ left: 0;
+ z-index: 11;
+ width: 100%;
+ height: 0;
+ min-height: 0;
+ overflow: hidden;
+ transform: translate(0,0);
+ transition: min-height 1s ease-out .5s;
+ white-space: nowrap;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ /* align-content: center; */
+}
+
+.bg-default span {
+ display: inline-block;
+ padding-left: 120%;
+}
+
+.show-bg {
+ /* height: auto; */
+ min-height: 25%;
+ transition: min-height 1s ease-in .5s;
+}
+
+.middle {
+ align-items: center;
+}
+
+.alert-container {
+ position: absolute;
+ display: flex;
+ flex-direction: row;
+ height: 100vh;
+ width: 100vw;
+}
+
+.top {
+ align-items: flex-start;
+}
+
+.bottom {
+ align-items: flex-end;
+}
+
+/* ALERT TEXT STYLING */
+#alert {
+ z-index: 100;
+ overflow: visible;
+ color: #ffffff;
+ font-size: 40pt;
+ padding: 0;
+ margin: 0;
+ opacity: 0;
+ transition: opacity .5s linear;
+}
+
+#alert.hide-text {
+ opacity: 0;
+}
+
+#alert.show-text {
+ transform: none;
+ transition: none;
+ animation: none;
+ padding: auto 5px;
+ opacity: 1;
+}
=== modified file 'openlp/core/display/html/display.html'
--- openlp/core/display/html/display.html 2019-03-17 10:36:12 +0000
+++ openlp/core/display/html/display.html 2019-07-01 17:51:00 +0000
@@ -2,7 +2,7 @@
<html>
<head>
<title>Display Window</title>
- <link href="reveal.css" rel="stylesheet">
+ <link href="reveal.css" rel="stylesheet">
<style type="text/css">
body {
background: transparent !important;
@@ -24,16 +24,21 @@
visibility: visible;
z-index: -1;
}
- </style>
+ </style>
+ <link rel="stylesheet" type="text/css" href="display.css"></link>
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script type="text/javascript" src="reveal.js"></script>
<script type="text/javascript" src="display.js"></script>
</head>
+
<body>
+ <div class="alert-container">
+ <div id="alert-background" class="bg-default"><span id="alert">Testing alerts</span></div>
+ </div>
<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 class="slides"></div>
<div class="footer"></div>
- </div>
+ </div>
</body>
</html>
=== modified file 'openlp/core/display/html/display.js'
--- openlp/core/display/html/display.js 2019-06-21 20:53:42 +0000
+++ openlp/core/display/html/display.js 2019-07-01 17:51:00 +0000
@@ -53,6 +53,50 @@
};
/**
+ * Transition state enumeration
+ */
+var TransitionState = {
+ EntranceTransition: "entranceTransition",
+ NoTransition: "noTransition",
+ ExitTransition: "exitTransition"
+};
+
+/**
+ * Animation state enumeration
+ */
+var AnimationState = {
+ NoAnimation: "noAnimation",
+ ScrollingText: "scrollingText",
+ NonScrollingText: "noScrollingText"
+};
+
+/**
+ * Alert location enumeration
+ */
+var AlertLocation = {
+ Top: 0,
+ Middle: 1,
+ Bottom: 2
+};
+
+/**
+ * Alert state enumeration
+ */
+var AlertState = {
+ Displaying: "displaying",
+ NotDisplaying: "notDisplaying"
+}
+
+/**
+ * Alert delay enumeration
+ */
+var AlertDelay = {
+ FiftyMilliseconds: 50,
+ OneSecond: 1000,
+ OnePointFiveSeconds: 1500
+}
+
+/**
* Return an array of elements based on the selector query
* @param {string} selector - The selector to find elements
* @returns {array} An array of matching elements
@@ -234,7 +278,12 @@
* The Display object is what we use from OpenLP
*/
var Display = {
+ _alerts: [],
_slides: {},
+ _alertSettings: {},
+ _alertState: AlertState.NotDisplaying,
+ _transitionState: TransitionState.NoTransition,
+ _animationState: AnimationState.NoAnimation,
_revealConfig: {
margin: 0.0,
minScale: 1.0,
@@ -356,19 +405,197 @@
/**
* Display an alert
* @param {string} text - The alert text
- * @param {int} location - The location of the text (top, middle or bottom)
- */
- alert: function (text, location) {
- console.debug(" alert text: " + text, ", location: " + location);
- /*
- * 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.
- */
- return;
-},
-
- /**
- * Add a slides. If the slide exists but the HTML is different, update the slide.
+ * @param {string} JSON object - The settings for the alert object e.g '{"backgroundColor": "rgb(255, 85, 0)",
+ * "location": 1, "fontFace": "Open Sans Condensed", "fontSize": 90, "fontColor": "rgb(255, 255, 255)",
+ * "timeout": 10, "repeat": 2, "scroll": true}'
+ */
+ alert: function (text, alertSettings) {
+ var alertBackground = $('#alert-background')[0];
+ var alertText = $('#alert')[0];
+ if (text == "") {
+ return null;
+ }
+ else {
+ if (this._alertState === AlertState.Displaying) {
+ Display.addAlertToQueue(text, alert_settings);
+ }
+ }
+ var settings = JSON.parse(alertSettings);
+ this._alertSettings = settings;
+ Display.setAlertText(text, settings.fontColor, settings.fontFace, settings.fontSize);
+ Display.setAlertLocation(settings.location);
+ /* Check if the alert is a queued alert */
+ if (Display._alertState !== AlertState.DisplayingFromQueue) {
+ Display._alertState = AlertState.Displaying;
+ }
+
+ alertBackground.addEventListener('transitionend', Display.alertTransitionEndEvent, false);
+ alertText.addEventListener('animationend', Display.alertAnimationEndEvent, false);
+
+ Display.showAlertBackground(settings.backgroundColor);
+ },
+ /**
+ * Add an alert to the alert queue
+ * @param {string} text - The alert text to be displayed
+ * @param {string} setttings - JSON object containing the settings for the alert
+ */
+ addAlertToQueue: function (text, settings) {
+ var alertObject = {text: text, settings: settings};
+ this._alerts.push(JSON.stringify(alertObject));
+ return null;
+ },
+ /**
+ * Set Alert Text
+ * @param {string} text - The alert text to display
+ */
+ setAlertText: function (text, color, fontFace, fontSize) {
+ var alertText = $("#alert")[0];
+ alertText.textContent = text;
+ alertText.style.color = color;
+ alertText.style.fontFamily = fontFace;
+ alertText.style.fontSize = fontSize + "pt";
+ },
+ /**
+ * The alertTransitionEndEvent called after a transition has ended
+ */
+ alertTransitionEndEvent: function (e) {
+ e.stopPropagation();
+ console.debug("Transition end event reached");
+ if (Display._transitionState === TransitionState.EntranceTransition) {
+ Display._transitionState = TransitionState.NoTransition;
+ Display.showAlertText(Display._alertSettings);
+ }
+ else if (Display._transitionState === TransitionState.ExitTransition) {
+ Display._transitionState = TransitionState.NoTransition;
+ Display.removeAlertLocation(Display._alertSettings.location);
+ Display.clearAlertSettings();
+ setTimeout(function () {
+ Display.showNextAlert();
+ }, AlertDelay.OnePointFiveSeconds);
+
+ }
+ },
+ /**
+ * The alertAnimationEndEvent called after an animation has ended
+ */
+ alertAnimationEndEvent: function (e) {
+ e.stopPropagation();
+ Display.hideAlertText();
+ },
+ /**
+ * Start background entrance transition for display of alert
+ * @param {string} hex_color - The background color of the alert
+ */
+ showAlertBackground: function (bg_color) {
+ var alertBackground = $("#alert-background")[0];
+ alertBackground.classList.add("show-bg");
+ alertBackground.style.backgroundColor = bg_color;
+ this._transitionState = TransitionState.EntranceTransition;
+ },
+ /**
+ * Set the location of the alert
+ * @param {int} location - Integer number with the location of the alert on screen
+ */
+ setAlertLocation: function (location) {
+ var alertContainer = $(".alert-container")[0];
+
+ switch (location) {
+ case AlertLocation.Top:
+ alertContainer.classList.add("top");
+ break;
+ case AlertLocation.Middle:
+ alertContainer.classList.add("middle");
+ break;
+ case AlertLocation.Bottom:
+ default:
+ alertContainer.classList.add("bottom");
+ break;
+ }
+ },
+ /**
+ * Remove the location class set after displaying the alert
+ * @param {int} location - Integer number with the location of the alert on screen
+ */
+ removeAlertLocation: function (location) {
+ var alertContainer = $(".alert-container")[0];
+ console.debug("The value of location for removal is: " + location);
+
+ switch (location) {
+ case AlertLocation.Top:
+ alertContainer.classList.remove("top");
+ break;
+ case AlertLocation.Middle:
+ alertContainer.classList.remove("middle");
+ break;
+ case AlertLocation.Bottom:
+ default:
+ alertContainer.classList.remove("bottom");
+ break;
+ }
+ },
+ /**
+ * Hide the alert background after the alert has been shown
+ */
+ hideAlertBackground: function () {
+ var alertBackground = $("#alert-background")[0];
+ alertBackground.classList.remove("show-bg");
+ this._transitionState = TransitionState.ExitTransition;
+ this._alertState = AlertState.NotDisplaying;
+ },
+ /**
+ * Sets the alert text styles correctly after the entrance transition has ended.
+ * @param {json} settings object - The settings to use for the animation
+ */
+ showAlertText: function (settings) {
+ var alertText = $("#alert")[0];
+
+ if (settings.scroll) {
+ var animationSettings = "alert-scrolling-text " + settings.timeout +
+ "s linear 0.6s " + settings.repeat + " normal";
+ alertText.style.animation = animationSettings;
+ Display._animationState = AnimationState.ScrollingText;
+ }
+ else {
+ Display._animationState = AnimationState.NonScrollingText;
+ alertText.classList.add("show-text");
+ setTimeout (function () {
+ Display._animationState = AnimationState.NoAnimation;
+ alertText.classList.add("hide-text");
+ alertText.classList.remove("show-text");
+ Display.hideAlertText();
+ }, settings.timeout * AlertDelay.OneSecond);
+ }
+ },
+ /**
+ * Reset styling and hide the alert text after displaying the animation
+ */
+ hideAlertText: function () {
+ var alertText = $('#alert')[0];
+ Display._animationState = AnimationState.NoAnimation;
+ alertText.style.animation = "";
+ Display.hideAlertBackground();
+ },
+ /**
+ * Display the next alert in the queue
+ */
+ showNextAlert: function () {
+ if (Display._alerts.length > 0) {
+ var alertObject = JSON.parse(this._alerts.shift());
+ this._alertState = AlertState.DisplayingFromQueue;
+ Display.alert(alertObject.text, alertObject.settings);
+ }
+ else {
+ return null;
+ }
+ },
+ /**
+ * Clears the alert settings after displaying an alert
+ */
+ clearAlertSettings: function () {
+ this._alertSettings = {};
+ },
+ /**
+ * Add a slide. If the slide exists but the HTML is different, update the slide.
* @param {string} verse - The verse number, e.g. "v1"
* @param {string} text - The HTML for the verse, e.g. "line1<br>line2"
* @param {string} footer_text - The HTML for the footer"
=== modified file 'openlp/core/display/window.py'
--- openlp/core/display/window.py 2019-06-21 22:09:36 +0000
+++ openlp/core/display/window.py 2019-07-01 17:51:00 +0000
@@ -397,8 +397,9 @@
self.scale = scale
self.run_javascript('Display.setScale({scale});'.format(scale=scale * 100))
- def alert(self, text, location):
+ def alert(self, text, settings):
"""
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 to prevent scrolling
=== modified file 'openlp/plugins/alerts/alertsplugin.py'
--- openlp/plugins/alerts/alertsplugin.py 2019-04-13 13:00:22 +0000
+++ openlp/plugins/alerts/alertsplugin.py 2019-07-01 17:51:00 +0000
@@ -126,7 +126,9 @@
'alerts/location': AlertLocation.Bottom,
'alerts/background color': '#660000',
'alerts/font color': '#ffffff',
- 'alerts/timeout': 5
+ 'alerts/timeout': 10,
+ 'alerts/repeat': 1,
+ 'alerts/scroll': True
}
=== modified file 'openlp/plugins/alerts/lib/alertsmanager.py'
--- openlp/plugins/alerts/lib/alertsmanager.py 2019-04-13 13:00:22 +0000
+++ openlp/plugins/alerts/lib/alertsmanager.py 2019-07-01 17:51:00 +0000
@@ -23,7 +23,9 @@
The :mod:`~openlp.plugins.alerts.lib.alertsmanager` module contains the part of the plugin which manages storing and
displaying of alerts.
"""
-from PyQt5 import QtCore
+import json
+
+from PyQt5 import QtCore, QtGui
from openlp.core.common.i18n import translate
from openlp.core.common.mixins import LogMixin, RegistryProperties
@@ -83,8 +85,26 @@
not Settings().value('core/display on monitor')):
return
text = self.alert_list.pop(0)
- alert_tab = self.parent().settings_tab
- self.live_controller.displays[0].alert(text, alert_tab.location)
+
+ # Get the rgb color format of the font & background hex colors from settings
+ rgb_font_color = self.hex_to_rgb(QtGui.QColor(Settings().value('alerts/font color')))
+ rgb_background_color = self.hex_to_rgb(QtGui.QColor(Settings().value('alerts/background color')))
+
+ # Put alert settings together in dict that will be passed to Display in Javascript
+ alert_settings = {
+ 'backgroundColor': rgb_background_color,
+ 'location': Settings().value('alerts/location'),
+ 'fontFace': Settings().value('alerts/font face'),
+ 'fontSize': Settings().value('alerts/font size'),
+ 'fontColor': rgb_font_color,
+ 'timeout': Settings().value('alerts/timeout'),
+ 'repeat': Settings().value('alerts/repeat'),
+ 'scroll': Settings().value('alerts/scroll')
+ }
+ self.live_controller.displays[0].alert(text, json.dumps(alert_settings))
+ # Check to see if we have a timer running.
+ # if self.timer_id == 0:
+ # self.timer_id = self.startTimer(int(alert_tab.timeout) * 1000)
def timerEvent(self, event):
"""
@@ -98,3 +118,13 @@
self.killTimer(self.timer_id)
self.timer_id = 0
self.generate_alert()
+
+ def hex_to_rgb(self, rgb_values):
+ """
+ Converts rgb color values from QColor to rgb string
+
+ :param rgb_values:
+ :return: rgb color string
+ :rtype: string
+ """
+ return "rgb(" + str(rgb_values.red()) + ", " + str(rgb_values.green()) + ", " + str(rgb_values.blue()) + ")"
=== modified file 'openlp/plugins/alerts/lib/alertstab.py'
--- openlp/plugins/alerts/lib/alertstab.py 2019-04-13 13:00:22 +0000
+++ openlp/plugins/alerts/lib/alertstab.py 2019-07-01 17:51:00 +0000
@@ -47,35 +47,56 @@
self.font_layout.addRow(self.font_label, self.font_combo_box)
self.font_color_label = QtWidgets.QLabel(self.font_group_box)
self.font_color_label.setObjectName('font_color_label')
- self.color_layout = QtWidgets.QHBoxLayout()
- self.color_layout.setObjectName('color_layout')
self.font_color_button = ColorButton(self.font_group_box)
self.font_color_button.setObjectName('font_color_button')
- self.color_layout.addWidget(self.font_color_button)
- self.color_layout.addSpacing(20)
- self.background_color_label = QtWidgets.QLabel(self.font_group_box)
- self.background_color_label.setObjectName('background_color_label')
- self.color_layout.addWidget(self.background_color_label)
- self.background_color_button = ColorButton(self.font_group_box)
- self.background_color_button.setObjectName('background_color_button')
- self.color_layout.addWidget(self.background_color_button)
- self.font_layout.addRow(self.font_color_label, self.color_layout)
+ self.font_layout.addRow(self.font_color_label, self.font_color_button)
self.font_size_label = QtWidgets.QLabel(self.font_group_box)
self.font_size_label.setObjectName('font_size_label')
self.font_size_spin_box = QtWidgets.QSpinBox(self.font_group_box)
self.font_size_spin_box.setObjectName('font_size_spin_box')
self.font_layout.addRow(self.font_size_label, self.font_size_spin_box)
- self.timeout_label = QtWidgets.QLabel(self.font_group_box)
+ self.left_layout.addWidget(self.font_group_box)
+ # Background Settings
+ self.background_group_box = QtWidgets.QGroupBox(self.left_column)
+ self.background_group_box.setObjectName('background_group_box')
+ self.background_layout = QtWidgets.QFormLayout(self.background_group_box)
+ self.background_layout.setObjectName('background_settings_layout')
+ self.background_color_label = QtWidgets.QLabel(self.background_group_box)
+ self.background_color_label.setObjectName('background_color_label')
+ self.background_color_button = ColorButton(self.background_group_box)
+ self.background_color_button.setObjectName('background_color_button')
+ self.background_layout.addRow(self.background_color_label,self.background_color_button)
+ self.left_layout.addWidget(self.background_group_box)
+ # Scroll Settings
+ self.scroll_group_box = QtWidgets.QGroupBox(self.left_column)
+ self.scroll_group_box.setObjectName('scroll_group_box')
+ self.scroll_group_layout = QtWidgets.QFormLayout(self.scroll_group_box)
+ self.scroll_group_layout.setObjectName('scroll_group_layout')
+ self.scroll_check_box = QtWidgets.QCheckBox(self.scroll_group_box)
+ self.scroll_check_box.setObjectName('scroll_check_box')
+ self.scroll_group_layout.addRow(self.scroll_check_box)
+ self.repeat_label = QtWidgets.QLabel(self.scroll_group_box)
+ self.repeat_label.setObjectName('repeat_label')
+ self.repeat_spin_box = QtWidgets.QSpinBox(self.scroll_group_box)
+ self.repeat_spin_box.setObjectName('repeat_spin_box')
+ self.scroll_group_layout.addRow(self.repeat_label, self.repeat_spin_box)
+ self.left_layout.addWidget(self.scroll_group_box)
+ # Other Settings
+ self.settings_group_box = QtWidgets.QGroupBox(self.left_column)
+ self.settings_group_box.setObjectName('settings_group_box')
+ self.settings_layout = QtWidgets.QFormLayout(self.settings_group_box)
+ self.settings_layout.setObjectName('settings_layout')
+ self.timeout_label = QtWidgets.QLabel(self.settings_group_box)
self.timeout_label.setObjectName('timeout_label')
- self.timeout_spin_box = QtWidgets.QSpinBox(self.font_group_box)
+ self.timeout_spin_box = QtWidgets.QSpinBox(self.settings_group_box)
self.timeout_spin_box.setMaximum(180)
self.timeout_spin_box.setObjectName('timeout_spin_box')
- self.font_layout.addRow(self.timeout_label, self.timeout_spin_box)
+ self.settings_layout.addRow(self.timeout_label, self.timeout_spin_box)
self.vertical_label, self.vertical_combo_box = create_valign_selection_widgets(self.font_group_box)
self.vertical_label.setObjectName('vertical_label')
self.vertical_combo_box.setObjectName('vertical_combo_box')
- self.font_layout.addRow(self.vertical_label, self.vertical_combo_box)
- self.left_layout.addWidget(self.font_group_box)
+ self.settings_layout.addRow(self.vertical_label, self.vertical_combo_box)
+ self.left_layout.addWidget(self.settings_group_box)
self.left_layout.addStretch()
self.preview_group_box = QtWidgets.QGroupBox(self.right_column)
self.preview_group_box.setObjectName('preview_group_box')
@@ -92,16 +113,22 @@
self.font_combo_box.activated.connect(self.on_font_combo_box_clicked)
self.timeout_spin_box.valueChanged.connect(self.on_timeout_spin_box_changed)
self.font_size_spin_box.valueChanged.connect(self.on_font_size_spin_box_changed)
+ self.repeat_spin_box.valueChanged.connect(self.on_repeat_spin_box_changed)
+ self.scroll_check_box.toggled.connect(self.scroll_check_box_toggled)
def retranslate_ui(self):
- self.font_group_box.setTitle(translate('AlertsPlugin.AlertsTab', 'Font'))
+ self.font_group_box.setTitle(translate('AlertsPlugin.AlertsTab', 'Font Settings'))
self.font_label.setText(translate('AlertsPlugin.AlertsTab', 'Font name:'))
self.font_color_label.setText(translate('AlertsPlugin.AlertsTab', 'Font color:'))
self.background_color_label.setText(UiStrings().BackgroundColorColon)
self.font_size_label.setText(translate('AlertsPlugin.AlertsTab', 'Font size:'))
self.font_size_spin_box.setSuffix(' {unit}'.format(unit=UiStrings().FontSizePtUnit))
+ self.background_group_box.setTitle(translate('AlertsPlugin.AlertsTab', 'Background Settings'))
+ self.settings_group_box.setTitle(translate('AlertsPlugin.AlertsTab', 'Other Settings'))
self.timeout_label.setText(translate('AlertsPlugin.AlertsTab', 'Alert timeout:'))
self.timeout_spin_box.setSuffix(' {unit}'.format(unit=UiStrings().Seconds))
+ self.repeat_label.setText(translate('AlertsPlugin.AlertsTab', 'Repeat (no. of times):'))
+ self.scroll_check_box.setText(translate('AlertsPlugin.AlertsTab', 'Enable Scrolling'))
self.preview_group_box.setTitle(UiStrings().Preview)
self.font_preview.setText(UiStrings().OpenLP)
@@ -140,6 +167,24 @@
self.font_size = self.font_size_spin_box.value()
self.update_display()
+ def on_repeat_spin_box_changed(self):
+ """
+ The repeat spin box has changed
+ """
+ self.repeat = self.repeat_spin_box.value()
+ self.changed = True
+
+ def scroll_check_box_toggled(self):
+ """
+ The scrolling checkbox has been toggled
+ """
+ if self.scroll_check_box.isChecked():
+ self.repeat_spin_box.setEnabled(True)
+ else:
+ self.repeat_spin_box.setEnabled(False)
+ self.scroll = self.scroll_check_box.isChecked()
+ self.changed = True
+
def load(self):
"""
Load the settings into the UI.
@@ -152,12 +197,17 @@
self.background_color = settings.value('background color')
self.font_face = settings.value('font face')
self.location = settings.value('location')
+ self.repeat = settings.value('repeat')
+ self.scroll = settings.value('scroll')
settings.endGroup()
self.font_size_spin_box.setValue(self.font_size)
self.timeout_spin_box.setValue(self.timeout)
self.font_color_button.color = self.font_color
self.background_color_button.color = self.background_color
+ self.repeat_spin_box.setValue(self.repeat)
+ self.repeat_spin_box.setEnabled(self.scroll)
self.vertical_combo_box.setCurrentIndex(self.location)
+ self.scroll_check_box.setChecked(self.scroll)
font = QtGui.QFont()
font.setFamily(self.font_face)
self.font_combo_box.setCurrentFont(font)
@@ -181,6 +231,8 @@
settings.setValue('timeout', self.timeout)
self.location = self.vertical_combo_box.currentIndex()
settings.setValue('location', self.location)
+ settings.setValue('repeat', self.repeat)
+ settings.setValue('scroll', self.scroll_check_box.isChecked())
settings.endGroup()
if self.changed:
self.settings_form.register_post_process('update_display_css')
=== modified file 'package.json'
--- package.json 2019-04-13 13:00:22 +0000
+++ package.json 2019-07-01 17:51:00 +0000
@@ -15,7 +15,7 @@
"phantomjs-prebuilt": "^2.1.16"
},
"scripts": {
- "test": "karma start"
+ "test": "karma start --single-run"
},
"author": "OpenLP Developers",
"license": "GPL-3.0-or-later",
=== modified file 'tests/js/test_display.js'
--- tests/js/test_display.js 2019-01-16 06:15:21 +0000
+++ tests/js/test_display.js 2019-07-01 17:51:00 +0000
@@ -18,6 +18,14 @@
it("AudioState should exist", function () {
expect(AudioState).toBeDefined();
});
+
+ it("TransitionState should exist", function(){
+ expect(TransitionState).toBeDefined();
+ });
+
+ it("AnimationState should exist", function(){
+ expect(AnimationState).toBeDefined();
+ });
});
describe("The function", function () {
@@ -138,6 +146,343 @@
Display.goToSlide("v1");
expect(Reveal.slide).toHaveBeenCalledWith(0);
});
+
+ it("should have an alert() method", function () {
+ expect(Display.alert).toBeDefined();
+ });
+
+});
+
+describe("Display.alert", function () {
+ var alertBackground, alertText, settings;
+
+ beforeEach(function () {
+ document.body.innerHTML = "";
+ alertContainer = document.createElement("div");
+ alertContainer.setAttribute("class", "alert-container");
+ document.body.appendChild(alertContainer);
+ alertBackground = document.createElement("div");
+ alertBackground.setAttribute("id", "alert-background");
+ alertContainer.appendChild(alertBackground);
+ alertText = document.createElement("span");
+ alertText.setAttribute("id","alert");
+ alertBackground.appendChild(alertText);
+ settings = '{ \
+ "location": 1, "fontFace": "Segoe UI, Tahoma, Geneva, Verdana, sans-serif", \
+ "fontSize": 40, "fontColor": "#ffffff", "backgroundColor": "#660000", \
+ "timeout": 5, "repeat": 1, "scroll": true \
+ }';
+ });
+
+ it("should return null if called without any text", function () {
+ expect(Display.alert("", settings)).toBeNull();
+ });
+
+ it("should set the correct alert text", function () {
+ spyOn(Display, "setAlertText");
+ spyOn(Display, "setAlertLocation");
+ Display.alert("OPEN-LP-3.0 Alert Test", settings);
+
+ expect(Display.setAlertText).toHaveBeenCalled();
+ expect(Display.setAlertLocation).toHaveBeenCalled();
+ });
+
+ it("should call the addAlertToQueue method if an alert is displaying", function () {
+ spyOn(Display, "addAlertToQueue");
+ Display._alerts = [];
+ Display._alertState = AlertState.Displaying;
+ var text = "Testing alert queue";
+
+ Display.alert(text, settings);
+
+ expect(Display.addAlertToQueue).toHaveBeenCalledWith(text, settings);
+ });
+
+ it("should set the alert settings correctly", function() {
+ Display.alert("Testing settings", settings);
+
+ expect(Display._alertSettings).toEqual(JSON.parse(settings));
+ });
+});
+
+describe("Display.showAlertBackground", function () {
+
+ var alertBackground, bg_color;
+ beforeEach(function () {
+ document.body.innerHTML = "";
+ bg_color = "rgb(102, 0, 0)";
+ alertBackground = document.createElement("div");
+ alertBackground.setAttribute("id", "alert-background");
+ alertBackground.setAttribute("class", "bg-default");
+ document.body.appendChild(alertBackground);
+ });
+
+ it("should set the correct transition state", function () {
+ Display.showAlertBackground(bg_color);
+ expect(Display._transitionState).toEqual(TransitionState.EntranceTransition);
+ });
+
+ it("should apply the styles correctly when showAlertBackground is called", function () {
+ Display.showAlertBackground(bg_color);
+
+ expect(alertBackground.style.backgroundColor).toEqual(bg_color);
+ expect(alertBackground.className).toEqual("bg-default show-bg");
+ });
+});
+
+describe("Display.hideAlertBackground", function () {
+ var alertBackground;
+ beforeEach( function() {
+ document.body.innerHTML = "";
+ alertBackground = document.createElement("div");
+ alertBackground.setAttribute("id", "alert-background");
+ alertBackground.setAttribute("class", "bg-default show-bg");
+ document.body.appendChild(alertBackground);
+ });
+
+ it("reset the background to default once an alert has been displayed", function() {
+ Display.hideAlertBackground();
+
+ expect(Display._transitionState).toEqual(TransitionState.ExitTransition);
+ expect(Display._alertState).toEqual(AlertState.NotDisplaying);
+ expect(alertBackground.className).toEqual("bg-default");
+ });
+});
+
+describe("Display.setAlertText", function() {
+ var alertText;
+ beforeEach( function() {
+ document.body.innerHTML = "";
+ alertText = document.createElement("span");
+ alertText.setAttribute("id", "alert");
+ document.body.appendChild(alertText);
+ });
+ it("should set the alert text correctly", function () {
+ Display.setAlertText("OpenLP Alert Text", "#ffffff", "Tahoma", 40);
+
+ expect(alertText.textContent).toEqual("OpenLP Alert Text");
+ expect(alertText.style.color).toEqual("rgb(255, 255, 255)");
+ expect(alertText.style.fontFamily).toEqual("Tahoma");
+ expect(alertText.style.fontSize).toEqual("40pt");
+ });
+});
+
+describe("Display.setAlertLocation", function() {
+ beforeEach(function() {
+ document.body.innerHTML = "";
+ alertContainer = document.createElement("div");
+ alertContainer.setAttribute("class", "alert-container");
+ document.body.appendChild(alertContainer);
+ });
+ it("should set the correct class when location is top of the page", function () {
+ Display.setAlertLocation(0);
+
+ expect(alertContainer.className).toEqual("alert-container top");
+ });
+
+ it("should set the correct class when location is middle of the page", function () {
+ Display.setAlertLocation(1);
+
+ expect(alertContainer.className).toEqual("alert-container middle");
+ });
+
+ it("should set the correct class when location is bottom of the page", function () {
+ Display.setAlertLocation(2);
+
+ expect(alertContainer.className).toEqual("alert-container bottom");
+ });
+});
+
+describe("Display.removeAlertLocation", function () {
+ beforeEach(function() {
+ document.body.innerHTML = "";
+ alertContainer = document.createElement("div");
+ alertContainer.setAttribute("class", "alert-container");
+ document.body.appendChild(alertContainer);
+ });
+ it("should remove the correct class when location is top of the page", function () {
+ alertContainer.classList.add("top");
+ Display.removeAlertLocation(0);
+
+ expect(alertContainer.className).toEqual("alert-container");
+ });
+
+ it("should remove the correct class when location is middle of the page", function () {
+ alertContainer.classList.add("middle");
+ Display.removeAlertLocation(1);
+
+ expect(alertContainer.className).toEqual("alert-container");
+ });
+
+ it("should remove the correct class when location is bottom of the page", function () {
+ alertContainer.classList.add("bottom");
+ Display.removeAlertLocation(2);
+
+ expect(alertContainer.className).toEqual("alert-container");
+ });
+});
+
+describe("Display.showAlertText", function () {
+ var alertText, settings;
+ beforeEach(function () {
+ document.body.innerHTML = "";
+ alertText = document.createElement("span");
+ alertText.setAttribute("id", "alert");
+ document.body.appendChild(alertText);
+ settings = {
+ "location": 2, "fontFace": "Tahoma", "fontSize": 40,
+ "fontColor": "rgb(255, 255, 255)", "backgroundColor": "rgb(102, 0, 0)",
+ "timeout": 0.01, "repeat": 1, "scroll": true
+ };
+ Display._transitionState = TransitionState.EntranceTransition;
+ });
+
+ it("should set the correct animation when text is set to scroll)", function () {
+ Display.showAlertText(settings);
+
+ expect(alertText.style.animation).toEqual("alert-scrolling-text " + settings.timeout + "s linear 0.6s 1 normal");
+ expect(Display._animationState).toEqual(AnimationState.ScrollingText);
+ });
+
+ it("should set the correct styles when text is not scrolling", function (done) {
+ settings.scroll = false;
+ Display._transitionState = TransitionState.EntranceTransition;
+ spyOn(Display, "hideAlertText");
+ Display.showAlertText(settings);
+
+ // expect(alertText.style.animation).toEqual("");
+ expect(Display._animationState).toEqual(AnimationState.NonScrollingText);
+ expect(alertText.classList.contains('show-text')).toBe(true);
+ setTimeout (function () {
+ expect(Display._animationState).toEqual(AnimationState.NoAnimation);
+ expect(Display.hideAlertText).toHaveBeenCalled();
+ done();
+ }, settings.timeout * 1000);
+ });
+});
+
+describe("Display.hideAlertText", function() {
+ var alertBackground, alertText, keyframeStyle;
+ beforeEach(function () {
+ document.body.innerHTML = "";
+ alertBackground = document.createElement("div");
+ alertBackground.setAttribute("id", "alert-background");
+ alertBackground.setAttribute("class", "bg-default show-bg");
+ document.body.appendChild(alertBackground);
+ alertText = document.createElement("span");
+ alertText.setAttribute("id", "alert");
+ alertText.style.opacity = 1;
+ alertText.style.animation = "alert-scrolling-text 5s linear 0s 1 bg-default";
+ alertBackground.appendChild(alertText);
+ Display._animationState = AnimationState.ScrollingText;
+ });
+
+ it("should reset the text styles and animation state after the text has scrolled", function() {
+ spyOn(Display, "hideAlertBackground");
+ Display.hideAlertText();
+
+ expect(alertText.style.animation).toEqual("");
+ expect(Display._animationState).toEqual(AnimationState.NoAnimation);
+ });
+
+ it("should call the hideAlertBackground method", function() {
+ spyOn(Display, "hideAlertBackground");
+ Display.hideAlertText();
+
+
+ expect(Display.hideAlertBackground).toHaveBeenCalled();
+ });
+});
+
+describe("Display.addAlertToQueue", function () {
+ it("should add an alert to the queue if one is displaying already", function() {
+ Display._alerts = [];
+ Display._alertState = AlertState.Displaying;
+ settings = '{ \
+ "location": 1, "fontFace": "Segoe UI, Tahoma, Geneva, Verdana, sans-serif", \
+ "fontSize": 40, "fontColor": "#ffffff", "backgroundColor": "#660000", \
+ "timeout": 5, "repeat": 1, "scrolling_text": true \
+ }';
+ var alertObject = {text: "Testing alert queue", settings: settings};
+ var queuedAlert = JSON.stringify(alertObject);
+
+ Display.addAlertToQueue("Testing alert queue", settings);
+
+ expect(Display._alerts.length).toEqual(1);
+ expect(Display._alerts[0]).toEqual(queuedAlert);
+ });
+});
+
+describe("Display.showNextAlert", function () {
+ Display.showNextAlert();
+
+ it("should return null if there are no alerts in the queue", function () {
+ Display._alerts = [];
+ Display.showNextAlert();
+
+ expect(Display.showNextAlert()).toBeNull();
+ });
+
+ it("should call the alert function correctly if there is an alert in the queue", function () {
+ var settings = {
+ "location": 2, "fontFace": "Tahoma", "fontSize": 40,
+ "fontColor": "rgb(255, 255, 255)", "backgroundColor": "rgb(102, 0, 0)",
+ "timeout": 5, "repeat": 1, "scrolling_text": true
+ };
+ var alertObject = {text: "Queued Alert", settings: settings};
+ Display._alerts.push(JSON.stringify(alertObject));
+ spyOn(Display, "alert");
+ Display.showNextAlert();
+
+ expect(Display.alert).toHaveBeenCalled();
+ expect(Display.alert).toHaveBeenCalledWith("Queued Alert",alertObject.settings);
+ });
+});
+
+describe("Display.alertTransitionEndEvent", function() {
+ beforeEach( function() {
+
+ });
+
+ it("should set the correct state and call showAlertText after the alert entrance transition", function() {
+ var fake_settings = {test: "fake_settings"};
+ var e = jasmine.createSpyObj('e', ['stopPropagation']);
+ Display._alertSettings = fake_settings;
+ spyOn(Display, "showAlertText");
+ Display._transitionState = TransitionState.EntranceTransition;
+ Display.alertTransitionEndEvent();
+
+ expect(Display._transitionState).toEqual(TransitionState.NoTransition);
+ expect(Display.showAlertText).toHaveBeenCalledWith(fake_settings);
+ });
+
+ it("should set the correct state after the alert exit transition", function() {
+ spyOn(Display, "showNextAlert");
+ Display._transitionState = TransitionState.ExitTransition;
+ Display.alertTransitionEndEvent();
+
+ expect(Display._transitionState).toEqual(TransitionState.NoTransition);
+ });
+});
+
+describe("Display.alertAnimationEndEvent", function () {
+ it("should call the hideAlertText method", function() {
+ spyOn(Display, "hideAlertText");
+
+ Display.alertAnimationEndEvent();
+
+ expect(Display.hideAlertText).toHaveBeenCalled();
+ });
+});
+
+describe("Display.clearAlertSettings", function () {
+ it("should clear the alert settings once an alert has been displayed", function () {
+ var fake_settings = {test: "fake_settings"};
+ Display._alertSettings = fake_settings;
+ Display.clearAlertSettings();
+
+ expect(Display._alertSettings).toEqual({});
+ });
});
describe("Display.addTextSlide", function () {
@@ -249,6 +594,7 @@
};
spyOn(Display, "reinit");
+ spyOn(Reveal, "slide");
Display.setTextSlides(slides);
Display.setTheme(theme);
Follow ups