Merge pull request #3666 from dpalou/MOBILE-4270

Mobile 4270
main
Pau Ferrer Ocaña 2023-05-10 10:14:32 +02:00 committed by GitHub
commit 0afc1bb2cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 62 additions and 17 deletions

View File

@ -87,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.
CoreNetwork.onConnect().subscribe(() => { CoreNetwork.onConnectShouldBeStable().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);

View File

@ -65,7 +65,7 @@
<!-- Template to render a list of conversations. --> <!-- Template to render a list of conversations. -->
<ng-template #attemptsTemplate let-attempts="attempts"> <ng-template #attemptsTemplate let-attempts="attempts">
<!-- "Header" of the table --> <!-- "Header" of the table -->
<ion-item class="ion-text-wrap addon-mod_h5pactivity-table-header hide-detail" detail="true"> <ion-item class="addon-mod_h5pactivity-table-header hide-detail" detail="true">
<ion-label> <ion-label>
<ion-row class="ion-align-items-center"> <ion-row class="ion-align-items-center">
<ion-col class="ion-text-center">#</ion-col> <ion-col class="ion-text-center">#</ion-col>

View File

@ -1,6 +1,11 @@
:host { :host {
.addon-mod_h5pactivity-table-header { .addon-mod_h5pactivity-table-header {
font-weight: bold; font-weight: bold;
ion-col {
overflow: hidden;
text-overflow: ellipsis;
}
} }
.addon-mod_h5pactivity-table-row .addon-mod_h5pactivity-table-success-col { .addon-mod_h5pactivity-table-row .addon-mod_h5pactivity-table-success-col {

View File

@ -31,9 +31,9 @@
</ion-item> </ion-item>
<!-- List of users. --> <!-- List of users. -->
<ion-item class="ion-text-wrap addon-mod_h5pactivity-table-row" *ngFor="let user of users" detail="true" button <ion-item class="ion-text-wrap addon-mod_h5pactivity-table-row" *ngFor="let user of users" detail="true"
[attr.aria-label]="'addon.mod_h5pactivity.review_user_attempts' | translate:{$a: user.attempts.length}" [attr.aria-label]="'addon.mod_h5pactivity.review_user_attempts' | translate:{$a: user.attempts.length}"
(click)="openUser(user)"> (click)="openUser(user)" [class.hide-detail]="!user.attempts.length" [button]="user.attempts.length > 0">
<ion-label> <ion-label>
<ion-row class="ion-align-items-center"> <ion-row class="ion-align-items-center">

View File

@ -0,0 +1,6 @@
:host {
.addon-mod_h5pactivity-table-header ion-col {
overflow: hidden;
text-overflow: ellipsis;
}
}

View File

@ -32,6 +32,7 @@ import {
@Component({ @Component({
selector: 'page-addon-mod-h5pactivity-users-attempts', selector: 'page-addon-mod-h5pactivity-users-attempts',
templateUrl: 'users-attempts.html', templateUrl: 'users-attempts.html',
styleUrls: ['users-attempts.scss'],
}) })
export class AddonModH5PActivityUsersAttemptsPage implements OnInit { export class AddonModH5PActivityUsersAttemptsPage implements OnInit {
@ -208,6 +209,10 @@ export class AddonModH5PActivityUsersAttemptsPage implements OnInit {
* @param user User to open. * @param user User to open.
*/ */
openUser(user: AddonModH5PActivityUserAttemptsFormatted): void { openUser(user: AddonModH5PActivityUserAttemptsFormatted): void {
if (!user.attempts.length) {
return;
}
CoreNavigator.navigate(`../userattempts/${user.userid}`); CoreNavigator.navigate(`../userattempts/${user.userid}`);
} }

View File

@ -98,12 +98,12 @@ export class AddonNotesListPage implements OnInit, OnDestroy {
* Fetch notes. * Fetch notes.
* *
* @param sync When to resync notes. * @param sync When to resync notes.
* @param showErrors When to display errors or not. * @param showSyncErrors When to display sync errors or not.
* @returns Promise with the notes. * @returns Promise with the notes.
*/ */
protected async fetchNotes(sync = false, showErrors = false): Promise<void> { protected async fetchNotes(sync = false, showSyncErrors = false): Promise<void> {
if (sync) { if (sync) {
await this.syncNotes(showErrors); await this.syncNotes(showSyncErrors);
} }
try { try {
@ -150,15 +150,15 @@ export class AddonNotesListPage implements OnInit, OnDestroy {
/** /**
* Refresh notes on PTR. * Refresh notes on PTR.
* *
* @param showErrors Whether to display errors or not. * @param showSyncErrors Whether to display sync errors or not.
* @param refresher Refresher instance. * @param refresher Refresher instance.
*/ */
refreshNotes(showErrors: boolean, refresher?: IonRefresher): void { refreshNotes(showSyncErrors: boolean, refresher?: IonRefresher): void {
this.refreshIcon = CoreConstants.ICON_LOADING; this.refreshIcon = CoreConstants.ICON_LOADING;
this.syncIcon = CoreConstants.ICON_LOADING; this.syncIcon = CoreConstants.ICON_LOADING;
AddonNotes.invalidateNotes(this.courseId, this.userId).finally(() => { AddonNotes.invalidateNotes(this.courseId, this.userId).finally(() => {
this.fetchNotes(true, showErrors).finally(() => { this.fetchNotes(true, showSyncErrors).finally(() => {
if (refresher) { if (refresher) {
refresher?.complete(); refresher?.complete();
} }
@ -253,7 +253,7 @@ export class AddonNotesListPage implements OnInit, OnDestroy {
e.stopPropagation(); e.stopPropagation();
await AddonNotesOffline.undoDeleteNote(note.id); await AddonNotesOffline.undoDeleteNote(note.id);
this.refreshNotes(true); this.refreshNotes(false);
} }
/** /**
@ -266,16 +266,16 @@ export class AddonNotesListPage implements OnInit, OnDestroy {
/** /**
* Tries to synchronize course notes. * Tries to synchronize course notes.
* *
* @param showErrors Whether to display errors or not. * @param showSyncErrors Whether to display sync errors or not.
* @returns Promise resolved when done. * @returns Promise resolved when done.
*/ */
protected async syncNotes(showErrors: boolean): Promise<void> { protected async syncNotes(showSyncErrors: boolean): Promise<void> {
try { try {
const result = await AddonNotesSync.syncNotes(this.courseId); const result = await AddonNotesSync.syncNotes(this.courseId);
this.showSyncWarnings(result.warnings); this.showSyncWarnings(result.warnings);
} catch (error) { } catch (error) {
if (showErrors) { if (showSyncErrors) {
CoreDomUtils.showErrorModalDefault(error, 'core.errorsync', true); CoreDomUtils.showErrorModalDefault(error, 'core.errorsync', true);
} }
} }

View File

@ -196,10 +196,15 @@ export class AppComponent implements OnInit, AfterViewInit {
*/ */
ngAfterViewInit(): void { ngAfterViewInit(): void {
if (!this.outlet) { if (!this.outlet) {
this.logger.debug('Aftew view init: no outlet found');
return; return;
} }
this.logger.debug('Aftew view init');
CoreSubscriptions.once(this.outlet.activateEvents, async () => { CoreSubscriptions.once(this.outlet.activateEvents, async () => {
this.logger.debug('Activate event triggered');
await CorePlatform.ready(); await CorePlatform.ready();
this.logger.debug('Hide splash screen'); this.logger.debug('Hide splash screen');
@ -213,6 +218,8 @@ export class AppComponent implements OnInit, AfterViewInit {
protected async onPlatformReady(): Promise<void> { protected async onPlatformReady(): Promise<void> {
await CorePlatform.ready(); await CorePlatform.ready();
this.logger.debug('Platform is ready');
// Refresh online status when changes. // Refresh online status when changes.
CoreNetwork.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.

View File

@ -16,9 +16,12 @@ import { CoreCronDelegate } from '@services/cron';
import { NgZone } from '@singletons'; import { NgZone } from '@singletons';
import { CoreNetwork } from '@services/network'; import { CoreNetwork } from '@services/network';
/**
* Initializer function.
*/
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.
CoreNetwork.onConnect().subscribe(() => { CoreNetwork.onConnectShouldBeStable().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());
}); });

View File

@ -150,7 +150,7 @@ export class CoreFilepoolProvider {
this.checkQueueProcessing(); this.checkQueueProcessing();
// Start queue when device goes online. // Start queue when device goes online.
CoreNetwork.onConnect().subscribe(() => { CoreNetwork.onConnectShouldBeStable().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());
}); });

View File

@ -38,9 +38,11 @@ export class CoreNetworkService extends Network {
type!: string; type!: string;
protected connectObservable = new Subject<'connected'>(); protected connectObservable = new Subject<'connected'>();
protected connectStableObservable = new Subject<'connected'>();
protected disconnectObservable = new Subject<'disconnected'>(); protected disconnectObservable = new Subject<'disconnected'>();
protected forceConnectionMode?: CoreNetworkConnection; protected forceConnectionMode?: CoreNetworkConnection;
protected online = false; protected online = false;
protected connectStableTimeout?: number;
get connectionType(): CoreNetworkConnection { get connectionType(): CoreNetworkConnection {
if (this.forceConnectionMode !== undefined) { if (this.forceConnectionMode !== undefined) {
@ -146,6 +148,7 @@ export class CoreNetworkService extends Network {
/** /**
* Returns an observable to notify when the app is connected. * Returns an observable to notify when the app is connected.
* It will also be fired when connection type changes. * It will also be fired when connection type changes.
* If you're going to perform network requests once the device is connected, please use onConnectShouldBeStable instead.
* *
* @returns Observable. * @returns Observable.
*/ */
@ -153,6 +156,18 @@ export class CoreNetworkService extends Network {
return this.connectObservable; return this.connectObservable;
} }
/**
* Returns an observable to notify when the app is connected and it should already be a stable a connection.
* E.g. when leaving flight mode the device could connect to mobile network first and then to WiFi.
* If you're going to perform network requests once the device is connected, it's recommended to use this function instead of
* onConnect because some OS (e.g. Android) duplicate a request if the type of connection changes while the request is done.
*
* @returns Observable.
*/
onConnectShouldBeStable(): Observable<'connected'> {
return this.connectStableObservable;
}
/** /**
* Returns an observable to notify when the app is disconnected. * Returns an observable to notify when the app is disconnected.
* *
@ -166,10 +181,14 @@ export class CoreNetworkService extends Network {
* Fires the correct observable depending on the connection status. * Fires the correct observable depending on the connection status.
*/ */
protected fireObservable(): void { protected fireObservable(): void {
clearTimeout(this.connectStableTimeout);
this.checkOnline(); this.checkOnline();
if (this.online) { if (this.online) {
this.connectObservable.next('connected'); this.connectObservable.next('connected');
this.connectStableTimeout = window.setTimeout(() => {
this.connectStableObservable.next('connected');
}, 5000);
} else { } else {
this.disconnectObservable.next('disconnected'); this.disconnectObservable.next('disconnected');
} }

View File

@ -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 = CoreNetwork.onConnect().subscribe(() => { const subscription = CoreNetwork.onConnectShouldBeStable().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)) {