colinskow / angular-electron-dream-starter

:tada: An Angular Electron Starter kit featuring Webpack, Angular 4 (Router, Http, Forms, Services, ngrx, Tests, E2E, Coverage), Karma, Spectron, Jasmine, Istanbul, and TypeScript
MIT License
162 stars 54 forks source link

Splash screen when main window is loading #24

Closed celestale closed 6 years ago

celestale commented 6 years ago

Is it possible to create a Splash screen when main window is loading in this starter project?

I have tried to create a loading.html which is in the same directory level with index.html

src  
| ------- loading.html
| ------- index.html
| ------- electron
          | ------- index.ts

loading.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
  <h1>TEST SPLASH SCREEN WHEN APP START UP</h1>
</body>
</html>

index.ts

let win,
  windowParams = {
    frame: false,
    width: 1024,
    height: 700,
    minWidth: 1024,
    minHeight: 700,
    icon: __dirname + 'neutron.png',
    show: false,
    webPreferences: {
      devTools: true
    }
  };

let loadingScreen,
  loadingParams = {
    frame: false,
    width: 400,
    height: 200,
    moveable: false,
    resizable: false,
    backgroundColor: '#34343B',
    show: true,
    webPreferences: {
      devTools: true
    }
  };
function createWindow() {
  win = new BrowserWindow(windowParams);

  win.webContents.on('did-finish-load', () => {
    win.show();

    if (loadingScreen) {
      loadingScreen.close();
    }
  });

  // and load the index.html of the app.
  win.loadURL(`file://${__dirname}/index.html`);
}

function createLoadingScreen() {
  loadingScreen = new BrowserWindow(Object.assign(loadingParams, { parent: win }));
  loadingScreen.loadURL(`file://${__dirname}/loading.html`);
  loadingScreen.on('closed', () => loadingScreen = null);

  loadingScreen.webContents.on('did-finish-load', () => {
    loadingScreen.show();
  });
}

app.on('ready', () => {
  createLoadingScreen();
  createWindow();
});

loading.html did not load but I could see the color of backgroundColor: '#34343B'.

Did i missed out any steps to create the loading window?

colinskow commented 6 years ago

I think what's happening is that your main screen is loading so fast the loading screen is unloaded before it is visible. What I'd suggest is instead of launching a new Electron window, create a simple static splash screen inside your tag in src/index.html. You can also look into Angular App Shell to accomplish this.

Kaffiend commented 6 years ago

This can also be accomplished using no additional window object and change to the

mainWindow.once('ready-to-show', () => {
     mainWindow.show()
 })

event and some css and js script tag in the index.html something like below. you can read more on this even here

@keyframes fadeInLoad {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.sk-folding-cube {
  margin: 20px auto;
  width: 40px;
  height: 40px;
  position: relative;
  -webkit-transform: rotateZ(45deg);
          transform: rotateZ(45deg);
}

.sk-folding-cube .sk-cube {
  float: left;
  width: 50%;
  height: 50%;
  position: relative;
  -webkit-transform: scale(1.1);
      -ms-transform: scale(1.1);
          transform: scale(1.1);
}
.sk-folding-cube .sk-cube:before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: #fff;
  -webkit-animation: sk-foldCubeAngle 2.4s infinite linear both;
          animation: sk-foldCubeAngle 2.4s infinite linear both;
  -webkit-transform-origin: 100% 100%;
      -ms-transform-origin: 100% 100%;
          transform-origin: 100% 100%;
}
.sk-folding-cube .sk-cube2 {
  -webkit-transform: scale(1.1) rotateZ(90deg);
          transform: scale(1.1) rotateZ(90deg);
}
.sk-folding-cube .sk-cube3 {
  -webkit-transform: scale(1.1) rotateZ(180deg);
          transform: scale(1.1) rotateZ(180deg);
}
.sk-folding-cube .sk-cube4 {
  -webkit-transform: scale(1.1) rotateZ(270deg);
          transform: scale(1.1) rotateZ(270deg);
}
.sk-folding-cube .sk-cube2:before {
  -webkit-animation-delay: 0.3s;
          animation-delay: 0.3s;
}
.sk-folding-cube .sk-cube3:before {
  -webkit-animation-delay: 0.6s;
          animation-delay: 0.6s;
}
.sk-folding-cube .sk-cube4:before {
  -webkit-animation-delay: 0.9s;
          animation-delay: 0.9s;
}
@-webkit-keyframes sk-foldCubeAngle {
  0%, 10% {
    -webkit-transform: perspective(140px) rotateX(-180deg);
            transform: perspective(140px) rotateX(-180deg);
    opacity: 0;
  } 25%, 75% {
    -webkit-transform: perspective(140px) rotateX(0deg);
            transform: perspective(140px) rotateX(0deg);
    opacity: 1;
  } 90%, 100% {
    -webkit-transform: perspective(140px) rotateY(180deg);
            transform: perspective(140px) rotateY(180deg);
    opacity: 0;
  }
}

@keyframes sk-foldCubeAngle {
  0%, 10% {
    -webkit-transform: perspective(140px) rotateX(-180deg);
            transform: perspective(140px) rotateX(-180deg);
    opacity: 0;
  } 25%, 75% {
    -webkit-transform: perspective(140px) rotateX(0deg);
            transform: perspective(140px) rotateX(0deg);
    opacity: 1;
  } 90%, 100% {
    -webkit-transform: perspective(140px) rotateY(180deg);
            transform: perspective(140px) rotateY(180deg);
    opacity: 0;
  }
}

and in the index.html

<div id="pre-bootstrap-container">
    <script type="text/javascript">
      document.addEventListener('appready', handleAppReady);

      function handleAppReady(event) {
        var preBootstrapContainer = document.getElementById("pre-bootstrap-container");
        var preBootstrap = document.getElementById("pre-bootstrap");
        preBootstrap.className = "loaded";
        setTimeout(
          function removeLoadingScreen() {
            preBootstrapContainer.parentNode.removeChild(preBootstrapContainer);
          }, 300
        );
      }
    </script>
<div id="pre-bootstrap">
    <img src="path/toimage" alt="image alt">
    <h1>Splash heading</h1>
    <div class="sk-folding-cube">
      <div class="sk-cube1 sk-cube"></div>
      <div class="sk-cube2 sk-cube"></div>
      <div class="sk-cube4 sk-cube"></div>
      <div class="sk-cube3 sk-cube"></div>
    </div> 
</div>
Kaffiend commented 6 years ago

if you dont want to use a timeout to remove the loading element you will have to create your own custom dom event to be triggered when angular is done bootstrapping which would be nothing more than an angular service, like below

import { DOCUMENT } from '@angular/platform-browser';
import { Inject } from '@angular/core';
import { Injectable } from '@angular/core';

@Injectable()

export class DOMEvents {
  private doc: Document;

  constructor(@Inject(DOCUMENT) doc: any) {
    this.doc = doc;
  }

  public triggerOnDocument(eventType: string) : Event {
    return (this.triggerOnElement(this.doc, eventType));
  }

  public triggerOnElement(
      nativeElement: any,
      eventType: string,
      bubbles: boolean = true,
      cancelable: boolean = false
    ) : Event {
    let customEvent: any = this.createEvent(eventType, bubbles, cancelable);
    nativeElement.dispatchEvent(customEvent);
    return customEvent;
  }

  private createEvent(
    eventType: string,
    bubbles: boolean,
    cancelable: boolean
  ) : Event {
    let customEvent: any;
    try {
      customEvent = new CustomEvent(
        eventType,
        {
          bubbles: bubbles,
          cancelable: cancelable
        }
      );
    } catch (error) {
      customEvent = this.doc.createEvent('CustomEvent');
      customEvent.initCustomEvent(eventType, bubbles, cancelable);
    }
    return(customEvent);
  }
}

and in the OnInit lifecycle hook of the app component inject this service and call

 this.domEvents.triggerOnDocument('appready');
celestale commented 6 years ago

@colinskow @Kaffiend Great tips! Thank you.