commit
2002ad6b5d
|
@ -1,5 +1,5 @@
|
||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<widget id="com.moodle.moodlemobile" version="3.5.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
<widget id="com.moodle.moodlemobile" version="3.5.2" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
||||||
<name>Moodle</name>
|
<name>Moodle</name>
|
||||||
<description>Moodle official app</description>
|
<description>Moodle official app</description>
|
||||||
<author email="mobile@moodle.com" href="http://moodle.com">Moodle Mobile team</author>
|
<author email="mobile@moodle.com" href="http://moodle.com">Moodle Mobile team</author>
|
||||||
|
@ -122,7 +122,7 @@
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin name="ionic-plugin-keyboard" spec="^2.2.1" />
|
<plugin name="ionic-plugin-keyboard" spec="^2.2.1" />
|
||||||
<plugin name="cordova-plugin-zip" spec="^3.1.0" />
|
<plugin name="cordova-plugin-zip" spec="^3.1.0" />
|
||||||
<plugin name="cordova-plugin-local-notifications-mm" spec="^1.0.11" />
|
<plugin name="cordova-plugin-local-notifications-mm" spec="^1.0.13" />
|
||||||
<plugin name="cordova-plugin-file-opener2" spec="^2.0.19" />
|
<plugin name="cordova-plugin-file-opener2" spec="^2.0.19" />
|
||||||
<plugin name="com-darryncampbell-cordova-plugin-intent" spec="^1.1.0" />
|
<plugin name="com-darryncampbell-cordova-plugin-intent" spec="^1.1.0" />
|
||||||
<plugin name="cordova-sqlite-evcore-extbuild-free" spec="^0.9.7" />
|
<plugin name="cordova-sqlite-evcore-extbuild-free" spec="^0.9.7" />
|
||||||
|
|
|
@ -7,4 +7,8 @@ ion-app.app-root page-addon-mod-quiz-player {
|
||||||
.core-has-fixed-timer form {
|
.core-has-fixed-timer form {
|
||||||
padding-top: 56px;
|
padding-top: 56px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toolbar-ios .bar-buttons-ios .bar-button {
|
||||||
|
@include padding-horizontal($content-padding);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -285,7 +285,8 @@ export class AddonModQuizSyncProvider extends CoreSyncBaseProvider {
|
||||||
// Attempt not found or it's finished in online. Discard it.
|
// Attempt not found or it's finished in online. Discard it.
|
||||||
warnings.push(this.translate.instant('addon.mod_quiz.warningattemptfinished'));
|
warnings.push(this.translate.instant('addon.mod_quiz.warningattemptfinished'));
|
||||||
|
|
||||||
return this.finishSync(siteId, quiz, courseId, warnings, lastAttemptId, offlineAttempt, onlineAttempt, true);
|
return this.finishSync(siteId, quiz, courseId, warnings, offlineAttempt.id, offlineAttempt, onlineAttempt,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the data stored in offline.
|
// Get the data stored in offline.
|
||||||
|
|
|
@ -151,4 +151,22 @@ export class AddonQtypeMultichoiceHandler implements CoreQuestionHandler {
|
||||||
isSameResponseSingle(prevAnswers: any, newAnswers: any): boolean {
|
isSameResponseSingle(prevAnswers: any, newAnswers: any): boolean {
|
||||||
return this.utils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
|
return this.utils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare and add to answers the data to send to server based in the input. Return promise if async.
|
||||||
|
*
|
||||||
|
* @param {any} question Question.
|
||||||
|
* @param {any} answers The answers retrieved from the form. Prepared answers must be stored in this object.
|
||||||
|
* @param {boolean} [offline] Whether the data should be saved in offline.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {void|Promise<any>} Return a promise resolved when done if async, void if sync.
|
||||||
|
*/
|
||||||
|
prepareAnswers(question: any, answers: any, offline: boolean, siteId?: string): void | Promise<any> {
|
||||||
|
if (question && !question.multi && typeof answers[question.optionsName] != 'undefined' && !answers[question.optionsName]) {
|
||||||
|
/* It's a single choice and the user hasn't answered. Delete the answer and its sequencecheck because
|
||||||
|
sending an empty string (default value) will mark the first option as selected. */
|
||||||
|
delete answers[question.optionsName];
|
||||||
|
delete answers[question.optionsName.replace('answer', ':sequencecheck')];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -930,7 +930,7 @@ ion-app.app-root {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix modals displayed over action sheet.
|
// Fix modals displayed over action sheet.
|
||||||
.disable-scroll ion-modal .ion-page {
|
&.disable-scroll ion-modal .ion-page {
|
||||||
pointer-events: initial;
|
pointer-events: initial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button *ngIf="editMode" ion-button icon-only clear [attr.aria-label]="'core.save' | translate" color="success" type="submit">
|
<button *ngIf="editMode" ion-button icon-only clear [attr.aria-label]="'core.save' | translate" color="success" type="submit">
|
||||||
<ion-icon name="checkmark"></ion-icon>
|
<ion-icon name="checkmark" ios="md-checkmark"></ion-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button ion-button clear icon-only (click)="deleteFile($event)" [attr.aria-label]="'core.delete' | translate" color="danger">
|
<button ion-button clear icon-only (click)="deleteFile($event)" [attr.aria-label]="'core.delete' | translate" color="danger">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<ion-split-pane (ionChange)="onSplitPaneChanged($event._visible);" [when]="when">
|
<ion-split-pane (ionChange)="onSplitPaneChanged($event._visible);" [when]="when">
|
||||||
<ion-menu [content]="detailNav" type="push" class="core-avoid-header">
|
<ion-menu [content]="detailNav" type="push" class="core-avoid-header" [side]="side" #menu>
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
</ion-menu>
|
</ion-menu>
|
||||||
<ion-nav [root]="detailPage" #detailNav main class="core-avoid-header"></ion-nav>
|
<ion-nav [root]="detailPage" #detailNav main class="core-avoid-header"></ion-nav>
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
// Code based on https://github.com/martinpritchardelevate/ionic-split-pane-demo
|
// Code based on https://github.com/martinpritchardelevate/ionic-split-pane-demo
|
||||||
|
|
||||||
import { Component, ViewChild, Input, ElementRef, OnInit, Optional, OnDestroy } from '@angular/core';
|
import { Component, ViewChild, Input, ElementRef, OnInit, Optional, OnDestroy } from '@angular/core';
|
||||||
import { NavController, Nav, ViewController } from 'ionic-angular';
|
import { NavController, Nav, ViewController, Platform, Menu } from 'ionic-angular';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
|
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
|
@ -45,7 +46,9 @@ import { Subscription } from 'rxjs';
|
||||||
export class CoreSplitViewComponent implements OnInit, OnDestroy {
|
export class CoreSplitViewComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
@ViewChild('detailNav') detailNav: Nav;
|
@ViewChild('detailNav') detailNav: Nav;
|
||||||
|
@ViewChild('menu') menu: Menu;
|
||||||
@Input() when?: string | boolean = 'md';
|
@Input() when?: string | boolean = 'md';
|
||||||
|
|
||||||
protected isEnabled = false;
|
protected isEnabled = false;
|
||||||
protected masterPageName = '';
|
protected masterPageName = '';
|
||||||
protected masterPageIndex = 0;
|
protected masterPageIndex = 0;
|
||||||
|
@ -56,16 +59,27 @@ export class CoreSplitViewComponent implements OnInit, OnDestroy {
|
||||||
protected originalMasterCanLeave: Function;
|
protected originalMasterCanLeave: Function;
|
||||||
protected ignoreSplitChanged = false;
|
protected ignoreSplitChanged = false;
|
||||||
protected audioCaptureSubscription: Subscription;
|
protected audioCaptureSubscription: Subscription;
|
||||||
|
protected languageChangedSubscription: Subscription;
|
||||||
|
|
||||||
// Empty placeholder for the 'detail' page.
|
// Empty placeholder for the 'detail' page.
|
||||||
detailPage: any = null;
|
detailPage: any = null;
|
||||||
|
side: string;
|
||||||
|
|
||||||
constructor(@Optional() private masterNav: NavController, element: ElementRef, fileUploaderProvider: CoreFileUploaderProvider) {
|
constructor(@Optional() private masterNav: NavController, element: ElementRef, fileUploaderProvider: CoreFileUploaderProvider,
|
||||||
|
platform: Platform, translate: TranslateService) {
|
||||||
this.element = element.nativeElement;
|
this.element = element.nativeElement;
|
||||||
|
|
||||||
this.audioCaptureSubscription = fileUploaderProvider.onAudioCapture.subscribe((starting) => {
|
this.audioCaptureSubscription = fileUploaderProvider.onAudioCapture.subscribe((starting) => {
|
||||||
this.ignoreSplitChanged = starting;
|
this.ignoreSplitChanged = starting;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Change the side when the language changes.
|
||||||
|
this.languageChangedSubscription = translate.onLangChange.subscribe((event: any) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.side = platform.isRTL ? 'right' : 'left';
|
||||||
|
this.menu.setElementAttribute('side', this.side);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -244,5 +258,6 @@ export class CoreSplitViewComponent implements OnInit, OnDestroy {
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.detailsDidEnterSubscription && this.detailsDidEnterSubscription.unsubscribe();
|
this.detailsDidEnterSubscription && this.detailsDidEnterSubscription.unsubscribe();
|
||||||
this.audioCaptureSubscription.unsubscribe();
|
this.audioCaptureSubscription.unsubscribe();
|
||||||
|
this.languageChangedSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
"app_id" : "com.moodle.moodlemobile",
|
"app_id" : "com.moodle.moodlemobile",
|
||||||
"appname": "Moodle Mobile",
|
"appname": "Moodle Mobile",
|
||||||
"desktopappname": "Moodle Desktop",
|
"desktopappname": "Moodle Desktop",
|
||||||
"versioncode" : 3510,
|
"versioncode" : 3520,
|
||||||
"versionname" : "3.5.1",
|
"versionname" : "3.5.2",
|
||||||
"cache_expiration_time" : 300000,
|
"cache_expiration_time" : 300000,
|
||||||
"default_lang" : "en",
|
"default_lang" : "en",
|
||||||
"languages": {"ar": "عربي", "bg": "Български", "ca": "Català", "cs": "Čeština", "da": "Dansk", "de": "Deutsch", "de-du": "Deutsch - Du", "el": "Ελληνικά", "en": "English", "es": "Español", "es-mx": "Español - México", "eu": "Euskara", "fa": "فارسی", "fi": "Suomi", "fr" : "Français", "he" : "עברית", "hu": "magyar", "it": "Italiano", "ja": "日本語", "ko" : "한국어", "lt" : "Lietuvių", "mr": "मराठी", "nl": "Nederlands", "pl": "Polski", "pt-br": "Português - Brasil", "pt": "Português - Portugal", "ro": "Română", "ru": "Русский", "sr-cr": "Српски", "sr-lt": "Srpski", "sv": "Svenska", "tr" : "Türkçe", "uk" : "Українська", "zh-cn" : "简体中文", "zh-tw" : "正體中文"},
|
"languages": {"ar": "عربي", "bg": "Български", "ca": "Català", "cs": "Čeština", "da": "Dansk", "de": "Deutsch", "de-du": "Deutsch - Du", "el": "Ελληνικά", "en": "English", "es": "Español", "es-mx": "Español - México", "eu": "Euskara", "fa": "فارسی", "fi": "Suomi", "fr" : "Français", "he" : "עברית", "hu": "magyar", "it": "Italiano", "ja": "日本語", "ko" : "한국어", "lt" : "Lietuvių", "mr": "मराठी", "nl": "Nederlands", "pl": "Polski", "pt-br": "Português - Brasil", "pt": "Português - Portugal", "ro": "Română", "ru": "Русский", "sr-cr": "Српски", "sr-lt": "Srpski", "sv": "Svenska", "tr" : "Türkçe", "uk" : "Українська", "zh-cn" : "简体中文", "zh-tw" : "正體中文"},
|
||||||
|
|
|
@ -465,10 +465,19 @@ export class CoreQuestionHelperProvider {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
selected.setAttribute('selected', 'selected');
|
selected.setAttribute('selected', 'selected');
|
||||||
}
|
}
|
||||||
} else if (element.type == 'radio' || element.type == 'checkbox') {
|
} else if (element.type == 'radio') {
|
||||||
// Check if this radio or checkbox is selected.
|
// Check if this radio is selected.
|
||||||
if (element.value == question.localAnswers[name]) {
|
if (element.value == question.localAnswers[name]) {
|
||||||
element.setAttribute('checked', 'checked');
|
element.setAttribute('checked', 'checked');
|
||||||
|
} else {
|
||||||
|
element.removeAttribute('checked');
|
||||||
|
}
|
||||||
|
} else if (element.type == 'checkbox') {
|
||||||
|
// Check if this checkbox is checked.
|
||||||
|
if (this.utils.isTrueOrOne(question.localAnswers[name])) {
|
||||||
|
element.setAttribute('checked', 'checked');
|
||||||
|
} else {
|
||||||
|
element.removeAttribute('checked');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Put the answer in the value.
|
// Put the answer in the value.
|
||||||
|
|
|
@ -497,6 +497,8 @@ export class CoreLocalNotificationsProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show an in app notification popover.
|
* Show an in app notification popover.
|
||||||
|
* This function was used because local notifications weren't displayed when the app was in foreground in iOS10+,
|
||||||
|
* but the issue was fixed in the plugin and this function is no longer used.
|
||||||
*
|
*
|
||||||
* @param {CoreILocalNotification} notification Notification.
|
* @param {CoreILocalNotification} notification Notification.
|
||||||
*/
|
*/
|
||||||
|
@ -594,11 +596,6 @@ export class CoreLocalNotificationsProvider {
|
||||||
* @return {Promise<any>} Promise resolved when stored, rejected otherwise.
|
* @return {Promise<any>} Promise resolved when stored, rejected otherwise.
|
||||||
*/
|
*/
|
||||||
trigger(notification: CoreILocalNotification): Promise<any> {
|
trigger(notification: CoreILocalNotification): Promise<any> {
|
||||||
if (this.platform.is('ios') && this.platform.version().num >= 10) {
|
|
||||||
// In iOS10 show in app notification.
|
|
||||||
this.showNotificationPopover(notification);
|
|
||||||
}
|
|
||||||
|
|
||||||
const entry = {
|
const entry = {
|
||||||
id: notification.id,
|
id: notification.id,
|
||||||
at: parseInt(notification.at, 10)
|
at: parseInt(notification.at, 10)
|
||||||
|
|
Loading…
Reference in New Issue