Merge branch 'gp/global-loading'

This commit is contained in:
Georgi Prodanov 2017-02-28 12:08:53 +02:00
Родитель 2db3e139d8 2f98ff6d81
Коммит bc940d1cd3
21 изменённых файлов: 198 добавлений и 32 удалений

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">TeamUP</string>
<string name="title_activity_kimera">TeamUP</string>
</resources>

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">TeamUP</string>
<string name="title_activity_kimera">TeamUP</string>
</resources>

Просмотреть файл

@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<string>TeamUP</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleInfoDictionaryVersion</key>

Просмотреть файл

@ -1,4 +1,4 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { Component, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
import { NavigationEnd } from '@angular/router';
import { RouterExtensions } from 'nativescript-angular/router';
import { RadSideDrawerComponent } from 'nativescript-telerik-ui/sidedrawer/angular';
@ -6,16 +6,10 @@ import * as application from 'application';
import { utilities } from './shared';
import {
EverliveProvider,
UsersService,
EventsService,
EventRegistrationsService,
AlertService,
GroupsService,
ImagePickerService,
FilesService,
PushNotificationsService,
PlatformService
PlatformService,
LoadingIndicatorService
} from './services';
@Component({
@ -32,12 +26,22 @@ export class AppComponent implements OnInit {
constructor(
private _usersService: UsersService,
private _routerExtensions: RouterExtensions,
private _platform: PlatformService
private _platform: PlatformService,
private _loadingService: LoadingIndicatorService,
private _vcRef: ViewContainerRef,
private _alertsService: AlertService
) {
this.isAndroid = this._platform.isAndroid;
this._loadingService.extendedLoading.subscribe(() => {
let modalOptions = {
justLoading: true,
outsideClose: this._loadingService.allLoaded
};
this._alertsService.showModal(modalOptions, this._vcRef);
});
}
ngOnInit() {
ngOnInit() {
this._routerExtensions.router.events.subscribe((ev) => {
if (ev instanceof NavigationEnd) {
this.disableDrawer = utilities.shouldDisableDrawer(ev.url);

Просмотреть файл

@ -1,3 +1,5 @@
@import '~/css/core.light.css';
@import 'nativescript-theme-core/css/core.light.css';
@import url('./platform.css');

Просмотреть файл

@ -1,7 +1,7 @@
import { NativeScriptModule } from "nativescript-angular/platform";
import { NativeScriptFormsModule } from "nativescript-angular/forms";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { NativeScriptUISideDrawerModule } from 'nativescript-telerik-ui/sidedrawer/angular';
import { NativeScriptUISideDrawerModule, SIDEDRAWER_DIRECTIVES } from 'nativescript-telerik-ui/sidedrawer/angular';
import { NgModule, NgModuleFactoryLoader, NO_ERRORS_SCHEMA } from "@angular/core";
import { NSModuleFactoryLoader } from "nativescript-angular/router";
@ -18,12 +18,13 @@ import {
FilesService,
GroupsService,
ImagePickerService,
PushNotificationsService
PushNotificationsService,
LoadingIndicatorService
} from './services';
import { EventsModule } from './events';
import { GroupsModule } from './groups';
import { UsersModule } from './users';
// import { EventsModule } from './events';
// import { GroupsModule } from './groups';
// import { UsersModule } from './users';
import { SharedModule } from './shared';
@NgModule({
@ -41,10 +42,14 @@ import { SharedModule } from './shared';
GroupsService,
ImagePickerService,
PushNotificationsService,
LoadingIndicatorService,
SIDEDRAWER_DIRECTIVES,
{ provide: NgModuleFactoryLoader, useClass: NSModuleFactoryLoader },
],
// entryComponents: [ AppModalComponent ],
bootstrap: [ AppComponent ],
imports: [
SharedModule,
NativeScriptUISideDrawerModule,
NativeScriptFormsModule,
NativeScriptModule,

Просмотреть файл

@ -79,7 +79,7 @@ export class GroupsComponent implements OnInit {
this.selectedIndex = tabIndex;
}
loadMoresUserGroups() {
loadMoreUserGroups() {
this.hasMoreUserGroups = false;
return this._usersService.currentUser()
.then((u) => this._groupsService.getUserGroups(u.Id, this._userGroupsPage, this._pageSize))
@ -114,7 +114,7 @@ export class GroupsComponent implements OnInit {
private _initialize(loadUserGroups) {
let promise: Promise<any>;
if (loadUserGroups) {
promise = this.loadMoresUserGroups();
promise = this.loadMoreUserGroups();
} else {
promise = this.loadMoresUnjoinedGroups();
}

Просмотреть файл

@ -3,7 +3,7 @@ import { ModalDialogService, ModalDialogOptions } from 'nativescript-angular/mod
import * as dialogs from 'ui/dialogs';
import { AppModalComponent } from '../shared';
import { utilities, AppModalComponent } from '../shared';
@Injectable()
export class AlertService {
@ -17,6 +17,7 @@ export class AlertService {
}
showError(message: string) {
message = utilities.prettifySystemErrors(message);
return this._showMessage(message, 'Error');
}

Просмотреть файл

@ -67,12 +67,9 @@ export class GroupsService {
}
getUserCountByGroup(userId: string): Promise<{GroupId: string, UserId: number}[]> {
return this.getUnjoinedGroups(userId)
.then(groups => {
let query = this._elProvider.getNewAggregateQuery();
query.groupBy('GroupId').count('UserId');
return this._membershipsData.aggregate(query);
})
let query = this._elProvider.getNewAggregateQuery();
query.groupBy('GroupId').count('UserId');
return this._membershipsData.aggregate(query)
.then((res: any) => res.result);
}

Просмотреть файл

@ -10,3 +10,4 @@ export * from './image-picker.service';
export * from './push-notifications.service';
export * from './platform.service';
export * from './auth-guard.service';
export * from './loading-indicator.service';

Просмотреть файл

@ -0,0 +1,70 @@
import { Injectable, EventEmitter } from '@angular/core';
import { EverliveProvider } from './';
import { Stopwatch, constants } from '../shared';
@Injectable()
export class LoadingIndicatorService {
extendedLoading: EventEmitter<void>;
allLoaded: EventEmitter<void>;
private _interval = null;
private _ongoingRequestsCount: number = 0;
private _stopwatch: Stopwatch;
private _loadingMode = false;
constructor(
private _elProvider: EverliveProvider
) {
this.extendedLoading = new EventEmitter<void>();
this.allLoaded = new EventEmitter<void>();
this.threshold = constants.extendedLoadingThreshold;
this._elProvider.get.on('beforeExecute', (query) => {
this._queueLoading();
if (query.contentTypeName === 'Files') {
this._loadingMode = true;
this.extendedLoading.emit();
}
});
this._elProvider.get.on('afterExecute', () => this._dequeueLoading());
}
get threshold() {
return this._interval;
}
set threshold(val: number) {
this._interval = val;
this._stopwatch = new Stopwatch(val, this._onIntervalHit.bind(this));
}
private _onIntervalHit() {
if (this._ongoingRequestsCount > 0 && !this._loadingMode) {
this._emitExtendedLoading();
}
}
private _queueLoading() {
this._ongoingRequestsCount++;
this._stopwatch.restart();
}
private _dequeueLoading() {
this._ongoingRequestsCount = Math.max(this._ongoingRequestsCount - 1, 0);
if (this._ongoingRequestsCount === 0) {
this._stopwatch.stop();
this._emitAllLoaded();
}
}
private _emitExtendedLoading() {
this.extendedLoading.emit();
this._loadingMode = true;
}
private _emitAllLoaded() {
this.allLoaded.emit();
this._loadingMode = false;
}
}

Просмотреть файл

@ -15,6 +15,8 @@ export class AppModalComponent {
@Input() text: string;
@Input() fullscreen: boolean = true;
outsideClose: EventEmitter<void>;
constructor(private _params?: ModalDialogParams) {
if (!this._params) {
return;
@ -39,13 +41,17 @@ export class AppModalComponent {
}
private _applyContextOptions(ctx: any) {
let validProps = ['title', 'text', 'buttons', 'fullscreen'];
let validProps = ['title', 'text', 'buttons', 'fullscreen', 'justLoading', 'outsideClose'];
for (let prop of validProps) {
if (prop in ctx && prop) {
this[prop] = ctx[prop];
}
}
if (ctx.outsideClose) {
this.outsideClose.subscribe(() => this._params.closeCallback(true));
}
if (ctx.closeTimeout) {
setTimeout(() => {
this._params.closeCallback(true);

Просмотреть файл

@ -1,8 +1,9 @@
<StackLayout class="app-modal-cntnr" [ngClass]="{ 'no-fullscreen': !fullscreen }">
<StackLayout class="app-modal-cntnr" [ngClass]="{ 'no-fullscreen': !fullscreen, 'just-loading': justLoading }">
<Label *ngIf="title" class="app-modal-title" [text]="title" textWrap="true"></Label>
<Label *ngIf="text" class="app-modal-text" [text]="text" textWrap="true"></Label>
<ng-content></ng-content>
<ActivityIndicator [busy]="justLoading" [visibility]="!justLoading ? 'collapse' : 'visible'" horizontalAlignment="center" verticalAlignment="center"></ActivityIndicator>
<StackLayout class="controls-wrapper" *ngIf="buttons">
<StackLayout class="btn-wrp">

Просмотреть файл

@ -7,3 +7,9 @@ export const disabledDawerRoutes = [
export const androidProjNumber = '832404619163';
export const modalsTimeout = 3000;
export const extendedLoadingThreshold = 1500;
export const systemErrorMsgs = {
'Iterator timed out': 'The operation took too long. Please try again later'
};

Просмотреть файл

@ -35,7 +35,7 @@ export class DateTimePickerModalComponent {
configureDatePicker(picker: DatePicker) {
let now = new Date();
let oneYear = 31536000000;
const oneYear = 31536000000;
picker.date = now;
if (!this._isEdit) {

Просмотреть файл

@ -64,7 +64,7 @@ export class EventListComponent implements OnInit {
let eventDate = this.getEventDate(event);
if (!eventDate) {
return 'TBD';
return 'DATE TBD';
}
let days = Math.round((eventDate.getTime() - Date.now()) / oneDay);

Просмотреть файл

@ -12,6 +12,7 @@ export * from './user-display/user-display.component';
export * from './user-list/user-list.component';
export * from './dismissable-input/dismissable-input.directive';
export * from './shared.module';
export * from './stopwatch';
export const utilities = utils;
export const constants = allConstants;

46
app/shared/stopwatch.ts Normal file
Просмотреть файл

@ -0,0 +1,46 @@
export class Stopwatch {
private _timer: number = null;
// private _startTime: number;
constructor(
private _period: number,
private _onTimerEnd: () => void
) {}
start() {
this._timer = setTimeout(() => {
this._onTimerEnd();
}, this._period);
}
stop() {
clearInterval(this._timer);
this._timer = null;
}
restart() {
this.stop();
this.start();
}
// get elapsed() {
// let result: number = 0;
// if (typeof this._startTime === 'number') {
// result = Date.now() - this._startTime;
// }
// return result;
// }
// start() {
// this._startTime = Date.now();
// }
// stop() {
// this._startTime = null;
// }
// restart() {
// this.stop();
// this.start();
// }
}

Просмотреть файл

@ -79,3 +79,19 @@ export function shallowCopy (obj) {
}
return res;
};
export function startsWith (str: string, substr: string) {
return str.indexOf(substr) === 0;
}
export function prettifySystemErrors (rawErrorMsg: string) {
let errorsToPrettify = Object.keys(constants.systemErrorMsgs);
let result: string = rawErrorMsg;
let keyIndex = findIndex(errorsToPrettify, errMsg => startsWith(rawErrorMsg, errMsg));
if (keyIndex !== -1) {
let prettifyKey = errorsToPrettify[keyIndex];
result = constants.systemErrorMsgs[prettifyKey];
}
return result;
}

Просмотреть файл

@ -403,7 +403,7 @@ function formAndroidNotification(title, message, data) {
body: message,
sound: 'default',
color: '#F4550F',
icon: 'icon'
icon: 'ic_stat_notify'
}
};

Просмотреть файл

@ -21,7 +21,7 @@
"@angular/platform-browser": "2.4.6",
"@angular/platform-browser-dynamic": "2.4.6",
"@angular/router": "3.4.6",
"everlive-sdk": "1.9.3",
"everlive-sdk": "https://github.com/georgiwe/backend-services-js-sdk.git",
"jstz": "1.0.9",
"nativescript-angular": "1.4.0",
"nativescript-imagepicker": "~2.5.1",