Merge branch 'gp/global-loading'
This commit is contained in:
Коммит
bc940d1cd3
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
Загрузка…
Ссылка в новой задаче