Skip to content

Commit 7a9eb90

Browse files
committed
MOBILE-4595 a11y: Pinch-to-zoom setting
1 parent f4934c0 commit 7a9eb90

File tree

10 files changed

+109
-2
lines changed

10 files changed

+109
-2
lines changed

config.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@
3030
<preference name="prerendered-icon" value="true" />
3131
<preference name="AppendUserAgent" value="MoodleMobile 5.0.0 (50000)" />
3232
<preference name="BackupWebStorage" value="none" />
33-
<preference name="ScrollEnabled" value="false" />
33+
<preference name="ScrollEnabled" value="true" />
3434
<preference name="KeyboardDisplayRequiresUserAction" value="false" />
3535
<preference name="HideKeyboardFormAccessoryBar" value="false" />
36+
<preference name="KeyboardResizeMode" value="ionic" />
3637
<preference name="AllowInlineMediaPlayback" value="true" />
3738
<preference name="LoadUrlTimeoutValue" value="60000" />
3839
<preference name="load-url-timeout" value="60000" />

cordova-plugin-moodleapp/plugin.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
<param name="android-package" value="com.moodle.moodlemobile.Diagnostic_Location"/>
2626
<param name="onload" value="true" />
2727
</feature>
28+
<feature name="PinchToZoom">
29+
<param name="android-package" value="com.moodle.moodlemobile.PinchToZoom"/>
30+
<param name="onload" value="true" />
31+
</feature>
2832
</config-file>
2933

3034
<source-file src="src/android/Diagnostic.java" target-dir="src/cordova/plugins" />
@@ -37,6 +41,7 @@
3741

3842
<source-file src="src/android/SecureStorage.java" target-dir="src/com/moodle/moodlemobile" />
3943
<source-file src="src/android/InstallReferrer.java" target-dir="src/com/moodle/moodlemobile" />
44+
<source-file src="src/android/PinchToZoom.java" target-dir="src/com/moodle/moodlemobile" />
4045
</platform>
4146

4247
<platform name="ios">
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// (C) Copyright 2025 Moodle Pty Ltd.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.moodle.moodlemobile;
16+
17+
import org.apache.cordova.CordovaInterface;
18+
import org.apache.cordova.CordovaPlugin;
19+
import org.apache.cordova.CordovaWebView;
20+
21+
import android.util.Log;
22+
import android.webkit.WebSettings;
23+
import android.webkit.WebSettings.ZoomDensity;
24+
import android.webkit.WebView;
25+
26+
public class PinchToZoom extends CordovaPlugin {
27+
28+
public static final String TAG = "PinchToZoom";
29+
30+
@Override
31+
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
32+
Log.d(TAG, "Initializing pinch-to-zoom");
33+
34+
super.initialize(cordova, webView);
35+
36+
WebSettings settings = ((WebView) webView.getView()).getSettings();
37+
settings.setBuiltInZoomControls(true);
38+
settings.setDefaultZoom(WebSettings.ZoomDensity.MEDIUM);
39+
settings.setDisplayZoomControls(false);
40+
settings.setSupportZoom(true);
41+
}
42+
}

scripts/langindex.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2490,6 +2490,7 @@
24902490
"core.settings.enableanalytics": "local_moodlemobileapp",
24912491
"core.settings.enableanalyticsdescription": "local_moodlemobileapp",
24922492
"core.settings.enabledownloadsection": "local_moodlemobileapp",
2493+
"core.settings.enablepinchtozoom": "local_moodlemobileapp",
24932494
"core.settings.enablerichtexteditor": "local_moodlemobileapp",
24942495
"core.settings.enablerichtexteditordescription": "local_moodlemobileapp",
24952496
"core.settings.encryptedpushsupported": "local_moodlemobileapp",

src/core/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ export class CoreConstants {
142142
static readonly SETTINGS_COLOR_SCHEME = 'CoreSettingsColorScheme';
143143
static readonly SETTINGS_ANALYTICS_ENABLED = 'CoreSettingsAnalyticsEnabled';
144144
static readonly SETTINGS_DONT_SHOW_EXTERNAL_LINK_WARN = 'CoreSettingsDontShowExtLinkWarn';
145+
static readonly SETTINGS_PINCH_TO_ZOOM = 'CoreSettingsPinchToZoom';
145146

146147
// WS constants.
147148
static readonly WS_TIMEOUT = 30000; // Timeout when not in WiFi.

src/core/features/settings/lang.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"enableanalytics": "Enable analytics",
3636
"enableanalyticsdescription": "If enabled, the app will collect anonymous data usage.",
3737
"enabledownloadsection": "Enable download sections",
38+
"enablepinchtozoom": "Enable pinch-to-zoom",
3839
"enablerichtexteditor": "Enable text editor",
3940
"enablerichtexteditordescription": "If enabled, a text editor will be available when entering content.",
4041
"encryptedpushsupported": "Encrypted push notifications supported",

src/core/features/settings/pages/general/general.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ <h1>{{ 'core.settings.general' | translate }}</h1>
3333
</ion-segment-button>
3434
</ion-segment>
3535
</ion-item>
36+
<ion-item>
37+
<ion-toggle [(ngModel)]="pinchToZoom" (ionChange)="pinchToZoomChanged($event)">
38+
<p class="item-heading ion-text-wrap">{{ 'core.settings.enablepinchtozoom' | translate }}</p>
39+
</ion-toggle>
40+
</ion-item>
3641
<ion-item class="ion-text-wrap core-settings-general-color-scheme" *ngIf="colorSchemes.length > 0">
3742
<ion-select [(ngModel)]="selectedScheme" (ionChange)="colorSchemeChanged($event)" interface="action-sheet"
3843
[cancelText]="'core.cancel' | translate" [disabled]="colorSchemeDisabled"

src/core/features/settings/pages/general/general.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export class CoreSettingsGeneralPage {
4343
selectedLanguage = '';
4444
zoomLevels: { value: CoreZoomLevel; style: number; selected: boolean }[] = [];
4545
selectedZoomLevel = CoreZoomLevel.NONE;
46+
pinchToZoom = false;
4647
richTextEditor = true;
4748
debugDisplay = false;
4849
analyticsAvailable = false;
@@ -98,6 +99,8 @@ export class CoreSettingsGeneralPage {
9899
selected: value === this.selectedZoomLevel,
99100
}));
100101

102+
this.pinchToZoom = await CoreSettingsHelper.getPinchToZoom();
103+
101104
this.richTextEditor = await CoreConfig.get(CoreConstants.SETTINGS_RICH_TEXT_EDITOR, true);
102105

103106
this.debugDisplay = await CoreConfig.get(CoreConstants.SETTINGS_DEBUG_DISPLAY, false);
@@ -206,6 +209,19 @@ export class CoreSettingsGeneralPage {
206209
CoreConfig.set(CoreConstants.SETTINGS_ZOOM_LEVEL, this.selectedZoomLevel);
207210
}
208211

212+
/**
213+
* Called when pinch-to-zoom is enabled or disabled.
214+
*
215+
* @param ev Event
216+
*/
217+
pinchToZoomChanged(ev: Event): void {
218+
ev.stopPropagation();
219+
ev.preventDefault();
220+
221+
CoreSettingsHelper.applyPinchToZoom(this.pinchToZoom);
222+
CoreConfig.set(CoreConstants.SETTINGS_PINCH_TO_ZOOM, this.pinchToZoom ? 1 : 0);
223+
}
224+
209225
/**
210226
* Called when a new color scheme is selected.
211227
*

src/core/features/settings/services/settings-helper.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,14 +318,25 @@ export class CoreSettingsHelperProvider {
318318
return CoreConstants.CONFIG.zoomlevels[zoomLevel];
319319
}
320320

321+
/**
322+
* Get saved pinch-to-zoom setting.
323+
*
324+
* @returns True if pinch-to-zoom is enabled.
325+
*/
326+
async getPinchToZoom(): Promise<boolean> {
327+
return Boolean(await CoreConfig.get(CoreConstants.SETTINGS_PINCH_TO_ZOOM, 0));
328+
}
329+
321330
/**
322331
* Init Settings related to DOM.
323332
*/
324333
async initDomSettings(): Promise<void> {
325334
// Set the font size based on user preference.
326335
const zoomLevel = await this.getZoomLevel();
336+
const pinchToZoom = await this.getPinchToZoom();
327337

328338
this.applyZoomLevel(zoomLevel);
339+
this.applyPinchToZoom(pinchToZoom);
329340

330341
this.initColorScheme();
331342
}
@@ -377,6 +388,30 @@ export class CoreSettingsHelperProvider {
377388
document.documentElement.style.setProperty('--zoom-level', zoom + '%');
378389
}
379390

391+
/**
392+
* Enable or disable pinch-to-zoom.
393+
*
394+
* @param pinchToZoom True if pinch-to-zoom should be enabled.
395+
*/
396+
applyPinchToZoom(pinchToZoom: boolean): void {
397+
const element = document.head.querySelector('meta[name=viewport]');
398+
if (!element) {
399+
return;
400+
}
401+
const content = element.getAttribute('content');
402+
if (!content) {
403+
return;
404+
}
405+
406+
element.setAttribute('content', content.replace(/maximum-scale=\d\.\d/, `maximum-scale=${pinchToZoom ? '4.0' : '1.0'}`));
407+
408+
// Force layout reflow.
409+
document.body.style.width = '99.9999%';
410+
setTimeout(() => {
411+
document.body.style.width = '';
412+
});
413+
}
414+
380415
/**
381416
* Get system allowed color schemes.
382417
*

src/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
<meta name="color-scheme" content="light dark" />
1111
<meta name="viewport"
12-
content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, interactive-widget=resizes-content" />
12+
content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=yes, interactive-widget=resizes-content" />
1313
<meta http-equiv="Content-Security-Policy"
1414
content="default-src * filesystem: cdvfile: file: data: gap: moodleappfs: blob: 'unsafe-inline' 'unsafe-eval' 'self' android-webview-video-poster: about:">
1515
<meta name="format-detection" content="telephone=no" />

0 commit comments

Comments
 (0)