@sumaris-net/ngx-components 0.25.0 → 0.25.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6944,6 +6944,9 @@ class StartableService {
6944
6944
  get started() {
6945
6945
  return this._started;
6946
6946
  }
6947
+ get starting() {
6948
+ return !!this._startPromise;
6949
+ }
6947
6950
  ready() {
6948
6951
  if (this._started)
6949
6952
  return Promise.resolve(this._data);
@@ -8165,6 +8168,19 @@ let Peer = Peer_1 = class Peer extends Entity {
8165
8168
  path: noTrailingSlash(url.pathname)
8166
8169
  });
8167
8170
  }
8171
+ static path(peer, ...paths) {
8172
+ if (!peer)
8173
+ throw new Error('Missing required argument \'peer\'!');
8174
+ // Remove starting slashes
8175
+ paths = (paths || []).map(path => {
8176
+ if (path.startsWith('./'))
8177
+ return path.substring(2);
8178
+ if (path.startsWith('/'))
8179
+ return path.substring(1);
8180
+ return path;
8181
+ }).filter(isNotNilOrBlank);
8182
+ return [noTrailingSlash(Peer_1.fromObject(peer).url)].concat(...paths).join('/');
8183
+ }
8168
8184
  asObject(options) {
8169
8185
  return super.asObject(options);
8170
8186
  }
@@ -9593,7 +9609,7 @@ class NetworkService extends StartableService {
9593
9609
  addListener(name, callback) {
9594
9610
  this._listeners[name] = this._listeners[name] || [];
9595
9611
  this._listeners[name].push(callback);
9596
- // When unsubcribe, remove from the listener
9612
+ // When unsubscribe, remove from the listener
9597
9613
  return new Subscription(() => {
9598
9614
  const index = this._listeners[name].indexOf(callback);
9599
9615
  if (index !== -1) {
@@ -11035,7 +11051,7 @@ function restoreTrackedQueries(opts) {
11035
11051
  const APP_GRAPHQL_TYPE_POLICIES = new InjectionToken('graphqlTypePolicies');
11036
11052
  class GraphqlService extends StartableService {
11037
11053
  constructor(platform, apollo, httpLink, network, storage, cryptoService, environment, typePolicies) {
11038
- super(network); // Wait network
11054
+ super(platform); // Wait network
11039
11055
  this.platform = platform;
11040
11056
  this.apollo = apollo;
11041
11057
  this.httpLink = httpLink;
@@ -11050,13 +11066,6 @@ class GraphqlService extends StartableService {
11050
11066
  this.customErrors = {};
11051
11067
  this._debug = !environment.production;
11052
11068
  this._defaultFetchPolicy = environment.apolloFetchPolicy;
11053
- // Restart if network restart
11054
- this.network.on('start', () => this.restart());
11055
- // Clear cache
11056
- this.network.on('resetCache', () => __awaiter(this, void 0, void 0, function* () {
11057
- yield this.ready();
11058
- yield this.clearCache();
11059
- }));
11060
11069
  // Listen network status
11061
11070
  this._networkStatusChanged$ = network.onNetworkStatusChanges
11062
11071
  .pipe(filter(isNotNil), distinctUntilChanged());
@@ -11461,10 +11470,11 @@ class GraphqlService extends StartableService {
11461
11470
  }
11462
11471
  clearCache(client) {
11463
11472
  return __awaiter(this, void 0, void 0, function* () {
11464
- client = (client || this.apollo.client);
11473
+ client = (client || this.client);
11465
11474
  if (client) {
11466
- const now = this._debug && Date.now();
11467
11475
  console.info('[graphql] Clearing Apollo client\'s cache... ');
11476
+ const now = this._debug && Date.now();
11477
+ // Clearing the cache
11468
11478
  yield client.cache.reset();
11469
11479
  if (this._debug)
11470
11480
  console.debug(`[graphql] Apollo client's cache cleared, in ${Date.now() - now}ms`);
@@ -11477,6 +11487,7 @@ class GraphqlService extends StartableService {
11477
11487
  /* -- protected methods -- */
11478
11488
  ngOnStart() {
11479
11489
  return __awaiter(this, void 0, void 0, function* () {
11490
+ yield this.network.ready();
11480
11491
  console.info('[graphql] Starting graphql...');
11481
11492
  const mobile = this.platform.is('mobile') || this.platform.is('mobileweb');
11482
11493
  const enableTrackMutationQueries = !mobile;
@@ -11612,6 +11623,10 @@ class GraphqlService extends StartableService {
11612
11623
  console.error('[graphql] Failed to restore tracked queries from storage: ' + (err && err.message || err), err);
11613
11624
  }
11614
11625
  }
11626
+ // Listen for network restart
11627
+ this._subscription.add(this.network.on('start', () => this.restart()));
11628
+ // Listen for clear cache request, from network
11629
+ this._subscription.add(this.network.on('resetCache', () => this.clearCache()));
11615
11630
  console.info('[graphql] Starting graphql [OK]');
11616
11631
  return client;
11617
11632
  });
@@ -13644,6 +13659,7 @@ class PlatformService {
13644
13659
  this.browser = browser;
13645
13660
  this.downloader = downloader;
13646
13661
  this._started = false;
13662
+ this._downloadingPromise = new Map();
13647
13663
  this._debug = !environment.production;
13648
13664
  if (this._debug)
13649
13665
  console.debug('[platform] Creating service');
@@ -13668,6 +13684,9 @@ class PlatformService {
13668
13684
  isAndroidCordova() {
13669
13685
  return this._android && this._cordova;
13670
13686
  }
13687
+ get canDownload() {
13688
+ return this._android && !!this.downloader;
13689
+ }
13671
13690
  width() {
13672
13691
  return this.platform.width();
13673
13692
  }
@@ -13709,7 +13728,7 @@ class PlatformService {
13709
13728
  .then(() => {
13710
13729
  this._started = true;
13711
13730
  this._startPromise = undefined;
13712
- console.info(`[platform] Starting platform [OK] {mobile: ${this._mobile}, touchUi: ${this.touchUi}, downloader: ${!!this.downloader} in ${Date.now() - now}ms`);
13731
+ console.info(`[platform] Starting platform [OK] {mobile: ${this._mobile}, touchUi: ${this.touchUi}, canDownload: ${this.canDownload}} in ${Date.now() - now}ms`);
13713
13732
  // Update cache configuration when network changed
13714
13733
  this.networkService.onNetworkStatusChanges.subscribe((type) => this.configureCache(type !== 'none'));
13715
13734
  // Update authentication type
@@ -13756,27 +13775,44 @@ class PlatformService {
13756
13775
  window.open(url, target, features, replace);
13757
13776
  }
13758
13777
  }
13778
+ getDownloadingPromise(uri) {
13779
+ return __awaiter(this, void 0, void 0, function* () {
13780
+ return this._downloadingPromise.get(uri);
13781
+ });
13782
+ }
13759
13783
  download(request) {
13760
13784
  return __awaiter(this, void 0, void 0, function* () {
13761
13785
  if (!request || !request.uri)
13762
13786
  throw new Error('Missing argument \'request\' or \'request.uri\'');
13763
- const downloader = this.downloader || window.plugins.Downloader;
13764
- if (downloader && this._android && this._cordova) {
13765
- request = Object.assign(Object.assign({ visibleInDownloadsUi: true, notificationVisibility: NotificationVisibility.VisibleNotifyCompleted, title: request.filename || '' }, request), { destinationInExternalFilesDir: Object.assign({ dirType: 'Downloads', subPath: request.filename || request.title || '' }, request.destinationInExternalFilesDir) });
13787
+ if (this._android && this.downloader) {
13788
+ // Check if not already downloading file
13789
+ let promise = this._downloadingPromise.get(request.uri);
13790
+ if (promise)
13791
+ return promise;
13792
+ request = Object.assign({ visibleInDownloadsUi: true, notificationVisibility: NotificationVisibility.VisibleNotifyCompleted, title: request.title || request.filename }, request);
13766
13793
  try {
13767
- const location = yield downloader.download(request);
13794
+ console.debug('[platform] Downloading, using request: ' + JSON.stringify(request));
13795
+ // Start download
13796
+ promise = this.downloader.download(request);
13797
+ // Remember this request uri
13798
+ this._downloadingPromise.set(request.uri, promise);
13799
+ const location = yield promise;
13768
13800
  console.info('[platform] File successfully downloaded at:' + location);
13769
13801
  return location;
13770
13802
  }
13771
13803
  catch (err) {
13772
- console.error('[platform] Error while downloading: ' + (err && err.message || err), err);
13804
+ console.error('[platform] Unable to download: ' + (err && err.message || err));
13773
13805
  throw err;
13774
13806
  }
13807
+ finally {
13808
+ // Forget the request
13809
+ this._downloadingPromise.delete(request.uri);
13810
+ }
13775
13811
  }
13776
- // Fallback (no Cordova)
13777
- // Web mode: open URI using the browser
13812
+ // Fallback (if not Android and Cordova): opening the URI using the browser
13813
+ // TODO: find a way to download under iOS (see https://www.c-sharpcorner.com/article/how-to-download-a-file-using-file-transfer-plugin-in-ionic-3/)
13778
13814
  else {
13779
- console.warn('[platform] Cannot use Cordova downloader: using browser open()');
13815
+ console.warn('[platform] Cannot use Android downloader: using browser open()');
13780
13816
  this.open(request.uri, '_system', 'location=no', true);
13781
13817
  return undefined;
13782
13818
  }
@@ -13877,13 +13913,14 @@ class PlatformService {
13877
13913
  storeName: forage.config().storeName,
13878
13914
  driver: [forage.INDEXEDDB, forage.WEBSQL]
13879
13915
  });
13880
- // IF data stored in the OLD storage: start migration
13881
13916
  const keys = yield oldForage.keys();
13917
+ // No data in the odl storage: skip migration
13882
13918
  if (isEmptyArray(keys)) {
13883
- // Drop the old instance
13884
- console.info(`[platform] Drop old storage {name: '${forage.config().name}', driver: '${oldForage.driver()}'}`);
13919
+ // Drop the old instance (not need anymore)
13920
+ console.debug(`[platform] Old storage is empty: dropping unused instance {name: '${forage.config().name}', driver: '${oldForage.driver()}'}`);
13885
13921
  yield oldForage.dropInstance();
13886
13922
  }
13923
+ // IF some data stored in the OLD storage: start migration
13887
13924
  else {
13888
13925
  const now = Date.now();
13889
13926
  console.info(`[platform] Starting storage migration...`);
@@ -18443,11 +18480,14 @@ const MimeTypes = Object.freeze({
18443
18480
  ANDROID_APK: 'application/vnd.android.package-archive'
18444
18481
  });
18445
18482
  class AppInstallUpgradeCard {
18446
- constructor(modalCtrl, configService, platform, cd, network, environment) {
18483
+ constructor(modalCtrl, configService, toastController, alertController, translate, cd, platform, network, environment) {
18447
18484
  this.modalCtrl = modalCtrl;
18448
18485
  this.configService = configService;
18449
- this.platform = platform;
18486
+ this.toastController = toastController;
18487
+ this.alertController = alertController;
18488
+ this.translate = translate;
18450
18489
  this.cd = cd;
18490
+ this.platform = platform;
18451
18491
  this.network = network;
18452
18492
  this.environment = environment;
18453
18493
  this._subscription = new Subscription();
@@ -18458,7 +18498,6 @@ class AppInstallUpgradeCard {
18458
18498
  this.showOfflineWarning = true;
18459
18499
  this.showInstallButton = false;
18460
18500
  this.onUpdateOfflineModeClick = new EventEmitter();
18461
- this.isAndroidCordova = platform.isAndroidCordova();
18462
18501
  }
18463
18502
  set showUpdateOfflineFeature(value) {
18464
18503
  if (value === this._showUpdateOfflineFeature)
@@ -18475,18 +18514,8 @@ class AppInstallUpgradeCard {
18475
18514
  this.offline = this.network.offline;
18476
18515
  // Listen pod config
18477
18516
  this._subscription.add(this.configService.config
18478
- .subscribe(config => {
18479
- console.info('[install] Checking if upgrade or install is need...');
18480
- const installLinks = this.getAllInstallLinks(config);
18481
- // Check for upgrade
18482
- this.updateLinks = this.getCompatibleUpgradeLinks(installLinks, config);
18483
- // Check for install links (if no upgrade need)
18484
- this.installLinks = !this.updateLinks && this.getCompatibleInstallLinks(installLinks);
18485
- setTimeout(() => {
18486
- this.loading = false;
18487
- this.markForCheck();
18488
- }, 2000); // Add a delay, for animation
18489
- }));
18517
+ .pipe(debounceTime(1000))
18518
+ .subscribe(config => this.checkNeedInstallOrUpdate(config)));
18490
18519
  // Listen network changes
18491
18520
  this._subscription.add(this.network.onNetworkStatusChanges
18492
18521
  .pipe(
@@ -18494,35 +18523,50 @@ class AppInstallUpgradeCard {
18494
18523
  //tap(() => this.waitingNetwork = false),
18495
18524
  map(connectionType => connectionType === 'none'), distinctUntilChanged())
18496
18525
  .subscribe(offline => {
18497
- this.offline = offline;
18498
- this.markForCheck();
18526
+ if (this.offline !== offline) {
18527
+ this.offline = offline;
18528
+ this.markForCheck();
18529
+ }
18499
18530
  }));
18500
18531
  });
18501
18532
  }
18502
18533
  ngOnDestroy() {
18503
18534
  this._subscription.unsubscribe();
18535
+ this._subscription = null;
18536
+ this.onUpdateOfflineModeClick.complete();
18537
+ this.installLinks = null;
18538
+ this.upgradeLinks = null;
18504
18539
  }
18505
- downloadLink(event, link) {
18506
- if (!link || !link.url)
18507
- return; // Skip
18508
- console.info(`[install-upgrade-card] Downloading '${link.url}' ...`);
18509
- this.platform.download({
18510
- uri: link.url,
18511
- filename: link.downloadFilename,
18512
- mimeType: link.mimeType
18540
+ download(event, link) {
18541
+ return __awaiter(this, void 0, void 0, function* () {
18542
+ if (!link || !link.url) {
18543
+ console.error('[install-upgrade-card] Missing required argument \'link.url\'');
18544
+ return; // Skip
18545
+ }
18546
+ const job = this.platform.download({
18547
+ uri: link.url,
18548
+ title: link.title,
18549
+ filename: link.filename,
18550
+ mimeType: link.mimeType
18551
+ });
18552
+ return this.listenDownloadPromise(link, job);
18513
18553
  });
18514
18554
  }
18515
18555
  tryOnline() {
18516
- this.waitingNetwork = true;
18517
- this.markForCheck();
18518
- this.network.tryOnline({
18519
- showLoadingToast: false,
18520
- showOnlineToast: true,
18521
- showOfflineToast: false
18522
- })
18523
- .then(() => {
18524
- this.waitingNetwork = false;
18556
+ return __awaiter(this, void 0, void 0, function* () {
18557
+ this.waitingNetwork = true;
18525
18558
  this.markForCheck();
18559
+ try {
18560
+ yield this.network.tryOnline({
18561
+ showLoadingToast: false,
18562
+ showOnlineToast: true,
18563
+ showOfflineToast: false
18564
+ });
18565
+ }
18566
+ finally {
18567
+ this.waitingNetwork = false;
18568
+ this.markForCheck();
18569
+ }
18526
18570
  });
18527
18571
  }
18528
18572
  getPlatformName(platform) {
@@ -18539,6 +18583,23 @@ class AppInstallUpgradeCard {
18539
18583
  return value;
18540
18584
  }
18541
18585
  /* -- private method -- */
18586
+ checkNeedInstallOrUpdate(config) {
18587
+ return __awaiter(this, void 0, void 0, function* () {
18588
+ console.info('[install] Check if need to install or upgrade...');
18589
+ try {
18590
+ const links = this.getLinks(config);
18591
+ // Check for upgrade
18592
+ this.upgradeLinks = this.getCompatibleUpgradeLinks(links, config);
18593
+ // Check for install links (if no upgrade need)
18594
+ this.installLinks = !this.upgradeLinks && this.getCompatibleInstallLinks(links);
18595
+ yield sleep(500); // Add a delay, for animation
18596
+ }
18597
+ finally {
18598
+ this.loading = false;
18599
+ this.markForCheck();
18600
+ }
18601
+ });
18602
+ }
18542
18603
  getCompatibleInstallLinks(installLinks) {
18543
18604
  // Cordova already running: not need to install
18544
18605
  if (this.platform.is('cordova'))
@@ -18564,10 +18625,16 @@ class AppInstallUpgradeCard {
18564
18625
  // Use min version as default version
18565
18626
  upgradeLinks.forEach(link => {
18566
18627
  link.version = link.version || appMinVersionFromPod;
18628
+ const promise = this.platform.getDownloadingPromise(link.url);
18629
+ // Listening download promise, if exists
18630
+ if (promise) {
18631
+ console.info(`[install-upgrade-card] Platform is already downloading this file \'${link.url}\': listening promise...`);
18632
+ this.listenDownloadPromise(link, promise);
18633
+ }
18567
18634
  });
18568
18635
  return isNotEmptyArray(upgradeLinks) ? upgradeLinks : undefined;
18569
18636
  }
18570
- getAllInstallLinks(config) {
18637
+ getLinks(config) {
18571
18638
  const result = [];
18572
18639
  // Android
18573
18640
  {
@@ -18575,16 +18642,20 @@ class AppInstallUpgradeCard {
18575
18642
  let url = config.getProperty(CORE_CONFIG_OPTIONS.ANDROID_INSTALL_URL);
18576
18643
  if (isNilOrBlank(url))
18577
18644
  url = this.environment.defaultAndroidInstallUrl || null;
18645
+ // Resolve relative URL
18646
+ const peer = this.network.peer;
18647
+ if (peer && (url.startsWith('./') || url.startsWith('/'))) {
18648
+ url = Peer.path(peer, url);
18649
+ }
18578
18650
  const minVersion = config.getProperty(CORE_CONFIG_OPTIONS.APP_MIN_VERSION);
18579
18651
  // Compute App name
18580
18652
  const name = isNotNilOrBlank(url) && config.label || this.environment.defaultAppName || 'SUMARiS';
18581
18653
  if (url) {
18582
- let downloadFilename;
18583
- let version;
18654
+ let title;
18584
18655
  let mimeType;
18585
18656
  // Get file name
18586
- const filename = this.getFilename(url);
18587
- version = minVersion || 'latest';
18657
+ let filename = this.getFilename(url);
18658
+ let version = minVersion || 'latest';
18588
18659
  // OK, this is a downloadable APK file (e.g. NOT a link to a playstore)
18589
18660
  if (filename === null || filename === void 0 ? void 0 : filename.endsWith('.apk')) {
18590
18661
  // Define mime type
@@ -18593,18 +18664,18 @@ class AppInstallUpgradeCard {
18593
18664
  const versionMatches = /-v([1-9][0-9]*\.[0-9]+\.(:?(:?alpha|beta|rc)?[0-9]*))/i.exec(filename);
18594
18665
  version = versionMatches && versionMatches[1] || version;
18595
18666
  // Compute a new file name, with the version
18596
- if (isNotNilOrBlank(name)) {
18597
- downloadFilename = `${name}-v${version}.apk`.toLowerCase();
18667
+ if (isNotNilOrBlank(name) && version !== 'latest') {
18668
+ filename = `${name}-v${version}.apk`.toLowerCase();
18669
+ title = `${name} v${version}`;
18598
18670
  }
18599
18671
  else {
18600
- downloadFilename = filename;
18601
18672
  // Replace 'latest' with the app version, if present
18602
- if (downloadFilename.indexOf('latest')) {
18603
- downloadFilename = downloadFilename.replace('latest', version);
18673
+ if (filename.indexOf('latest')) {
18674
+ filename = filename.replace('latest', version);
18604
18675
  }
18605
18676
  }
18606
18677
  }
18607
- result.push({ name, url, platform: 'android', version, downloadFilename, mimeType });
18678
+ result.push({ name, url, platform: 'android', version, filename, title, mimeType });
18608
18679
  }
18609
18680
  }
18610
18681
  // iOS - TODO
@@ -18628,11 +18699,72 @@ class AppInstallUpgradeCard {
18628
18699
  markForCheck() {
18629
18700
  this.cd.markForCheck();
18630
18701
  }
18702
+ showToast(opts) {
18703
+ return __awaiter(this, void 0, void 0, function* () {
18704
+ yield Toasts.show(this.toastController, this.translate, opts);
18705
+ });
18706
+ }
18707
+ listenDownloadPromise(link, promise) {
18708
+ return __awaiter(this, void 0, void 0, function* () {
18709
+ if (!link || !promise)
18710
+ return; // Skip
18711
+ if (!link.downloading) {
18712
+ link.downloading = true;
18713
+ this.markForCheck();
18714
+ }
18715
+ try {
18716
+ const location = yield promise;
18717
+ console.info('[install-upgrade-card] File downloaded at: ' + location);
18718
+ }
18719
+ // Failed: display a toast
18720
+ catch (err) {
18721
+ console.error('[install-upgrade] Download failed: ' + (err && err.message || err));
18722
+ this.showDownloadFailedToast(err);
18723
+ }
18724
+ finally {
18725
+ link.downloading = false;
18726
+ this.markForCheck();
18727
+ }
18728
+ return this.showDownloadCompleteDialog();
18729
+ });
18730
+ }
18731
+ showDownloadFailedToast(err) {
18732
+ return this.showToast({
18733
+ message: 'ERROR.DOWNLOAD_FAILED',
18734
+ messageParams: { error: err },
18735
+ type: 'error',
18736
+ showCloseButton: true
18737
+ });
18738
+ }
18739
+ showDownloadCompleteDialog() {
18740
+ return __awaiter(this, void 0, void 0, function* () {
18741
+ if (!this._subscription)
18742
+ return; // Skip if component has been destroyed
18743
+ const translations = yield this.translate.get([
18744
+ 'INFO.ALERT_HEADER',
18745
+ 'INFO.DOWNLOAD_UPDATE_SUCCEED',
18746
+ 'COMMON.BTN_CLOSE'
18747
+ ]).toPromise();
18748
+ const alert = yield this.alertController.create({
18749
+ header: translations['INFO.ALERT_HEADER'],
18750
+ message: translations['INFO.DOWNLOAD_UPDATE_SUCCEED'],
18751
+ buttons: [
18752
+ {
18753
+ text: translations['COMMON.BTN_CLOSE'],
18754
+ role: 'cancel',
18755
+ cssClass: 'secondary'
18756
+ }
18757
+ ]
18758
+ });
18759
+ yield alert.present();
18760
+ yield alert.onDidDismiss();
18761
+ });
18762
+ }
18631
18763
  }
18632
18764
  AppInstallUpgradeCard.decorators = [
18633
18765
  { type: Component, args: [{
18634
18766
  selector: 'app-install-upgrade-card',
18635
- template: "\n\n<!-- Offline mode card-->\n<ion-card *ngIf=\"showOfflineWarning && (!loading && offline || waitingNetwork)\"\n color=\"accent\"\n class=\"main ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row>\n <ion-col>\n <ion-text class=\"ion-text-wrap\" *ngIf=\"!waitingNetwork; else waitingNetworkText\">\n <h4>\n <b *ngIf=\"isLogin; else notLogin\" [innerHTML]=\"'NETWORK.INFO.OFFLINE_OR_UNAUTHORIZED'| translate\"></b>\n <ng-template #notLogin>\n <b [innerHTML]=\"'NETWORK.INFO.OFFLINE'| translate\"></b>\n </ng-template>\n </h4>\n <h3>\n <small [innerHTML]=\"'NETWORK.INFO.OFFLINE_HELP'|translate\"></small>\n </h3>\n </ion-text>\n <ng-template #waitingNetworkText>\n <ion-text class=\"ion-text-wrap\" [innerHTML]=\"'NETWORK.INFO.RETRY_TO_CONNECT'| translate\"></ion-text>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\">\n\n <!-- Retry button -->\n <ion-button *ngIf=\"!waitingNetwork; else waitingSpinner\" color=\"tertiary\" class=\"ion-float-end\"\n (click)=\"tryOnline()\">\n <span translate>NETWORK.BTN_CHECK_ALIVE</span>\n </ion-button>\n\n <!-- Waiting spinner -->\n <ng-template #waitingSpinner>\n <ion-spinner *ngIf=\"waitingNetwork\" color=\"light\"></ion-spinner>\n </ng-template>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Upgrade links -->\n<ion-card *ngIf=\"showUpgradeWarning && !loading && !offline && updateLinks\"\n color=\"accent\"\n class=\"ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row *ngFor=\"let link of updateLinks; last as last\">\n <ion-col>\n <ion-text class=\"ion-text-wrap\">\n <h3>\n <span *ngIf=\"link.version\" [innerHTML]=\"'INFO.UPDATE_APP_TO_VERSION'| translate: link\"></span>\n <span *ngIf=\"!link.version\" [innerHTML]=\"'INFO.UPDATE_APP'| translate: link\"></span>\n </h3>\n <h4>\n <small *ngIf=\"last\" [innerHTML]=\"'INFO.UPDATE_APP_HELP'|translate\"></small>\n </h4>\n </ion-text>\n </ion-col>\n\n <ion-col size=\"auto\">\n\n <!-- Download button -->\n <ion-button *ngIf=\"link.downloadFilename; else redirectButton\"\n [download]=\"link.downloadFilename\"\n [href]=\"link.url\"\n color=\"tertiary\" class=\"ion-float-end\" >\n <ion-label translate>COMMON.BTN_DOWNLOAD</ion-label>\n </ion-button>\n\n <!-- Redirect button -->\n <ng-template #redirectButton>\n <ion-button [href]=\"link.url\" rel=\"external\" color=\"tertiary\" class=\"ion-float-end\" target=\"_blank\">\n <ion-label translate>COMMON.BTN_SHOW_MORE</ion-label>\n </ion-button>\n </ng-template>\n\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Install links -->\n<ion-card *ngIf=\"showInstallButton && !loading && !offline && installLinks\"\n color=\"secondary\"\n class=\"ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row *ngFor=\"let link of installLinks; last as last\">\n <ion-col>\n <ion-text class=\"ion-text-wrap\">\n <h3 [innerHTML]=\"'INFO.DOWNLOAD_APP_TITLE'| translate: {name: link.name, platform: getPlatformName(link.platform) }\"></h3>\n <h4><small *ngIf=\"last\" [innerHTML]=\"'INFO.DOWNLOAD_APP_HELP'|translate\"></small></h4>\n </ion-text>\n </ion-col>\n <ion-col size=\"auto\">\n <ng-container *ngTemplateOutlet=\"downloadButton; context: { $implicit: link }\"></ng-container>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Update offline feature card-->\n<ion-card *ngIf=\"showUpdateOfflineFeature && !loading && !offline\"\n color=\"accent\"\n class=\"main ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row>\n <ion-col>\n <ion-text class=\"ion-text-wrap\">\n <h4>\n <b [innerHTML]=\"'NETWORK.INFO.UPDATE_OFFLINE_MODE'| translate\"></b>\n </h4>\n <h3>\n <small [innerHTML]=\"'NETWORK.INFO.UPDATE_OFFLINE_MODE_HELP'|translate\"></small>\n </h3>\n </ion-text>\n </ion-col>\n <ion-col size=\"auto\">\n\n <!-- Retry button -->\n <ion-button color=\"tertiary\" class=\"ion-float-end\"\n (click)=\"onUpdateOfflineModeClick.emit($event)\">\n <span translate>NETWORK.BTN_UPDATE</span>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Display a download button, depending on the link URL, and the device platform -->\n<ng-template #downloadButton let-link>\n\n <ng-container *ngIf=\"link.downloadFilename; else redirectButton\">\n\n <!-- Cordova download button -->\n <ion-button *ngIf=\"isAndroidCordova; else webDownloadButton\"\n (click)=\"downloadLink($event, asLink(link))\"\n color=\"tertiary\" class=\"ion-float-end\" >\n <ion-label translate>COMMON.BTN_DOWNLOAD</ion-label>\n </ion-button>\n\n <!-- Web download button -->\n <ng-template #webDownloadButton>\n <ion-button [download]=\"link.downloadFilename\"\n [href]=\"link.url\"\n color=\"tertiary\" class=\"ion-float-end\" >\n <ion-label translate>COMMON.BTN_DOWNLOAD</ion-label>\n </ion-button>\n </ng-template>\n </ng-container>\n\n <!-- Web redirect button -->\n <ng-template #redirectButton>\n <ion-button [href]=\"link.url\" rel=\"external\" color=\"tertiary\" class=\"ion-float-end\" target=\"_blank\">\n <ion-label translate>COMMON.BTN_SHOW_MORE</ion-label>\n </ion-button>\n </ng-template>\n</ng-template>\n",
18767
+ template: "\n\n<!-- Offline mode card-->\n<ion-card *ngIf=\"showOfflineWarning && (!loading && offline || waitingNetwork)\"\n color=\"accent\"\n class=\"main ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row>\n <ion-col>\n <ion-text class=\"ion-text-wrap\" *ngIf=\"!waitingNetwork; else waitingNetworkText\">\n <h4>\n <b *ngIf=\"isLogin; else notLogin\" [innerHTML]=\"'NETWORK.INFO.OFFLINE_OR_UNAUTHORIZED'| translate\"></b>\n <ng-template #notLogin>\n <b [innerHTML]=\"'NETWORK.INFO.OFFLINE'| translate\"></b>\n </ng-template>\n </h4>\n <h3>\n <small [innerHTML]=\"'NETWORK.INFO.OFFLINE_HELP'|translate\"></small>\n </h3>\n </ion-text>\n <ng-template #waitingNetworkText>\n <ion-text class=\"ion-text-wrap\" [innerHTML]=\"'NETWORK.INFO.RETRY_TO_CONNECT'| translate\"></ion-text>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\">\n\n <!-- Retry button -->\n <ion-button *ngIf=\"!waitingNetwork; else waitingSpinner\" color=\"tertiary\" class=\"ion-float-end\"\n (click)=\"tryOnline()\">\n <span translate>NETWORK.BTN_CHECK_ALIVE</span>\n </ion-button>\n\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Upgrade links -->\n<ion-card *ngIf=\"showUpgradeWarning && !loading && !offline && upgradeLinks\"\n color=\"accent\"\n class=\"ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row *ngFor=\"let link of upgradeLinks; last as last\">\n <ion-col>\n <ion-text class=\"ion-text-wrap\">\n <h3>\n <span *ngIf=\"link.version\" [innerHTML]=\"'INFO.UPDATE_APP_TO_VERSION'| translate: link\"></span>\n <span *ngIf=\"!link.version\" [innerHTML]=\"'INFO.UPDATE_APP'| translate: link\"></span>\n </h3>\n <h4>\n <small *ngIf=\"last\" [innerHTML]=\"'INFO.UPDATE_APP_HELP'|translate\"></small>\n </h4>\n </ion-text>\n </ion-col>\n\n <ion-col size=\"auto\">\n <ng-container *ngTemplateOutlet=\"downloadButton; context: { $implicit: link }\"></ng-container>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Install links -->\n<ion-card *ngIf=\"showInstallButton && !loading && !offline && installLinks\"\n color=\"secondary\"\n class=\"ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row *ngFor=\"let link of installLinks; last as last\">\n <ion-col>\n <ion-text class=\"ion-text-wrap\">\n <h3 [innerHTML]=\"'INFO.DOWNLOAD_APP_TITLE'| translate: {name: link.name, platform: getPlatformName(link.platform) }\"></h3>\n <h4><small *ngIf=\"last\" [innerHTML]=\"'INFO.DOWNLOAD_APP_HELP'|translate\"></small></h4>\n </ion-text>\n </ion-col>\n <ion-col size=\"auto\">\n <ng-container *ngTemplateOutlet=\"downloadButton; context: { $implicit: link }\"></ng-container>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Update offline feature card-->\n<ion-card *ngIf=\"showUpdateOfflineFeature && !loading && !offline\"\n color=\"accent\"\n class=\"main ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row>\n <ion-col>\n <ion-text class=\"ion-text-wrap\">\n <h4>\n <b [innerHTML]=\"'NETWORK.INFO.UPDATE_OFFLINE_MODE'| translate\"></b>\n </h4>\n <h3>\n <small [innerHTML]=\"'NETWORK.INFO.UPDATE_OFFLINE_MODE_HELP'|translate\"></small>\n </h3>\n </ion-text>\n </ion-col>\n <ion-col size=\"auto\">\n\n <!-- Retry button -->\n <ion-button color=\"tertiary\" class=\"ion-float-end\"\n (click)=\"onUpdateOfflineModeClick.emit($event)\">\n <span translate>NETWORK.BTN_UPDATE</span>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Display a download button, depending on the link URL, and the device platform -->\n<ng-template #downloadButton let-link>\n\n <ng-container *ngIf=\"link.downloadFilename; else redirectButton\">\n\n <ng-container *ngIf=\"platform.canDownload; else webDownloadButton\">\n <!-- Download using platform -->\n <ion-button (click)=\"download($event, asLink(link))\"\n [disabled]=\"link.downloading\"\n color=\"tertiary\" class=\"ion-float-end\">\n <ion-icon slot=\"start\" *ngIf=\"!link.downloading\" name=\"download\"></ion-icon>\n <ion-spinner slot=\"start\" class=\"ion-no-padding\" *ngIf=\"link.downloading\"></ion-spinner>\n <ion-label translate>COMMON.BTN_DOWNLOAD</ion-label>\n </ion-button>\n </ng-container>\n\n <!-- Web download button -->\n <ng-template #webDownloadButton>\n <ion-button [download]=\"link.downloadFilename\"\n [href]=\"link.url\"\n color=\"tertiary\" class=\"ion-float-end\" >\n <ion-label translate>COMMON.BTN_DOWNLOAD</ion-label>\n </ion-button>\n </ng-template>\n </ng-container>\n\n <!-- Web redirect button -->\n <ng-template #redirectButton>\n <ion-button [href]=\"link.url\" rel=\"external\" color=\"tertiary\" class=\"ion-float-end\" target=\"_blank\">\n <ion-label translate>COMMON.BTN_SHOW_MORE</ion-label>\n </ion-button>\n </ng-template>\n</ng-template>\n\n\n<!-- Waiting spinner -->\n<ng-template #waitingSpinner>\n <ion-spinner color=\"light\"></ion-spinner>\n</ng-template>\n",
18636
18768
  changeDetection: ChangeDetectionStrategy.OnPush,
18637
18769
  animations: [slideUpDownAnimation],
18638
18770
  styles: ["ion-text small{font-size:85%}"]
@@ -18641,8 +18773,11 @@ AppInstallUpgradeCard.decorators = [
18641
18773
  AppInstallUpgradeCard.ctorParameters = () => [
18642
18774
  { type: ModalController },
18643
18775
  { type: ConfigService },
18644
- { type: PlatformService },
18776
+ { type: ToastController },
18777
+ { type: AlertController },
18778
+ { type: TranslateService },
18645
18779
  { type: ChangeDetectorRef },
18780
+ { type: PlatformService },
18646
18781
  { type: NetworkService },
18647
18782
  { type: undefined, decorators: [{ type: Inject, args: [ENVIRONMENT,] }] }
18648
18783
  ];