Skip to content

Mobile 4842 - Additional signals #4496

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions local_moodleappbehat/tests/behat/behat_app.php
Original file line number Diff line number Diff line change
Expand Up @@ -1179,15 +1179,16 @@ public function i_switch_offline_mode(string $offline) {
public function i_switch_network_connection(string $mode) {
switch ($mode) {
case 'wifi':
$this->runtime_js("network.setForceConnectionMode('$mode');");
$this->runtime_js("network.setForceConnectionMode('not_measured');");
break;
case 'cellular':
$this->runtime_js("network.setForceConnectionMode('$mode');");
$this->runtime_js("network.setForceConnectionMode('measured');");
break;
case 'offline':
$this->runtime_js("network.setForceConnectionMode('none');");
$this->runtime_js("network.setForceConnectionMode('offline');");
break;
default:
$this->runtime_js("network.setForceConnectionMode('unknown');");
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion scripts/langindex.json
Original file line number Diff line number Diff line change
Expand Up @@ -2537,6 +2537,7 @@
"core.settings.loggedin": "message",
"core.settings.loggedoff": "message",
"core.settings.logintosync": "local_moodlemobileapp",
"core.settings.measuredconnection": "local_moodlemobileapp",
"core.settings.navigatorlanguage": "local_moodlemobileapp",
"core.settings.navigatoruseragent": "local_moodlemobileapp",
"core.settings.networkstatus": "local_moodlemobileapp",
Expand All @@ -2560,7 +2561,6 @@
"core.settings.synchronizenowhelp": "local_moodlemobileapp",
"core.settings.syncsettings": "local_moodlemobileapp",
"core.settings.total": "moodle",
"core.settings.wificonnection": "local_moodlemobileapp",
"core.settings.youradev": "local_moodlemobileapp",
"core.share": "moodle",
"core.sharedfiles.chooseaccountstorefile": "local_moodlemobileapp",
Expand Down
11 changes: 1 addition & 10 deletions src/addons/blog/pages/index/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreTime } from '@singletons/time';
import { CorePopovers } from '@services/overlays/popovers';
import { CoreLoadings } from '@services/overlays/loadings';
import { Subscription } from 'rxjs';
import { CoreAlerts } from '@services/overlays/alerts';
import { Translate } from '@singletons';
import { CoreCommentsCommentsComponent } from '@features/comments/components/comments/comments';
Expand Down Expand Up @@ -89,10 +88,9 @@ export default class AddonBlogIndexPage implements OnInit, OnDestroy {
contextInstanceId = 0;
entryUpdateObserver: CoreEventObserver;
syncObserver: CoreEventObserver;
onlineObserver: Subscription;
optionsAvailable = false;
readonly hasOfflineDataToSync = signal(false);
readonly isOnline = signal(false);
readonly isOnline = CoreNetwork.onlineSignal();
siteId: string;
syncIcon = CoreConstants.ICON_SYNC;
readonly syncHidden = computed(() => !this.loaded() || !this.isOnline() || !this.hasOfflineDataToSync());
Expand All @@ -101,7 +99,6 @@ export default class AddonBlogIndexPage implements OnInit, OnDestroy {
this.currentUserId = CoreSites.getCurrentSiteUserId();
this.siteHomeId = CoreSites.getCurrentSiteHomeId();
this.siteId = CoreSites.getCurrentSiteId();
this.isOnline.set(CoreNetwork.isOnline());

this.logView = CoreTime.once(async () => {
await CorePromiseUtils.ignoreErrors(AddonBlog.logView(this.filter));
Expand Down Expand Up @@ -137,11 +134,6 @@ export default class AddonBlogIndexPage implements OnInit, OnDestroy {
await CorePromiseUtils.ignoreErrors(this.refresh(false));
this.loaded.set(true);
});

// Refresh online status when changes.
this.onlineObserver = CoreNetwork.onChange().subscribe(async () => {
this.isOnline.set(CoreNetwork.isOnline());
});
}

/**
Expand Down Expand Up @@ -516,7 +508,6 @@ export default class AddonBlogIndexPage implements OnInit, OnDestroy {
ngOnDestroy(): void {
this.entryUpdateObserver.off();
this.syncObserver.off();
this.onlineObserver.unsubscribe();
}

}
2 changes: 1 addition & 1 deletion src/addons/mod/page/tests/behat/basic_usage.feature
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Feature: Test basic usage of page activity in app
| name | activity | activityname | course |
| \mod_page\event\course_module_viewed | page | Test page title | Course 1 |

Scenario: Prefecth page
Scenario: Prefetch page
Given I entered the course "Course 1" as "student1" in the app
When I press "Course downloads" in the app
And I press "Download" within "Test page title" "ion-item" in the app
Expand Down
2 changes: 1 addition & 1 deletion src/core/classes/sites/authenticated-site.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1592,7 +1592,7 @@ export class CoreAuthenticatedSite extends CoreUnauthenticatedSite {
let expirationDelay = CoreAuthenticatedSite.UPDATE_FREQUENCIES[updateFrequency] ||
CoreAuthenticatedSite.UPDATE_FREQUENCIES[CoreCacheUpdateFrequency.USUALLY];

if (CoreNetwork.isNetworkAccessLimited()) {
if (CoreNetwork.connectionIsMeasured()) {
// Not WiFi, increase the expiration delay a 50% to decrease the data usage in this case.
expirationDelay *= 1.5;
}
Expand Down
3 changes: 2 additions & 1 deletion src/core/directives/external-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,8 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges, O
clickableEl.addEventListener(eventName, () => {
// User played media or opened a downloadable link.
// Download the file if in wifi and it hasn't been downloaded already (for big files).
if (state !== DownloadStatus.DOWNLOADED && state !== DownloadStatus.DOWNLOADING && CoreNetwork.isWifi()) {
if (state !== DownloadStatus.DOWNLOADED && state !== DownloadStatus.DOWNLOADING &&
CoreNetwork.connectionIsNotMeasured()) {
// We aren't using the result, so it doesn't matter which of the 2 functions we call.
CoreFilepool.getUrlByUrl(site.getId(), url, this.component, this.componentId, 0, false);
}
Expand Down
13 changes: 7 additions & 6 deletions src/core/features/comments/pages/viewer/viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { Component, OnDestroy, OnInit, ViewChild, AfterViewInit, inject } from '@angular/core';
import { Component, OnDestroy, OnInit, ViewChild, AfterViewInit, effect, inject } from '@angular/core';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { ActivatedRoute } from '@angular/router';
import { CoreSites } from '@services/sites';
Expand Down Expand Up @@ -49,6 +49,7 @@ import { CoreDom } from '@singletons/dom';
import { CoreSharedModule } from '@/core/shared.module';
import { ADDON_MOD_ASSIGN_COMMENTS_COMPONENT_NAME } from '@addons/mod/assign/submission/comments/constants';
import { CoreCourses } from '@features/courses/services/courses';
import { CoreKeyboard } from '@singletons/keyboard';

/**
* Page that displays comments.
Expand Down Expand Up @@ -93,7 +94,6 @@ export default class CoreCommentsViewerPage implements OnInit, OnDestroy, AfterV
protected addDeleteCommentsAvailable = false;
protected syncObserver?: CoreEventObserver;
protected onlineObserver: Subscription;
protected keyboardObserver: CoreEventObserver;
protected viewDestroyed = false;
protected scrollBottom = true;
protected scrollElement?: HTMLElement;
Expand Down Expand Up @@ -128,9 +128,11 @@ export default class CoreCommentsViewerPage implements OnInit, OnDestroy, AfterV
});
});

this.keyboardObserver = CoreEvents.on(CoreEvents.KEYBOARD_CHANGE, (keyboardHeight: number) => {
// Force when opening.
this.scrollToBottom(keyboardHeight > 0);
effect(() => {
const shown = CoreKeyboard.getKeyboardShownSignal();

/// Force when opening.
this.scrollToBottom(shown());
});
}

Expand Down Expand Up @@ -700,7 +702,6 @@ export default class CoreCommentsViewerPage implements OnInit, OnDestroy, AfterV
this.syncObserver?.off();
this.onlineObserver.unsubscribe();
this.viewDestroyed = true;
this.keyboardObserver.off();
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
@if (module.visible === 0 || module.uservisible === false) {
<ion-icon name="fas-lock" [attr.aria-label]="'core.restricted' | translate" />
}
@if (prefetchStatusIcon$ | async; as prefetchStatusIcon) {
<ion-icon [name]="prefetchStatusIcon" color="success"
[attr.aria-label]="((prefetchStatusText$ | async) || '') | translate" />
@if (prefetchStatusIcon()) {
<ion-icon [name]="prefetchStatusIcon()" color="success"
[attr.aria-label]="(prefetchStatusText() || '') | translate" />
}
</p>

Expand Down
19 changes: 9 additions & 10 deletions src/core/features/course/components/module/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { Component, Input, Output, EventEmitter, OnInit, OnDestroy, HostBinding } from '@angular/core';
import { Component, Input, Output, EventEmitter, OnInit, OnDestroy, HostBinding, signal } from '@angular/core';

import { CoreSites } from '@services/sites';
import {
Expand All @@ -29,7 +29,6 @@ import {
} from '@features/course/services/module-prefetch-delegate';
import { CoreConstants, DownloadStatus } from '@/core/constants';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { BehaviorSubject } from 'rxjs';
import { toBoolean } from '@/core/transforms/boolean';
import { CoreRemindersDateComponent } from '../../../reminders/components/date/date';
import { CoreCourseModuleCompletionComponent } from '../module-completion/module-completion';
Expand Down Expand Up @@ -74,9 +73,9 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy {
modNameTranslated = '';
hasCompletion = false; // Whether activity has completion to be shown.
showManualCompletion = false; // Whether to show manual completion when completion conditions are disabled.
prefetchStatusIcon$ = new BehaviorSubject<string>(''); // Module prefetch status icon.
prefetchStatusText$ = new BehaviorSubject<string>(''); // Module prefetch status text.
moduleHasView = true;
readonly prefetchStatusIcon = signal<string>(''); // Module prefetch status icon.
readonly prefetchStatusText = signal<string>(''); // Module prefetch status text.

protected prefetchHandler?: CoreCourseModulePrefetchHandler;

Expand Down Expand Up @@ -152,16 +151,16 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy {

switch (prefetchStatus) {
case DownloadStatus.OUTDATED:
this.prefetchStatusIcon$.next(CoreConstants.ICON_OUTDATED);
this.prefetchStatusText$.next('core.outdated');
this.prefetchStatusIcon.set(CoreConstants.ICON_OUTDATED);
this.prefetchStatusText.set('core.outdated');
break;
case DownloadStatus.DOWNLOADED:
this.prefetchStatusIcon$.next(CoreConstants.ICON_DOWNLOADED);
this.prefetchStatusText$.next('core.downloaded');
this.prefetchStatusIcon.set(CoreConstants.ICON_DOWNLOADED);
this.prefetchStatusText.set('core.downloaded');
break;
default:
this.prefetchStatusIcon$.next('');
this.prefetchStatusText$.next('');
this.prefetchStatusIcon.set('');
this.prefetchStatusText.set('');
break;
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/features/course/services/course-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,7 @@ export class CoreCourseHelperProvider {
}

// Start the download if in wifi, but return the URL right away so the file is opened.
if (CoreNetwork.isWifi()) {
if (CoreNetwork.connectionIsNotMeasured()) {
this.downloadModule(module, courseId, component, componentId, files, siteId);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
Output,
EventEmitter,
inject,
effect,
} from '@angular/core';
import { IonContent } from '@ionic/angular';
import { CoreSharedModule } from '@/core/shared.module';
Expand All @@ -50,6 +51,7 @@ import { CoreLoadingComponent } from '@components/loading/loading';
import { CoreToasts } from '@services/overlays/toasts';
import { CorePromiseUtils } from '@singletons/promise-utils';
import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
import { CoreKeyboard } from '@singletons/keyboard';

/**
* Component that displays a rich text editor.
Expand Down Expand Up @@ -85,7 +87,6 @@ export class CoreEditorRichTextEditorComponent implements AfterViewInit, OnDestr

@ViewChild(CoreDynamicComponent) dynamicComponent!: CoreDynamicComponent<CoreEditorBaseComponent>;

protected keyboardObserver?: CoreEventObserver;
protected resizeListener?: CoreEventObserver;
protected editorComponentClass?: Type<CoreEditorBaseComponent>;
protected editorComponentData: Record<string, unknown> = {};
Expand All @@ -107,6 +108,15 @@ export class CoreEditorRichTextEditorComponent implements AfterViewInit, OnDestr
constructor() {
// Generate a "unique" ID based on timestamp.
this.pageInstance = `app_${Date.now()}`;

effect(() => {
// Signal will be triggered when the keyboard is shown or hidden.
CoreKeyboard.getKeyboardShownSignal();

// Opening or closing the keyboard also calls the resize function, but sometimes the resize is called too soon.
// Check the height again, now the window height should have been updated.
this.maximizeEditorSize();
});
}

/**
Expand Down Expand Up @@ -188,20 +198,13 @@ export class CoreEditorRichTextEditorComponent implements AfterViewInit, OnDestr
this.controlSubscription = this.control?.valueChanges.subscribe((newValue) => {
this.onControlValueChange(newValue);
});

// Opening or closing the keyboard also calls the resize function, but sometimes the resize is called too soon.
// Check the height again, now the window height should have been updated.
this.keyboardObserver = CoreEvents.on(CoreEvents.KEYBOARD_CHANGE, () => {
this.maximizeEditorSize();
});
}

/**
* @inheritdoc
*/
ngOnDestroy(): void {
this.resizeListener?.off();
this.keyboardObserver?.off();
this.controlSubscription?.unsubscribe();
this.resetObserver?.off();
this.labelObserver?.disconnect();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export class CoreFileUploaderHelperProvider {

if (size < 0) {
return CoreAlerts.confirm(Translate.instant('core.fileuploader.confirmuploadunknownsize'));
} else if (size >= wifiThreshold || (CoreNetwork.isNetworkAccessLimited() && size >= limitedThreshold)) {
} else if (size >= wifiThreshold || (CoreNetwork.connectionIsMeasured() && size >= limitedThreshold)) {
const readableSize = CoreText.bytesToSize(size, 2);

return CoreAlerts.confirm(Translate.instant('core.fileuploader.confirmuploadfile', { size: readableSize }));
Expand Down
33 changes: 18 additions & 15 deletions src/core/features/mainmenu/pages/menu/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Component, OnInit, OnDestroy, ViewChild, effect } from '@angular/core';
import { IonTabs } from '@ionic/angular';
import { BackButtonEvent } from '@ionic/core';
import { Subscription } from 'rxjs';
Expand Down Expand Up @@ -44,6 +44,7 @@ import {
import { CoreSharedModule } from '@/core/shared.module';
import { CoreMainMenuUserButtonComponent } from '../../components/user-menu-button/user-menu-button';
import { BackButtonPriority } from '@/core/constants';
import { CoreKeyboard } from '@singletons/keyboard';

const ANIMATION_DURATION = 500;

Expand Down Expand Up @@ -119,6 +120,22 @@ export default class CoreMainMenuPage implements OnInit, OnDestroy {
this.isMainScreen = !this.mainTabs?.outlet.canGoBack();
this.updateVisibility();
});

if (CorePlatform.isIOS()) {
effect(() => {
const shown = CoreKeyboard.getKeyboardShownSignal();
// In iOS, the resize event is triggered before the keyboard is opened/closed and not triggered again once done.
// Init handlers again once keyboard is closed since the resize event doesn't have the updated height.
if (!shown) {
this.updateHandlers();

// If the device is slow it can take a bit more to update the window height. Retry in a few ms.
setTimeout(() => {
this.updateHandlers();
}, 250);
}
});
}
}

/**
Expand Down Expand Up @@ -150,20 +167,6 @@ export default class CoreMainMenuPage implements OnInit, OnDestroy {
});
document.addEventListener('ionBackButton', this.backButtonFunction);

if (CorePlatform.isIOS()) {
// In iOS, the resize event is triggered before the keyboard is opened/closed and not triggered again once done.
// Init handlers again once keyboard is closed since the resize event doesn't have the updated height.
this.keyboardObserver = CoreEvents.on(CoreEvents.KEYBOARD_CHANGE, (kbHeight: number) => {
if (kbHeight === 0) {
this.updateHandlers();

// If the device is slow it can take a bit more to update the window height. Retry in a few ms.
setTimeout(() => {
this.updateHandlers();
}, 250);
}
});
}
CoreEvents.trigger(CoreEvents.MAIN_HOME_LOADED);
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/features/settings/lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,6 @@
"synchronizenowhelp": "Synchronising a site will send pending changes and all offline activity stored in the device and will synchronise some data like messages and notifications.",
"syncsettings": "Synchronisation settings",
"total": "Total",
"wificonnection": "Wi-Fi connection",
"measuredconnection": "Measured data connection",
"youradev": "You are now a developer"
}
10 changes: 7 additions & 3 deletions src/core/features/settings/pages/deviceinfo/deviceinfo.html
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ <h1>
<ion-item (longPress)="copyItemInfo($event)">
<ion-label class="ion-text-wrap">
<p class="item-heading">{{ 'core.settings.networkstatus' | translate}}</p>
@if (deviceInfo.isOnline) {
@if (deviceInfo.isOnline()) {
<p>{{ 'core.online' | translate }}</p>
} @else {
<p>{{ 'core.offline' | translate }}</p>
Expand All @@ -148,8 +148,12 @@ <h1>
</ion-item>
<ion-item (longPress)="copyItemInfo($event)">
<ion-label class="ion-text-wrap">
<p class="item-heading">{{ 'core.settings.wificonnection' | translate}}</p>
<p>{{ 'core.' + deviceInfo.wifiConnection | translate }}</p>
<p class="item-heading">{{ 'core.settings.measuredconnection' | translate}}</p>
@if (deviceInfo.measuredConnection()) {
<p>{{ 'core.yes' | translate }}</p>
} @else {
<p>{{ 'core.no' | translate }}</p>
}
</ion-label>
</ion-item>
@if (deviceInfo.cordovaVersion) {
Expand Down
Loading
Loading