Skip to content

Commit

Permalink
Add loading screen
Browse files Browse the repository at this point in the history
  • Loading branch information
nezhar committed Nov 4, 2018
1 parent 3c5f4bb commit 3f4765f
Show file tree
Hide file tree
Showing 10 changed files with 336 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/app/app.component.html
Expand Up @@ -5,3 +5,5 @@
<ng-template #snippetsApp style="min-width: 1024px;">
<app-base></app-base>
</ng-template>

<app-loading-screen></app-loading-screen>
8 changes: 8 additions & 0 deletions src/app/app.module.ts
Expand Up @@ -54,6 +54,8 @@ import { TeamMemberDeleteModalComponent } from './components/team-member-delete-
import { LabelDeleteModalComponent } from './components/label-delete-modal/label-delete-modal.component';
import { BaseComponent } from './layout/base/base.component';
import { BootstrapSwitchComponent } from './components/bootstrap-switch/bootstrap-switch.component';
import { LoadingScreenComponent } from './components/loading-screen/loading-screen.component';
import { LoadingScreenInterceptor } from "./helpers/loading.interceptor";

library.add(
fas.faCoffee,
Expand Down Expand Up @@ -102,6 +104,7 @@ library.add(
LabelDeleteModalComponent,
BaseComponent,
BootstrapSwitchComponent,
LoadingScreenComponent,
],
entryComponents: [
SnippetModalComponent,
Expand Down Expand Up @@ -136,6 +139,11 @@ library.add(
provide: HTTP_INTERCEPTORS,
useClass: JwtInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: LoadingScreenInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
Expand Down
22 changes: 22 additions & 0 deletions src/app/components/loading-screen/loading-screen.component.html
@@ -0,0 +1,22 @@
<div class="loading-screen-wrapper" *ngIf="loading">
<div class="loading-screen-icon">
<div class="blobs">
<div class="blob-center"></div>
<div class="blob"></div>
<div class="blob"></div>
<div class="blob"></div>
<div class="blob"></div>
<div class="blob"></div>
<div class="blob"></div>
</div>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<filter id="goo">
<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur"/>
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="goo"/>
<feBlend in="SourceGraphic" in2="goo"/>
</filter>
</defs>
</svg>
</div>
</div>
156 changes: 156 additions & 0 deletions src/app/components/loading-screen/loading-screen.component.scss
@@ -0,0 +1,156 @@
.loading-screen-wrapper {
z-index: 100000;
position: absolute;
background-color: rgba(255, 255, 255, 0.6);
width: 100%;
height: 100%;
display: block;
}

.loading-screen-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

/**
Loader: https://codepen.io/eliortabeka/pen/EXJyPP
*/
svg {
display: none;
}

$bolb-color: #475158;

// Loader
.blobs {
filter: url(#goo);
width: 300px;
height: 300px;
position: relative;
overflow: hidden;
border-radius: 70px;
transform-style: preserve-3d;

// Blob center item
.blob-center {
transform-style: preserve-3d;
position: absolute;
background: $bolb-color;
top: 50%;
left: 50%;
width: 30px;
height: 30px;
transform-origin: left top;
transform: scale(.9) translate(-50%, -50%);
animation: blob-grow
linear
3.4s
infinite;
border-radius: 50%;
box-shadow: 0 -10px 40px -5px $bolb-color;
}
}

// Blob item
.blob {
position: absolute;
background: $bolb-color;
top: 50%;
left: 50%;
width: 30px;
height: 30px;
border-radius: 50%;
animation: blobs
ease-out
3.4s
infinite;
transform: scale(.9) translate(-50%, -50%);
transform-origin: center top;
opacity: 0;

// Set animation delay for each of type
@for $i from 1 to 6 {
&:nth-child(#{$i}) {
animation-delay: $i * 0.2 + s;
}
}
}

// Keyframes variables
$left: calc(-330px - 50%);
$right: calc(330px - 50%);

// Keyframes
@keyframes blobs {
0% {
opacity: 0;
transform: scale(0) translate($left, -50%);
}
1% {
opacity: 1;
}
35%,65% {
opacity: 1;
transform: scale(.9) translate(-50%, -50%);
}
99% {
opacity: 1;
}
100% {
opacity: 0;
transform: scale(0) translate($right, -50%);
}
}

@keyframes blob-grow {
0%, 39% {
transform: scale(0) translate(-50%, -50%);
}
40%, 42% {
transform: scale(1, .9) translate(-50%, -50%);
}
43%, 44% {
transform: scale(1.2, 1.1) translate(-50%, -50%);
}
45%, 46% {
transform: scale(1.3, 1.2) translate(-50%, -50%);
}
47%, 48% {
transform: scale(1.4, 1.3) translate(-50%, -50%);
}
52%{
transform: scale(1.5, 1.4) translate(-50%, -50%);
}
54% {
transform: scale(1.7, 1.6) translate(-50%, -50%);
}
58% {
transform: scale(1.8, 1.7) translate(-50%, -50%);
}
68%, 70% {
transform: scale(1.7, 1.5) translate(-50%, -50%);
}
78% {
transform: scale(1.6, 1.4) translate(-50%, -50%);
}
80%, 81% {
transform: scale(1.5, 1.4) translate(-50%, -50%);
}
82%, 83% {
transform: scale(1.4, 1.3) translate(-50%, -50%);
}
84%, 85% {
transform: scale(1.3, 1.2) translate(-50%, -50%);
}
86%, 87% {
transform: scale(1.2, 1.1) translate(-50%, -50%);
}
90%, 91% {
transform: scale(1, .9) translate(-50%, -50%);
}
92%, 100% {
transform: scale(0) translate(-50%, -50%);
}
}
25 changes: 25 additions & 0 deletions src/app/components/loading-screen/loading-screen.component.spec.ts
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { LoadingScreenComponent } from './loading-screen.component';

describe('LoadingScreenComponent', () => {
let component: LoadingScreenComponent;
let fixture: ComponentFixture<LoadingScreenComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ LoadingScreenComponent ]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(LoadingScreenComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
31 changes: 31 additions & 0 deletions src/app/components/loading-screen/loading-screen.component.ts
@@ -0,0 +1,31 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { LoadingScreenService } from "../../services/loading-screen/loading-screen.service";
import { Subscription } from "rxjs";
import { debounceTime } from "rxjs/operators";

@Component({
selector: 'app-loading-screen',
templateUrl: './loading-screen.component.html',
styleUrls: ['./loading-screen.component.scss']
})
export class LoadingScreenComponent implements OnInit, OnDestroy {

loading: boolean = false;
loadingSubscription: Subscription;

constructor(private loadingScreenService: LoadingScreenService) {
}

ngOnInit() {
this.loadingSubscription = this.loadingScreenService.loadingStatus.pipe(
debounceTime(200)
).subscribe((value) => {
this.loading = value;
});
}

ngOnDestroy() {
this.loadingSubscription.unsubscribe();
}

}
51 changes: 51 additions & 0 deletions src/app/helpers/loading.interceptor.ts
@@ -0,0 +1,51 @@
import { Injectable } from "@angular/core";
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from "@angular/common/http";
import { Observable } from "rxjs";
import { LoadingScreenService } from "../services/loading-screen/loading-screen.service";
import { finalize } from "rxjs/operators";


@Injectable()
export class LoadingScreenInterceptor implements HttpInterceptor {

activeRequests: number = 0;

/**
* URLs for which the loading screen should not be enabled
*/
skippUrls = [
'/authrefresh',
];

constructor(private loadingScreenService: LoadingScreenService) {
}

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let displayLoadingScreen = true;

for (const skippUrl of this.skippUrls) {
if (new RegExp(skippUrl).test(request.url)) {
displayLoadingScreen = false;
break;
}
}

if (displayLoadingScreen) {
if (this.activeRequests === 0) {
this.loadingScreenService.startLoading();
}
this.activeRequests++;

return next.handle(request).pipe(
finalize(() => {
this.activeRequests--;
if (this.activeRequests === 0) {
this.loadingScreenService.stopLoading();
}
})
)
} else {
return next.handle(request);
}
};
}
12 changes: 12 additions & 0 deletions src/app/services/loading-screen/loading-screen.service.spec.ts
@@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';

import { LoadingScreenService } from './loading-screen.service';

describe('LoadingScreenService', () => {
beforeEach(() => TestBed.configureTestingModule({}));

it('should be created', () => {
const service: LoadingScreenService = TestBed.get(LoadingScreenService);
expect(service).toBeTruthy();
});
});
28 changes: 28 additions & 0 deletions src/app/services/loading-screen/loading-screen.service.ts
@@ -0,0 +1,28 @@
import { Injectable } from '@angular/core';
import { Subject } from "rxjs";

@Injectable({
providedIn: 'root'
})
export class LoadingScreenService {

private _loading: boolean = false;
loadingStatus: Subject = new Subject();

get loading():boolean {
return this._loading;
}

set loading(value) {
this._loading = value;
this.loadingStatus.next(value);
}

startLoading() {
this.loading = true;
}

stopLoading() {
this.loading = false;
}
}
1 change: 1 addition & 0 deletions src/app/services/services.module.ts
Expand Up @@ -15,6 +15,7 @@ import { AuthResource } from "./resources/auth.resource";
import { ActiveScopeService } from "./navigation/activeScope.service";
import { UserTeamResource } from "./resources/userteam.resource";
import { SnippetLabelResource } from "./resources/snippetlabel.resource";
import { LoadingScreenService } from "./loading-screen/loading-screen.service";


@NgModule({
Expand Down

0 comments on commit 3f4765f

Please sign in to comment.