← Back to team overview

openlp-dev team mailing list archive

[Merge] lp:~ic90/openlp/animated-alerts into lp:~openlp-dev/openlp/webengine-migrate

 

Nico Opiyo has proposed merging lp:~ic90/openlp/animated-alerts into lp:~openlp-dev/openlp/webengine-migrate.

Commit message:
Added transitions and animations to the alerts.

Requested reviews:
  OpenLP Development (openlp-dev)

For more details, see:
https://code.launchpad.net/~ic90/openlp/animated-alerts/+merge/362833

I have fixed the tests to test the various components added to the UI and also made some slight adjustments to the entrance transition and fixed a glitch when an alert is first displayed on opening the program.
-- 
Your team OpenLP Development is requested to review the proposed merge of lp:~ic90/openlp/animated-alerts into lp:~openlp-dev/openlp/webengine-migrate.
=== modified file 'openlp/core/display/html/display.html'
--- openlp/core/display/html/display.html	2018-10-12 19:51:51 +0000
+++ openlp/core/display/html/display.html	2019-02-06 21:00:42 +0000
@@ -24,14 +24,89 @@
       visibility: visible;
       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>
     <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="reveal">
       <div id="global-background" class="slide-background present" data-loaded="true"></div>
+      <div id="alert-background"><p id="alert">Testing alerts</p></div>
       <div class="slides"></div>
       <div class="footer"></div>
     </div>

=== modified file 'openlp/core/display/html/display.js'
--- openlp/core/display/html/display.js	2019-02-05 21:26:30 +0000
+++ openlp/core/display/html/display.js	2019-02-06 21:00:42 +0000
@@ -53,6 +53,31 @@
 };
 
 /**
+ * Transition state enumeration
+ */
+
+var TransitionState = {
+   EntranceTransition: "entranceTransition",
+   NoTransition: "noTransition",
+   ExitTransition: "exitTransition"
+};
+
+/**
+ * Animation state enumeration
+ */
+var AnimationState = {
+  NoAnimation: "noAnimation",
+  ScrollingAnimation: "scrollingAnimation",
+  FadeInAnimation: "fadeInAnimation",
+  FadeOutAnimation: "fadeOutAnimation"
+};
+
+/**
+ *
+ * @param {Location} selector
+ */
+
+/**
  * 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
@@ -132,6 +157,10 @@
 }
 
 /**
+ *
+ */
+
+/**
  * An audio player with a play list
  */
 var AudioPlayer = function (audioElement) {
@@ -249,6 +278,8 @@
  */
 var Display = {
   _slides: {},
+  _transitionState: TransitionState.NoTransition,
+  _animationState: AnimationState.NoAnimation,
   _revealConfig: {
     margin: 0.0,
     minScale: 1.0,
@@ -372,15 +403,111 @@
    * @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);
+  alert: function (text, location) {
+    console.debug(" alert text: " + text + ", location: " + location);
+
+    if(text == ""){
+      return null;
+    }
+
+    var alertBackground = $("#alert-background")[0];
+    var alertText = $("#alert")[0];
+
+    alertText.innerHTML = text;
+
+    /* Bring in the transition background */
+    Display._transitionState = Display.doEntranceTransition(location);
+
+    alertBackground.addEventListener('transitionend', function(e){
+      e.stopPropagation();
+      if(Display._transitionState == TransitionState.EntranceTransition){
+        alertText.style.visibility = "visible";
+        alertText.classList.add("horizontal-scroll-animation");
+      }else if(Display._transitionState == TransitionState.ExitTransition){
+        Display._transitionState = TransitionState.NoTransition;
+        alertBackground.style.visibility = "hidden";
+        alertBackground.classList.remove("middle-exit-animation");
+      }
+    });
+
+    alertBackground.addEventListener('animationend',function(){
+
+      console.debug("Noticed an animation has ended. The animation state is: ", Display._animationState);
+      if(Display._animationState == AnimationState.FadeInAnimation){
+        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");
+        Display._animationState = AnimationState.NoAnimation;
+        Display._transitionState = Display.doExitTransition(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;
-},
-
+    return location;
+  },
+
+  /**
+   * Start background entrance transition for display of alert
+   * @param {string} location - String showing the location of the alert on screen
+   */
+  doEntranceTransition: function (location){
+    var alertBackground = $("#alert-background")[0];
+
+    switch(location){
+      case "0":
+        alertBackground.style.top = '0';
+        alertBackground.style.transition = "2s linear";
+        alertBackground.style.height = "25%";
+        break;
+      case "1":
+        alertBackground.style.top = ((window.innerHeight - alertBackground.clientHeight) / 2)
+            + 'px';
+        alertBackground.style.height = "25%";
+        alertBackground.classList.add("middle-entrance-animation");
+        Display._animationState = AnimationState.FadeInAnimation;
+        break;
+      case "2":
+      default:
+        alertBackground.style.bottom = '0';
+        alertBackground.style.transition= "2s linear";
+        alertBackground.style.height = "25%";
+        break;
+    }
+    alertBackground.style.visibility = "visible";
+    return TransitionState.EntranceTransition;
+
+  },
+
+  /**
+   * Start background exit transition once alert has been displayed
+   * @param {string} location - Integer showing the location of the alert on screen
+   */
+  doExitTransition: function(location){
+
+    var alertBackground = $("#alert-background")[0];
+
+    if(location == "0" || location == "2"){
+      alertBackground.style.height = "0%";
+      alertBackground.style.transition = '2s linear';
+    }else if(location == "1"){
+      alertBackground.classList.add("middle-exit-animation");
+      alertBackground.style.height = "0%";
+      Display._animationState = AnimationState.FadeOutAnimation;
+    }
+
+    return TransitionState.ExitTransition;
+  },
   /**
    * Add a slides. If the slide exists but the HTML is different, update the slide.
    * @param {string} verse - The verse number, e.g. "v1"

=== modified file 'openlp/core/display/window.py'
--- openlp/core/display/window.py	2018-12-06 20:26:35 +0000
+++ openlp/core/display/window.py	2019-02-06 21:00:42 +0000
@@ -401,4 +401,4 @@
         """
         Set an alert
         """
-        self.run_javascript('Display.alert({text}, {location});'.format(text=text, location=location))
+        self.run_javascript('Display.alert("{text}", "{location}");'.format(text=text, location=location))

=== 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-02-06 21:00:42 +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,7 +146,150 @@
     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,alert;
+
+    beforeEach(function(){
+        document.body.innerHTML = "";
+        alertBackground = document.createElement("div");
+        alertBackground.setAttribute("id", "alert-background");
+        document.body.appendChild(alertBackground);
+        alert = document.createElement("p");
+        alert.setAttribute("id","alert");
+        alertBackground.appendChild(alert);
+    });
+
+   it("should return null if called without any text", function(){
+    expect(Display.alert("","2")).toBeNull();
+   });
+
+   it("should set correct alert text", function(){
+    Display.alert("OPEN-LP-3.0 Alert Test", "2");
+    expect(alert.innerHTML).toEqual("OPEN-LP-3.0 Alert Test");
+   });
+
+   it("should set the correct alert position", function(){
+    expect(Display.alert("Alert Location Test","2")).toEqual("2");
+   });
+
+});
+
+describe("The doEntranceTransition", function(){
+
+    var alertBackground;
+
+    beforeEach(function(){
+        document.body.innerHTML = "";
+        alertBackground = document.createElement("div");
+        alertBackground.setAttribute("id", "alert-background");
+        document.body.appendChild(alertBackground);
+        alertBackground.style.top = '0px';
+        alertBackground.style.height = "0%";
+    });
+
+    it("should move the alert background to the top of the page", function(){
+        Display.doEntranceTransition("0");
+        expect(alertBackground.style.top).toEqual('0px');
+    });
+
+    it("should move the alert background to the middle of the page", function(){
+        Display.doEntranceTransition("1");
+        var middlePosition = ((window.innerHeight - alertBackground.clientHeight) / 2) + 'px';
+        expect(alertBackground.style.top).toEqual(middlePosition);
+    });
+
+    it("should move the alert background to the bottom of the page", function(){
+        Display.doEntranceTransition("2");
+        expect(alertBackground.style.bottom).toEqual('0px');
+    });
+
+    it("should have a transition set when position is set to top", function(){
+        Display.doEntranceTransition("0");
+        expect(alertBackground.style.transition).toEqual("2s linear");
+    });
+
+    it("should have a transition set when position is set to bottom", function(){
+        Display.doEntranceTransition("2");
+        expect(alertBackground.style.transition).toEqual("2s linear");
+    });
+
+    it("should have an animation class when position is set to middle", function(){
+        Display.doEntranceTransition("1");
+        expect(alertBackground.classList.contains("middle-entrance-animation"));
+    });
+
+    it("should have the height set to 25% when the position is top", function(){
+        Display.doEntranceTransition("0");
+        expect(alertBackground.style.height).toEqual("25%");
+    });
+
+    it("should have the height set to 25% when the position is middle", function(){
+        Display.doEntranceTransition("1");
+        expect(alertBackground.style.height).toEqual("25%");
+    });
+
+    it("should have the height set to 25% when the position is bottom", function(){
+        Display.doEntranceTransition("2");
+        expect(alertBackground.style.height).toEqual("25%");
+    });
+
+    it("should make the alert background visible", function(){
+        Display.doEntranceTransition();
+        expect(alertBackground.style.visibility).toEqual("visible");
+    });
+});
+
+describe("The doExitTransition", function(){
+    var alertBackground;
+
+    beforeEach(function(){
+        document.body.innerHTML = "";
+        alertBackground = document.createElement("div");
+        alertBackground.setAttribute("id", "alert-background");
+        document.body.appendChild(alertBackground);
+
+    });
+
+    it("should make the height of the alert zero when position is top", function(){
+        Display.doExitTransition("0");
+        expect(alertBackground.style.height).toEqual('0%');
+    });
+
+    it("should make the height of the alert zero when position is bottom", function(){
+        Display.doExitTransition("2");
+        expect(alertBackground.style.height).toEqual('0%');
+    });
+
+    it("should make the height of the alert zero when position is middle", function(){
+        Display.doExitTransition("2");
+        expect(alertBackground.style.height).toEqual('0%');
+    });
+
+    it("should have a transition set when position is set to top", function(){
+        Display.doExitTransition("0");
+        expect(alertBackground.style.transition).toEqual("2s linear");
+    });
+
+    it("should have a transition set when position is set to bottom", function(){
+        Display.doExitTransition("2");
+        expect(alertBackground.style.transition).toEqual("2s linear");
+    });
+
+    it("should have an animation class when position is set to middle", function(){
+        Display.doExitTransition("1");
+        expect(alertBackground.classList.contains("middle-exit-animation"));
+    });
+
+
+});
+
 
 describe("Display.addTextSlide", function () {
   beforeEach(function() {


Follow ups