MOBILE-4061 core: Handle network changes on the network service
parent
ed4ebdd9e2
commit
82033e05d0
|
@ -33,7 +33,7 @@ import { CoreCategoryData, CoreCourses, CoreEnrolledCourseData } from '@features
|
||||||
import { CoreCoursesHelper } from '@features/courses/services/courses-helper';
|
import { CoreCoursesHelper } from '@features/courses/services/courses-helper';
|
||||||
import { AddonCalendarFilterComponent } from '../../components/filter/filter';
|
import { AddonCalendarFilterComponent } from '../../components/filter/filter';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { Network, NgZone } from '@singletons';
|
import { NgZone } from '@singletons';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { Params } from '@angular/router';
|
import { Params } from '@angular/router';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
|
@ -180,7 +180,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Refresh online status when changes.
|
// Refresh online status when changes.
|
||||||
this.onlineObserver = Network.onChange().subscribe(() => {
|
this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => {
|
NgZone.run(() => {
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
|
|
|
@ -32,7 +32,7 @@ import { CoreLocalNotifications } from '@services/local-notifications';
|
||||||
import { CoreCourse } from '@features/course/services/course';
|
import { CoreCourse } from '@features/course/services/course';
|
||||||
import { CoreTimeUtils } from '@services/utils/time';
|
import { CoreTimeUtils } from '@services/utils/time';
|
||||||
import { CoreGroups } from '@services/groups';
|
import { CoreGroups } from '@services/groups';
|
||||||
import { Network, NgZone, Translate } from '@singletons';
|
import { NgZone, Translate } from '@singletons';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
|
@ -123,7 +123,7 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Refresh online status when changes.
|
// Refresh online status when changes.
|
||||||
this.onlineObserver = Network.onChange().subscribe(() => {
|
this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => {
|
NgZone.run(() => {
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
|
|
|
@ -23,7 +23,7 @@ import { AddonCalendar, AddonCalendarProvider } from '../../services/calendar';
|
||||||
import { AddonCalendarOffline } from '../../services/calendar-offline';
|
import { AddonCalendarOffline } from '../../services/calendar-offline';
|
||||||
import { AddonCalendarSync, AddonCalendarSyncProvider } from '../../services/calendar-sync';
|
import { AddonCalendarSync, AddonCalendarSyncProvider } from '../../services/calendar-sync';
|
||||||
import { AddonCalendarFilter, AddonCalendarHelper } from '../../services/calendar-helper';
|
import { AddonCalendarFilter, AddonCalendarHelper } from '../../services/calendar-helper';
|
||||||
import { Network, NgZone } from '@singletons';
|
import { NgZone } from '@singletons';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { CoreEnrolledCourseData } from '@features/courses/services/courses';
|
import { CoreEnrolledCourseData } from '@features/courses/services/courses';
|
||||||
import { ActivatedRoute, Params } from '@angular/router';
|
import { ActivatedRoute, Params } from '@angular/router';
|
||||||
|
@ -153,7 +153,7 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Refresh online status when changes.
|
// Refresh online status when changes.
|
||||||
this.onlineObserver = Network.onChange().subscribe(() => {
|
this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => {
|
NgZone.run(() => {
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
|
|
|
@ -32,7 +32,8 @@ import { CorePushNotificationsDelegate } from '@features/pushnotifications/servi
|
||||||
import { AddonMessagesPushClickHandler } from './services/handlers/push-click';
|
import { AddonMessagesPushClickHandler } from './services/handlers/push-click';
|
||||||
import { CoreUserDelegate } from '@features/user/services/user-delegate';
|
import { CoreUserDelegate } from '@features/user/services/user-delegate';
|
||||||
import { AddonMessagesSendMessageUserHandler } from './services/handlers/user-send-message';
|
import { AddonMessagesSendMessageUserHandler } from './services/handlers/user-send-message';
|
||||||
import { Network, NgZone } from '@singletons';
|
import { NgZone } from '@singletons';
|
||||||
|
import { CoreNetwork } from '@services/network';
|
||||||
import { AddonMessagesSync, AddonMessagesSyncProvider } from './services/messages-sync';
|
import { AddonMessagesSync, AddonMessagesSyncProvider } from './services/messages-sync';
|
||||||
import { AddonMessagesSyncCronHandler } from './services/handlers/sync-cron';
|
import { AddonMessagesSyncCronHandler } from './services/handlers/sync-cron';
|
||||||
import { CoreSitePreferencesRoutingModule } from '@features/settings/pages/site/site-routing';
|
import { CoreSitePreferencesRoutingModule } from '@features/settings/pages/site/site-routing';
|
||||||
|
@ -86,7 +87,7 @@ const preferencesRoutes: Routes = [
|
||||||
CoreUserDelegate.registerHandler(AddonMessagesSendMessageUserHandler.instance);
|
CoreUserDelegate.registerHandler(AddonMessagesSendMessageUserHandler.instance);
|
||||||
|
|
||||||
// Sync some discussions when device goes online.
|
// Sync some discussions when device goes online.
|
||||||
Network.onConnect().subscribe(() => {
|
CoreNetwork.onConnect().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => {
|
NgZone.run(() => {
|
||||||
AddonMessagesSync.syncAllDiscussions(undefined, true);
|
AddonMessagesSync.syncAllDiscussions(undefined, true);
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { CoreNetwork } from '@services/network';
|
import { CoreNetwork } from '@services/network';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { ModalController, Network, NgZone } from '@singletons';
|
import { ModalController, NgZone } from '@singletons';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { AddonModChat, AddonModChatUser } from '../../services/chat';
|
import { AddonModChat, AddonModChatUser } from '../../services/chat';
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ export class AddonModChatUsersModalComponent implements OnInit, OnDestroy {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
this.currentUserId = CoreSites.getCurrentSiteUserId();
|
this.currentUserId = CoreSites.getCurrentSiteUserId();
|
||||||
this.onlineSubscription = Network.onChange().subscribe(() => {
|
this.onlineSubscription = CoreNetwork.onChange().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => {
|
NgZone.run(() => {
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
|
|
|
@ -23,7 +23,7 @@ import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { Network, NgZone, Translate } from '@singletons';
|
import { NgZone, Translate } from '@singletons';
|
||||||
import { CoreEvents } from '@singletons/events';
|
import { CoreEvents } from '@singletons/events';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { AddonModChatUsersModalComponent, AddonModChatUsersModalResult } from '../../components/users-modal/users-modal';
|
import { AddonModChatUsersModalComponent, AddonModChatUsersModalResult } from '../../components/users-modal/users-modal';
|
||||||
|
@ -67,7 +67,7 @@ export class AddonModChatChatPage implements OnInit, OnDestroy, CanLeave {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.currentUserId = CoreSites.getCurrentSiteUserId();
|
this.currentUserId = CoreSites.getCurrentSiteUserId();
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
this.onlineSubscription = Network.onChange().subscribe(() => {
|
this.onlineSubscription = CoreNetwork.onChange().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => {
|
NgZone.run(() => {
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
|
|
|
@ -24,7 +24,7 @@ import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
|
import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { Network, NgZone, Translate } from '@singletons';
|
import { NgZone, Translate } from '@singletons';
|
||||||
import { CoreEvents } from '@singletons/events';
|
import { CoreEvents } from '@singletons/events';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
|
@ -80,7 +80,7 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
this.currentSite = CoreSites.getRequiredCurrentSite();
|
this.currentSite = CoreSites.getRequiredCurrentSite();
|
||||||
|
|
||||||
// Refresh online status when changes.
|
// Refresh online status when changes.
|
||||||
this.onlineObserver = Network.onChange().subscribe(() => {
|
this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => {
|
NgZone.run(() => {
|
||||||
this.offline = !CoreNetwork.isOnline();
|
this.offline = !CoreNetwork.isOnline();
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { CoreScreen } from '@services/screen';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { Network, NgZone, Translate } from '@singletons';
|
import { NgZone, Translate } from '@singletons';
|
||||||
import { CoreArray } from '@singletons/array';
|
import { CoreArray } from '@singletons/array';
|
||||||
import { CoreDom } from '@singletons/dom';
|
import { CoreDom } from '@singletons/dom';
|
||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
|
@ -166,7 +166,7 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes
|
||||||
|
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
this.externalUrl = CoreSites.getCurrentSite()?.createSiteUrl('/mod/forum/discuss.php', { d: this.discussionId.toString() });
|
this.externalUrl = CoreSites.getCurrentSite()?.createSiteUrl('/mod/forum/discuss.php', { d: this.discussionId.toString() });
|
||||||
this.onlineObserver = Network.onChange().subscribe(() => {
|
this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => {
|
NgZone.run(() => {
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
|
|
|
@ -27,7 +27,7 @@ import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
import { CoreTextUtils } from '@services/utils/text';
|
||||||
import { CoreUtils, OpenFileAction } from '@services/utils/utils';
|
import { CoreUtils, OpenFileAction } from '@services/utils/utils';
|
||||||
import { Network, NgZone, Translate } from '@singletons';
|
import { NgZone, Translate } from '@singletons';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
AddonModResource,
|
AddonModResource,
|
||||||
|
@ -83,7 +83,7 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
|
|
||||||
// Refresh online status when changes.
|
// Refresh online status when changes.
|
||||||
this.onlineObserver = Network.onChange().subscribe(() => {
|
this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => {
|
NgZone.run(() => {
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
|
|
|
@ -27,7 +27,7 @@ import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { Network, Translate, NgZone } from '@singletons';
|
import { Translate, NgZone } from '@singletons';
|
||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
import { CoreText } from '@singletons/text';
|
import { CoreText } from '@singletons/text';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
|
@ -119,7 +119,7 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
|
|
||||||
// Refresh online status when changes.
|
// Refresh online status when changes.
|
||||||
this.onlineSubscription = Network.onChange().subscribe(() => {
|
this.onlineSubscription = CoreNetwork.onChange().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => {
|
NgZone.run(() => {
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
|
|
|
@ -19,7 +19,8 @@ import { BackButtonEvent, ScrollDetail } from '@ionic/core';
|
||||||
import { CoreLang } from '@services/lang';
|
import { CoreLang } from '@services/lang';
|
||||||
import { CoreLoginHelper } from '@features/login/services/login-helper';
|
import { CoreLoginHelper } from '@features/login/services/login-helper';
|
||||||
import { CoreEvents } from '@singletons/events';
|
import { CoreEvents } from '@singletons/events';
|
||||||
import { Network, NgZone, Platform, SplashScreen, Translate } from '@singletons';
|
import { NgZone, Platform, SplashScreen, Translate } from '@singletons';
|
||||||
|
import { CoreNetwork } from '@services/network';
|
||||||
import { CoreApp, CoreAppProvider } from '@services/app';
|
import { CoreApp, CoreAppProvider } from '@services/app';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
|
@ -32,7 +33,6 @@ import { CoreConstants } from '@/core/constants';
|
||||||
import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins';
|
import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreDom } from '@singletons/dom';
|
import { CoreDom } from '@singletons/dom';
|
||||||
import { CoreNetwork } from '@services/network';
|
|
||||||
|
|
||||||
const MOODLE_VERSION_PREFIX = 'version-';
|
const MOODLE_VERSION_PREFIX = 'version-';
|
||||||
const MOODLEAPP_VERSION_PREFIX = 'moodleapp-';
|
const MOODLEAPP_VERSION_PREFIX = 'moodleapp-';
|
||||||
|
@ -308,7 +308,7 @@ export class AppComponent implements OnInit, AfterViewInit {
|
||||||
await Platform.ready();
|
await Platform.ready();
|
||||||
|
|
||||||
// Refresh online status when changes.
|
// Refresh online status when changes.
|
||||||
Network.onChange().subscribe(() => {
|
CoreNetwork.onChange().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => {
|
NgZone.run(() => {
|
||||||
const isOnline = CoreNetwork.isOnline();
|
const isOnline = CoreNetwork.isOnline();
|
||||||
|
|
|
@ -30,7 +30,7 @@ import {
|
||||||
import { IonContent, IonRefresher } from '@ionic/angular';
|
import { IonContent, IonRefresher } from '@ionic/angular';
|
||||||
import { ContextLevel, CoreConstants } from '@/core/constants';
|
import { ContextLevel, CoreConstants } from '@/core/constants';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { Network, NgZone, Translate } from '@singletons';
|
import { NgZone, Translate } from '@singletons';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreUser } from '@features/user/services/user';
|
import { CoreUser } from '@features/user/services/user';
|
||||||
|
@ -110,7 +110,7 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy {
|
||||||
}, CoreSites.getCurrentSiteId());
|
}, CoreSites.getCurrentSiteId());
|
||||||
|
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
this.onlineObserver = Network.onChange().subscribe(() => {
|
this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => {
|
NgZone.run(() => {
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
import { CoreTextUtils } from '@services/utils/text';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { ModalController, Network, NgZone } from '@singletons';
|
import { ModalController, NgZone } from '@singletons';
|
||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ export class CoreCourseModuleSummaryComponent implements OnInit, OnDestroy {
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
|
|
||||||
// Refresh online status when changes.
|
// Refresh online status when changes.
|
||||||
this.onlineSubscription = Network.onChange().subscribe(() => {
|
this.onlineSubscription = CoreNetwork.onChange().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => {
|
NgZone.run(() => {
|
||||||
this.isOnline = CoreNetwork.isOnline();
|
this.isOnline = CoreNetwork.isOnline();
|
||||||
|
|
|
@ -81,8 +81,8 @@ import { FileTransferMock } from './services/file-transfer';
|
||||||
import { GeolocationMock } from './services/geolocation';
|
import { GeolocationMock } from './services/geolocation';
|
||||||
import { InAppBrowserMock } from './services/inappbrowser';
|
import { InAppBrowserMock } from './services/inappbrowser';
|
||||||
import { MediaCaptureMock } from './services/media-capture';
|
import { MediaCaptureMock } from './services/media-capture';
|
||||||
import { NetworkMock } from './services/network';
|
|
||||||
import { ZipMock } from './services/zip';
|
import { ZipMock } from './services/zip';
|
||||||
|
import { CoreNetworkService } from '@services/network';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This module handles the emulation of Cordova plugins in browser and desktop.
|
* This module handles the emulation of Cordova plugins in browser and desktop.
|
||||||
|
@ -152,11 +152,7 @@ import { ZipMock } from './services/zip';
|
||||||
deps: [Platform],
|
deps: [Platform],
|
||||||
useFactory: (platform: Platform): MediaCapture => platform.is('cordova') ? new MediaCapture() : new MediaCaptureMock(),
|
useFactory: (platform: Platform): MediaCapture => platform.is('cordova') ? new MediaCapture() : new MediaCaptureMock(),
|
||||||
},
|
},
|
||||||
{
|
CoreNetworkService,
|
||||||
provide: Network,
|
|
||||||
deps: [Platform],
|
|
||||||
useFactory: (platform: Platform): Network => platform.is('cordova') ? new Network() : new NetworkMock(),
|
|
||||||
},
|
|
||||||
Push,
|
Push,
|
||||||
QRScanner,
|
QRScanner,
|
||||||
SplashScreen,
|
SplashScreen,
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
// (C) Copyright 2015 Moodle Pty Ltd.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { Network } from '@ionic-native/network/ngx';
|
|
||||||
import { Observable, Subject, merge } from 'rxjs';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emulates the Cordova Network plugin in browser.
|
|
||||||
*/
|
|
||||||
@Injectable()
|
|
||||||
export class NetworkMock extends Network {
|
|
||||||
|
|
||||||
type!: string;
|
|
||||||
|
|
||||||
protected connectObservable = new Subject<'connected'>();
|
|
||||||
protected disconnectObservable = new Subject<'disconnected'>();
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
(<any> window).Connection = {
|
|
||||||
UNKNOWN: 'unknown', // eslint-disable-line @typescript-eslint/naming-convention
|
|
||||||
ETHERNET: 'ethernet', // eslint-disable-line @typescript-eslint/naming-convention
|
|
||||||
WIFI: 'wifi', // eslint-disable-line @typescript-eslint/naming-convention
|
|
||||||
CELL_2G: '2g', // eslint-disable-line @typescript-eslint/naming-convention
|
|
||||||
CELL_3G: '3g', // eslint-disable-line @typescript-eslint/naming-convention
|
|
||||||
CELL_4G: '4g', // eslint-disable-line @typescript-eslint/naming-convention
|
|
||||||
CELL: 'cellular', // eslint-disable-line @typescript-eslint/naming-convention
|
|
||||||
NONE: 'none', // eslint-disable-line @typescript-eslint/naming-convention
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener('online', () => {
|
|
||||||
this.connectObservable.next('connected');
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
window.addEventListener('offline', () => {
|
|
||||||
this.disconnectObservable.next('disconnected');
|
|
||||||
}, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable to watch connection changes.
|
|
||||||
*
|
|
||||||
* @return Observable.
|
|
||||||
*/
|
|
||||||
onChange(): Observable<'connected' | 'disconnected'> {
|
|
||||||
return merge(this.connectObservable, this.disconnectObservable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable to notify when the app is connected.
|
|
||||||
*
|
|
||||||
* @return Observable.
|
|
||||||
*/
|
|
||||||
onConnect(): Observable<'connected'> {
|
|
||||||
return this.connectObservable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an observable to notify when the app is disconnected.
|
|
||||||
*
|
|
||||||
* @return Observable.
|
|
||||||
*/
|
|
||||||
onDisconnect(): Observable<'disconnected'> {
|
|
||||||
return this.disconnectObservable;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -16,7 +16,7 @@ import { CoreApp } from '@services/app';
|
||||||
import { Component, OnDestroy } from '@angular/core';
|
import { Component, OnDestroy } from '@angular/core';
|
||||||
import { CoreConstants } from '@/core/constants';
|
import { CoreConstants } from '@/core/constants';
|
||||||
import { CoreLocalNotifications } from '@services/local-notifications';
|
import { CoreLocalNotifications } from '@services/local-notifications';
|
||||||
import { Device, Platform, Translate, Network, NgZone } from '@singletons';
|
import { Device, Platform, Translate, NgZone } from '@singletons';
|
||||||
import { CoreLang } from '@services/lang';
|
import { CoreLang } from '@services/lang';
|
||||||
import { CoreFile } from '@services/file';
|
import { CoreFile } from '@services/file';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
|
@ -82,7 +82,6 @@ export class CoreSettingsDeviceInfoPage implements OnDestroy {
|
||||||
protected onlineObserver?: Subscription;
|
protected onlineObserver?: Subscription;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const appProvider = CoreApp.instance;
|
|
||||||
const sitesProvider = CoreSites.instance;
|
const sitesProvider = CoreSites.instance;
|
||||||
const device = Device.instance;
|
const device = Device.instance;
|
||||||
const translate = Translate.instance;
|
const translate = Translate.instance;
|
||||||
|
@ -112,10 +111,10 @@ export class CoreSettingsDeviceInfoPage implements OnDestroy {
|
||||||
|
|
||||||
if (CorePlatform.isMobile()) {
|
if (CorePlatform.isMobile()) {
|
||||||
this.deviceInfo.deviceType = Platform.is('tablet') ? 'tablet' : 'phone';
|
this.deviceInfo.deviceType = Platform.is('tablet') ? 'tablet' : 'phone';
|
||||||
if (appProvider.isAndroid()) {
|
if (CoreApp.isAndroid()) {
|
||||||
this.deviceInfo.deviceOs = 'android';
|
this.deviceInfo.deviceOs = 'android';
|
||||||
this.deviceOsTranslated = 'Android';
|
this.deviceOsTranslated = 'Android';
|
||||||
} else if (appProvider.isIOS()) {
|
} else if (CoreApp.isIOS()) {
|
||||||
this.deviceInfo.deviceOs = 'ios';
|
this.deviceInfo.deviceOs = 'ios';
|
||||||
this.deviceOsTranslated = 'iOS';
|
this.deviceOsTranslated = 'iOS';
|
||||||
} else {
|
} else {
|
||||||
|
@ -177,7 +176,7 @@ export class CoreSettingsDeviceInfoPage implements OnDestroy {
|
||||||
this.deviceInfo.siteVersion = currentSite?.getInfo()?.release;
|
this.deviceInfo.siteVersion = currentSite?.getInfo()?.release;
|
||||||
|
|
||||||
// Refresh online status when changes.
|
// Refresh online status when changes.
|
||||||
this.onlineObserver = Network.onChange().subscribe(() => {
|
this.onlineObserver = CoreNetwork.onChange().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => {
|
NgZone.run(() => {
|
||||||
this.deviceInfo.networkStatus = CoreNetwork.isOnline() ? 'online' : 'offline';
|
this.deviceInfo.networkStatus = CoreNetwork.isOnline() ? 'online' : 'offline';
|
||||||
|
|
|
@ -13,11 +13,12 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { CoreCronDelegate } from '@services/cron';
|
import { CoreCronDelegate } from '@services/cron';
|
||||||
import { Network, NgZone } from '@singletons';
|
import { NgZone } from '@singletons';
|
||||||
|
import { CoreNetwork } from '@services/network';
|
||||||
|
|
||||||
export default function(): void {
|
export default function(): void {
|
||||||
// When the app is re-connected, start network handlers that were stopped.
|
// When the app is re-connected, start network handlers that were stopped.
|
||||||
Network.onConnect().subscribe(() => {
|
CoreNetwork.onConnect().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => CoreCronDelegate.startNetworkHandlers());
|
NgZone.run(() => CoreCronDelegate.startNetworkHandlers());
|
||||||
});
|
});
|
||||||
|
|
|
@ -31,7 +31,7 @@ import { CoreUtils, CoreUtilsOpenFileOptions } from '@services/utils/utils';
|
||||||
import { SQLiteDB } from '@classes/sqlitedb';
|
import { SQLiteDB } from '@classes/sqlitedb';
|
||||||
import { CoreError } from '@classes/errors/error';
|
import { CoreError } from '@classes/errors/error';
|
||||||
import { CoreConstants } from '@/core/constants';
|
import { CoreConstants } from '@/core/constants';
|
||||||
import { ApplicationInit, makeSingleton, Network, NgZone, Translate } from '@singletons';
|
import { ApplicationInit, makeSingleton, NgZone, Translate } from '@singletons';
|
||||||
import { CoreLogger } from '@singletons/logger';
|
import { CoreLogger } from '@singletons/logger';
|
||||||
import {
|
import {
|
||||||
APP_SCHEMA,
|
APP_SCHEMA,
|
||||||
|
@ -150,7 +150,7 @@ export class CoreFilepoolProvider {
|
||||||
this.checkQueueProcessing();
|
this.checkQueueProcessing();
|
||||||
|
|
||||||
// Start queue when device goes online.
|
// Start queue when device goes online.
|
||||||
Network.onConnect().subscribe(() => {
|
CoreNetwork.onConnect().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => this.checkQueueProcessing());
|
NgZone.run(() => this.checkQueueProcessing());
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,15 +14,56 @@
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { CorePlatform } from '@services/platform';
|
import { CorePlatform } from '@services/platform';
|
||||||
import { makeSingleton, Network } from '@singletons';
|
import { Network as NetworkService } from '@ionic-native/network/ngx';
|
||||||
|
import { makeSingleton } from '@singletons';
|
||||||
|
import { Observable, Subject, merge } from 'rxjs';
|
||||||
|
|
||||||
|
const Network = makeSingleton(NetworkService);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to manage network information.
|
* Service to manage network connections.
|
||||||
*/
|
*/
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class CoreNetworkService {
|
export class CoreNetworkService extends NetworkService {
|
||||||
|
|
||||||
|
type!: string;
|
||||||
|
|
||||||
|
protected connectObservable = new Subject<'connected'>();
|
||||||
|
protected disconnectObservable = new Subject<'disconnected'>();
|
||||||
protected forceOffline = false;
|
protected forceOffline = false;
|
||||||
|
protected online = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.checkOnline();
|
||||||
|
|
||||||
|
if (CorePlatform.isMobile()) {
|
||||||
|
Network.onChange().subscribe(() => {
|
||||||
|
this.fireObservable();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
(<any> window).Connection = {
|
||||||
|
UNKNOWN: 'unknown', // eslint-disable-line @typescript-eslint/naming-convention
|
||||||
|
ETHERNET: 'ethernet', // eslint-disable-line @typescript-eslint/naming-convention
|
||||||
|
WIFI: 'wifi', // eslint-disable-line @typescript-eslint/naming-convention
|
||||||
|
CELL_2G: '2g', // eslint-disable-line @typescript-eslint/naming-convention
|
||||||
|
CELL_3G: '3g', // eslint-disable-line @typescript-eslint/naming-convention
|
||||||
|
CELL_4G: '4g', // eslint-disable-line @typescript-eslint/naming-convention
|
||||||
|
CELL: 'cellular', // eslint-disable-line @typescript-eslint/naming-convention
|
||||||
|
NONE: 'none', // eslint-disable-line @typescript-eslint/naming-convention
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('online', () => {
|
||||||
|
this.fireObservable();
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
window.addEventListener('offline', () => {
|
||||||
|
this.fireObservable();
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set value of forceOffline flag. If true, the app will think the device is offline.
|
* Set value of forceOffline flag. If true, the app will think the device is offline.
|
||||||
|
@ -31,6 +72,7 @@ export class CoreNetworkService {
|
||||||
*/
|
*/
|
||||||
setForceOffline(value: boolean): void {
|
setForceOffline(value: boolean): void {
|
||||||
this.forceOffline = !!value;
|
this.forceOffline = !!value;
|
||||||
|
this.fireObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,23 +81,77 @@ export class CoreNetworkService {
|
||||||
* @return Whether the app is online.
|
* @return Whether the app is online.
|
||||||
*/
|
*/
|
||||||
isOnline(): boolean {
|
isOnline(): boolean {
|
||||||
|
return this.online;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether we are online.
|
||||||
|
*
|
||||||
|
* @return Whether the app is online.
|
||||||
|
*/
|
||||||
|
checkOnline(): void {
|
||||||
if (this.forceOffline) {
|
if (this.forceOffline) {
|
||||||
return false;
|
this.online = false;
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CorePlatform.isMobile()) {
|
if (!CorePlatform.isMobile()) {
|
||||||
return navigator.onLine;
|
this.online = navigator.onLine;
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let online = Network.type !== null && Network.type != Network.Connection.NONE &&
|
let online = this.type !== null && this.type != this.Connection.NONE &&
|
||||||
Network.type != Network.Connection.UNKNOWN;
|
this.type != this.Connection.UNKNOWN;
|
||||||
|
|
||||||
// Double check we are not online because we cannot rely 100% in Cordova APIs.
|
// Double check we are not online because we cannot rely 100% in Cordova APIs.
|
||||||
if (!online && navigator.onLine) {
|
if (!online && navigator.onLine) {
|
||||||
online = true;
|
online = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return online;
|
this.online = online;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an observable to watch connection changes.
|
||||||
|
*
|
||||||
|
* @return Observable.
|
||||||
|
*/
|
||||||
|
onChange(): Observable<'connected' | 'disconnected'> {
|
||||||
|
return merge(this.connectObservable, this.disconnectObservable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an observable to notify when the app is connected.
|
||||||
|
*
|
||||||
|
* @return Observable.
|
||||||
|
*/
|
||||||
|
onConnect(): Observable<'connected'> {
|
||||||
|
return this.connectObservable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an observable to notify when the app is disconnected.
|
||||||
|
*
|
||||||
|
* @return Observable.
|
||||||
|
*/
|
||||||
|
onDisconnect(): Observable<'disconnected'> {
|
||||||
|
return this.disconnectObservable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires the correct observable depending on the connection status.
|
||||||
|
*/
|
||||||
|
protected fireObservable(): void {
|
||||||
|
const previousOnline = this.online;
|
||||||
|
|
||||||
|
this.checkOnline();
|
||||||
|
if (this.online && !previousOnline) {
|
||||||
|
this.connectObservable.next('connected');
|
||||||
|
} else if (!this.online && previousOnline) {
|
||||||
|
this.disconnectObservable.next('disconnected');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -25,7 +25,7 @@ import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreUrlUtils } from '@services/utils/url';
|
import { CoreUrlUtils } from '@services/utils/url';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
|
|
||||||
import { makeSingleton, Network, NgZone, Translate, Diagnostic } from '@singletons';
|
import { makeSingleton, NgZone, Translate, Diagnostic } from '@singletons';
|
||||||
import { CoreLogger } from '@singletons/logger';
|
import { CoreLogger } from '@singletons/logger';
|
||||||
import { CoreUrl } from '@singletons/url';
|
import { CoreUrl } from '@singletons/url';
|
||||||
import { CoreWindow } from '@singletons/window';
|
import { CoreWindow } from '@singletons/window';
|
||||||
|
@ -76,7 +76,7 @@ export class CoreIframeUtilsProvider {
|
||||||
this.addOfflineWarning(element, src, isSubframe);
|
this.addOfflineWarning(element, src, isSubframe);
|
||||||
|
|
||||||
// If the network changes, check it again.
|
// If the network changes, check it again.
|
||||||
const subscription = Network.onConnect().subscribe(() => {
|
const subscription = CoreNetwork.onConnect().subscribe(() => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
NgZone.run(() => {
|
NgZone.run(() => {
|
||||||
if (!this.checkOnlineFrameInOffline(element, isSubframe)) {
|
if (!this.checkOnlineFrameInOffline(element, isSubframe)) {
|
||||||
|
|
|
@ -187,6 +187,9 @@ export const LocalNotifications = makeSingleton(LocalNotificationsService);
|
||||||
export const Media = makeSingleton(MediaService);
|
export const Media = makeSingleton(MediaService);
|
||||||
export const MediaCapture = makeSingleton(MediaCaptureService);
|
export const MediaCapture = makeSingleton(MediaCaptureService);
|
||||||
export const NativeHttp = makeSingleton(HTTP);
|
export const NativeHttp = makeSingleton(HTTP);
|
||||||
|
/**
|
||||||
|
* @deprecated on 4.1 use CoreNetwork instead.
|
||||||
|
*/
|
||||||
export const Network = makeSingleton(NetworkService);
|
export const Network = makeSingleton(NetworkService);
|
||||||
export const Push = makeSingleton(PushService);
|
export const Push = makeSingleton(PushService);
|
||||||
export const QRScanner = makeSingleton(QRScannerService);
|
export const QRScanner = makeSingleton(QRScannerService);
|
||||||
|
|
|
@ -19,11 +19,12 @@ import { Observable, Subject } from 'rxjs';
|
||||||
import { sep } from 'path';
|
import { sep } from 'path';
|
||||||
|
|
||||||
import { CORE_SITE_SCHEMAS } from '@services/sites';
|
import { CORE_SITE_SCHEMAS } from '@services/sites';
|
||||||
import { CoreSingletonProxy, Network, Platform, Translate } from '@singletons';
|
import { CoreSingletonProxy, Platform, Translate } from '@singletons';
|
||||||
import { CoreTextUtilsProvider } from '@services/utils/text';
|
import { CoreTextUtilsProvider } from '@services/utils/text';
|
||||||
|
|
||||||
import { TranslatePipeStub } from './stubs/pipes/translate';
|
import { TranslatePipeStub } from './stubs/pipes/translate';
|
||||||
import { CoreExternalContentDirectiveStub } from './stubs/directives/core-external-content';
|
import { CoreExternalContentDirectiveStub } from './stubs/directives/core-external-content';
|
||||||
|
import { CoreNetwork } from '@services/network';
|
||||||
|
|
||||||
abstract class WrapperComponent<U> {
|
abstract class WrapperComponent<U> {
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ let testBedInitialized = false;
|
||||||
const textUtils = new CoreTextUtilsProvider();
|
const textUtils = new CoreTextUtilsProvider();
|
||||||
const DEFAULT_SERVICE_SINGLETON_MOCKS: [CoreSingletonProxy, Record<string, unknown>][] = [
|
const DEFAULT_SERVICE_SINGLETON_MOCKS: [CoreSingletonProxy, Record<string, unknown>][] = [
|
||||||
[Platform, mock({ is: () => false, ready: () => Promise.resolve(), resume: new Subject<void>() })],
|
[Platform, mock({ is: () => false, ready: () => Promise.resolve(), resume: new Subject<void>() })],
|
||||||
[Network, { onChange: () => new Observable() }],
|
[CoreNetwork, { onChange: () => new Observable() }],
|
||||||
];
|
];
|
||||||
|
|
||||||
async function renderAngularComponent<T>(component: Type<T>, config: RenderConfig): Promise<ComponentFixture<T>> {
|
async function renderAngularComponent<T>(component: Type<T>, config: RenderConfig): Promise<ComponentFixture<T>> {
|
||||||
|
|
Loading…
Reference in New Issue