Merge pull request #3669 from crazyserver/MOBILE-4270

Mobile 4270
main
Dani Palou 2023-05-11 15:19:56 +02:00 committed by GitHub
commit 709070382e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 282 additions and 255 deletions

View File

@ -18,6 +18,7 @@ cache:
- $HOME/.gradle/caches/ - $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/ - $HOME/.gradle/wrapper/
- $HOME/.android/build-cache - $HOME/.android/build-cache
- $HOME/Library/Caches/Homebrew
before_install: before_install:
- nvm install - nvm install
@ -34,8 +35,7 @@ script:
jobs: jobs:
include: include:
- stage: build - name: "Build Android"
name: "Build Android"
if: env(DEPLOY) = 1 OR (env(DEPLOY) = 2 AND tag IS NOT blank) if: env(DEPLOY) = 1 OR (env(DEPLOY) = 2 AND tag IS NOT blank)
language: android language: android
android: android:
@ -63,13 +63,14 @@ jobs:
- libsecret-1-dev - libsecret-1-dev
- php5-cli - php5-cli
- php5-common - php5-common
- stage: build - name: "Build iOS"
name: "Build iOS"
language: node_js language: node_js
if: env(BUILD_IOS) = 1 AND (env(DEPLOY) = 1 OR (env(DEPLOY) = 2 AND tag IS NOT blank)) if: env(BUILD_IOS) = 1 AND (env(DEPLOY) = 1 OR (env(DEPLOY) = 2 AND tag IS NOT blank))
os: osx os: osx
osx_image: xcode13.1 osx_image: xcode14.2
addons: addons:
homebrew: homebrew:
packages: packages:
- jq - jq
before_cache:
- brew cleanup

View File

@ -764,7 +764,7 @@ class behat_app extends behat_app_helper {
$result = $this->runtime_js("setField('$field', '$value')"); $result = $this->runtime_js("setField('$field', '$value')");
if ($result !== 'OK') { if ($result !== 'OK') {
throw new DriverException('Error setting field - ' . $result); throw new DriverException('Error setting field "' . $field . '" - ' . $result);
} }
return true; return true;

View File

@ -57,6 +57,7 @@
"sr-cr": "Српски", "sr-cr": "Српски",
"sr-lt": "Srpski", "sr-lt": "Srpski",
"sv": "Svenska", "sv": "Svenska",
"szl": "Ślōnski",
"tg": "Тоҷикӣ", "tg": "Тоҷикӣ",
"tr": "Türkçe", "tr": "Türkçe",
"uk": "Українська", "uk": "Українська",

View File

@ -1692,20 +1692,20 @@
"core.downloading": "local_moodlemobileapp", "core.downloading": "local_moodlemobileapp",
"core.edit": "moodle", "core.edit": "moodle",
"core.editor.autosavesucceeded": "editor_atto", "core.editor.autosavesucceeded": "editor_atto",
"core.editor.bold": "atto_bold/pluginname", "core.editor.bold": "editor",
"core.editor.clear": "atto_clear/pluginname", "core.editor.clear": "atto_clear/pluginname",
"core.editor.h3": "atto_title", "core.editor.h3": "atto_title",
"core.editor.h4": "atto_title", "core.editor.h4": "atto_title",
"core.editor.h5": "atto_title", "core.editor.h5": "atto_title",
"core.editor.hidetoolbar": "local_moodlemobileapp", "core.editor.hidetoolbar": "local_moodlemobileapp",
"core.editor.italic": "atto_italic/pluginname", "core.editor.italic": "editor",
"core.editor.orderedlist": "atto_orderedlist/pluginname", "core.editor.orderedlist": "editor",
"core.editor.p": "atto_title", "core.editor.p": "editor_tinymce/advanced:paragraph",
"core.editor.strike": "atto_strike/pluginname", "core.editor.strikethrough": "editor",
"core.editor.textrecovered": "editor_atto", "core.editor.textrecovered": "editor_atto",
"core.editor.toggle": "local_moodlemobileapp", "core.editor.toggle": "local_moodlemobileapp",
"core.editor.underline": "atto_underline/pluginname", "core.editor.underline": "editor",
"core.editor.unorderedlist": "atto_unorderedlist/pluginname", "core.editor.unorderedlist": "editor",
"core.emptysplit": "local_moodlemobileapp", "core.emptysplit": "local_moodlemobileapp",
"core.endingtime": "local_moodlemobileapp", "core.endingtime": "local_moodlemobileapp",
"core.endonesteptour": "tool_usertours", "core.endonesteptour": "tool_usertours",
@ -2268,7 +2268,7 @@
"core.reminders.atthetime": "local_moodlemobileapp", "core.reminders.atthetime": "local_moodlemobileapp",
"core.reminders.custom": "local_moodlemobileapp", "core.reminders.custom": "local_moodlemobileapp",
"core.reminders.customreminder": "local_moodlemobileapp", "core.reminders.customreminder": "local_moodlemobileapp",
"core.reminders.delete": "moodle", "core.reminders.delete": "local_moodlemobileapp",
"core.reminders.reminderset": "local_moodlemobileapp", "core.reminders.reminderset": "local_moodlemobileapp",
"core.reminders.reminderunset": "local_moodlemobileapp", "core.reminders.reminderunset": "local_moodlemobileapp",
"core.reminders.setareminder": "local_moodlemobileapp", "core.reminders.setareminder": "local_moodlemobileapp",
@ -2310,7 +2310,7 @@
"core.selectagroup": "moodle", "core.selectagroup": "moodle",
"core.send": "message", "core.send": "message",
"core.sending": "chat", "core.sending": "chat",
"core.serverconnection": "error", "core.serverconnection": "local_moodlemobileapp",
"core.settings.about": "local_moodlemobileapp", "core.settings.about": "local_moodlemobileapp",
"core.settings.accessstatement": "access", "core.settings.accessstatement": "access",
"core.settings.appsettings": "local_moodlemobileapp", "core.settings.appsettings": "local_moodlemobileapp",

View File

@ -31,14 +31,6 @@
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher> </ion-refresher>
<core-loading [hideUntil]="eventLoaded"> <core-loading [hideUntil]="eventLoaded">
<!-- There is data to be synchronized -->
<ion-card class="core-warning-card" *ngIf="hasOffline || (event && event.deleted)">
<ion-item>
<ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendarevent' | translate} }}</ion-label>
</ion-item>
</ion-card>
<ion-list *ngIf="event"> <ion-list *ngIf="event">
<ion-item class="ion-text-wrap addon-calendar-event" collapsible [ngClass]="['addon-calendar-eventtype-'+event.eventtype]"> <ion-item class="ion-text-wrap addon-calendar-event" collapsible [ngClass]="['addon-calendar-eventtype-'+event.eventtype]">
<core-mod-icon *ngIf="event.moduleIcon" [modicon]="event.moduleIcon" [showAlt]="false" [modname]="event.modulename" <core-mod-icon *ngIf="event.moduleIcon" [modicon]="event.moduleIcon" [showAlt]="false" [modname]="event.modulename"
@ -58,6 +50,13 @@
</h1> </h1>
</ion-label> </ion-label>
</ion-item> </ion-item>
<!-- There is data to be synchronized -->
<ion-card class="core-warning-card" *ngIf="hasOffline || event.deleted">
<ion-item>
<ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendarevent' | translate} }}</ion-label>
</ion-item>
</ion-card>
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label> <ion-label>
<p class="item-heading">{{ 'addon.calendar.when' | translate }}</p> <p class="item-heading">{{ 'addon.calendar.when' | translate }}</p>

View File

@ -103,7 +103,7 @@
</ion-fab> </ion-fab>
</ion-content> </ion-content>
<ion-footer class="footer-adjustable" *ngIf="loaded && (!conversationId || conversation)"> <ion-footer class="footer-adjustable" *ngIf="loaded && (!conversationId || conversation)">
<ion-toolbar [color]="footerType == 'message' ? 'contrast' : 'light'"> <ion-toolbar [color]="footerType == 'message' ? null : 'light'">
<p *ngIf="footerType == 'unable'" class="ion-text-center ion-margin-horizontal"> <p *ngIf="footerType == 'unable'" class="ion-text-center ion-margin-horizontal">
{{ 'addon.messages.unabletomessage' | translate }} {{ 'addon.messages.unabletomessage' | translate }}
</p> </p>

View File

@ -44,6 +44,7 @@
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
flex-shrink: 1; flex-shrink: 1;
display: block;
} }
ion-icon { ion-icon {

View File

@ -10,12 +10,12 @@
"view_groups_selection_warning": "There is a room for each group and you have access to more than one. Be sure to select the correct one.", "view_groups_selection_warning": "There is a room for each group and you have access to more than one. Be sure to select the correct one.",
"view_message_conference_in_progress": "The session is in progress.", "view_message_conference_in_progress": "The session is in progress.",
"view_message_conference_room_ready": "This room is ready. You can join the session now.", "view_message_conference_room_ready": "This room is ready. You can join the session now.",
"view_message_moderator": "moderator", "view_message_moderator": "Moderator",
"view_message_moderators": "moderators", "view_message_moderators": "Moderators",
"view_message_norecordings": "There are no recordings available.", "view_message_norecordings": "There are no recordings available.",
"view_message_session_started_at": "This session started at", "view_message_session_started_at": "Session started at",
"view_message_viewer": "viewer", "view_message_viewer": "Viewer",
"view_message_viewers": "viewers", "view_message_viewers": "Viewers",
"view_nojoin": "You do not have a role that is allowed to join this session.", "view_nojoin": "You do not have a role that is allowed to join this session.",
"view_section_title_recordings": "Recordings" "view_section_title_recordings": "Recordings"
} }

View File

@ -53,8 +53,8 @@ Feature: Test basic usage of BBB activity in app
Given I wait "10" seconds Given I wait "10" seconds
Then I should find "The session is in progress." in the app Then I should find "The session is in progress." in the app
And I should find "1" near "viewer" in the app And I should find "1" near "Viewer" in the app
And I should find "0" near "moderator" in the app And I should find "0" near "Moderator" in the app
Scenario: Join meeting (moderator) Scenario: Join meeting (moderator)
Given the following "activities" exist: Given the following "activities" exist:
@ -69,8 +69,8 @@ Feature: Test basic usage of BBB activity in app
Given I wait "10" seconds Given I wait "10" seconds
Then I should find "The session is in progress." in the app Then I should find "The session is in progress." in the app
And I should find "1" near "moderator" in the app And I should find "1" near "Moderator" in the app
And I should find "0" near "viewer" in the app And I should find "0" near "Viewer" in the app
Scenario: Wait for moderator Scenario: Wait for moderator
Given the following "activities" exist: Given the following "activities" exist:
@ -91,8 +91,8 @@ Feature: Test basic usage of BBB activity in app
And I press "Close" in the app And I press "Close" in the app
And I pull to refresh in the app And I pull to refresh in the app
Then I should find "The session is in progress." in the app Then I should find "The session is in progress." in the app
And I should find "1" near "moderator" in the app And I should find "1" near "Moderator" in the app
And I should find "0" near "viewer" in the app And I should find "0" near "Viewer" in the app
And I should be able to press "Join session" in the app And I should be able to press "Join session" in the app
When I close all opened windows When I close all opened windows

View File

@ -93,7 +93,7 @@
</core-loading> </core-loading>
</ion-content> </ion-content>
<ion-footer class="footer-adjustable"> <ion-footer class="footer-adjustable">
<ion-toolbar [color]="isOnline && polling && loaded ? 'contrast' : 'light'"> <ion-toolbar [color]="isOnline && polling && loaded ? null : 'light'">
<p class="ion-text-center" *ngIf="!isOnline"> <p class="ion-text-center" *ngIf="!isOnline">
{{ 'addon.mod_chat.mustbeonlinetosendmessages' | translate }} {{ 'addon.mod_chat.mustbeonlinetosendmessages' | translate }}
</p> </p>

View File

@ -1,9 +1,12 @@
<ion-list> <ion-content>
<ion-item button class="ion-text-wrap" (click)="onItemClick(item)" *ngFor="let item of items" detail="false" <ion-list>
[attr.aria-label]="item.text | translate"> <ion-item button class="ion-text-wrap" (click)="onItemClick(item)" *ngFor="let item of items" detail="false"
<ion-label> [attr.aria-label]="item.text | translate">
<p class="item-heading">{{ item.text | translate }}</p> <ion-label>
</ion-label> <p class="item-heading">{{ item.text | translate }}</p>
<ion-icon [name]="item.icon" slot="end" aria-hidden="true"></ion-icon> </ion-label>
</ion-item> <ion-icon [name]="item.icon" slot="end" aria-hidden="true"></ion-icon>
</ion-list> </ion-item>
</ion-list>
</ion-content>

View File

@ -13,14 +13,14 @@
"disapprove": "Undo approval", "disapprove": "Undo approval",
"edittagsnotsupported": "Sorry, editing tags is not supported by the app.", "edittagsnotsupported": "Sorry, editing tags is not supported by the app.",
"emptyaddform": "You did not fill out any fields!", "emptyaddform": "You did not fill out any fields!",
"entrieslefttoadd": "You must add {{$a.entriesleft}} more entry/entries in order to complete this activity", "entrieslefttoadd": "You must add {{$a.entriesleft}} more entry/entries to complete this activity.",
"entrieslefttoaddtoview": "You must add {{$a.entrieslefttoview}} more entry/entries before you can view other participants' entries.", "entrieslefttoaddtoview": "You must add {{$a.entrieslefttoview}} more entry/entries before you can view other participants' entries.",
"errorapproving": "Error approving or unapproving entry.", "errorapproving": "Error approving or unapproving entry.",
"errordeleting": "Error deleting entry.", "errordeleting": "Error deleting entry.",
"errormustsupplyvalue": "You must supply a value here.", "errormustsupplyvalue": "You must supply a value here.",
"expired": "Sorry, this activity closed on {{$a}} and is no longer available", "expired": "Sorry, this activity closed on {{$a}} and is no longer available",
"fields": "Fields", "fields": "Fields",
"foundrecords": "Found records: {{$a.num}}/{{$a.max}} (<a href=\"{{$a.reseturl}}\">Reset filters</a>)", "foundrecords": "Found {{$a.num}} out of {{$a.max}} records. <a href=\"{{$a.reseturl}}\">Clear all</a>",
"gettinglocation": "Getting location", "gettinglocation": "Getting location",
"latlongboth": "Both latitude and longitude are required.", "latlongboth": "Both latitude and longitude are required.",
"locationnotenabled": "Location is not enabled", "locationnotenabled": "Location is not enabled",

View File

@ -334,15 +334,16 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
return label; return label;
}); });
item.chartData = parsedData.map((dataItem) => <number> dataItem.answercount); item.chartData = parsedData.map((dataItem) => Number(dataItem.answercount));
if (item.typ == 'multichoicerated') { if (item.typ === 'multichoicerated') {
item.average = parsedData.reduce((prev, current) => prev + Number(current.avg), 0.0); item.average = parsedData.reduce((prev, current) => prev + Number(current.avg), 0.0);
} }
const subtype = item.presentation.charAt(0); const subtype = item.presentation.charAt(0);
const single = subtype != 'c'; // Display bar chart if there are no answers to avoid division by 0 error.
const single = subtype !== 'c' && item.chartData.some((count) => count > 0);
item.chartType = single ? 'doughnut' : 'bar'; item.chartType = single ? 'doughnut' : 'bar';
item.templateName = 'chart'; item.templateName = 'chart';
break; break;

View File

@ -1,38 +1,42 @@
<ion-item button class="ion-text-wrap" (click)="setLockState(true)" *ngIf="discussion.canlock && !discussion.locked" detail="false"> <ion-content>
<ion-icon name="fas-lock" slot="start" aria-hidden="true"></ion-icon> <ion-list>
<ion-label> <ion-item button class="ion-text-wrap" (click)="setLockState(true)" *ngIf="discussion.canlock && !discussion.locked" detail="false">
<p class="item-heading">{{ 'addon.mod_forum.lockdiscussion' | translate }}</p> <ion-icon name="fas-lock" slot="start" aria-hidden="true"></ion-icon>
</ion-label> <ion-label>
</ion-item> <p class="item-heading">{{ 'addon.mod_forum.lockdiscussion' | translate }}</p>
<ion-item button class="ion-text-wrap" (click)="setLockState(false)" *ngIf="discussion.canlock && discussion.locked" detail="false"> </ion-label>
<ion-icon name="fas-unlock" slot="start" aria-hidden="true"></ion-icon> </ion-item>
<ion-label> <ion-item button class="ion-text-wrap" (click)="setLockState(false)" *ngIf="discussion.canlock && discussion.locked" detail="false">
<p class="item-heading">{{ 'addon.mod_forum.unlockdiscussion' | translate }}</p> <ion-icon name="fas-unlock" slot="start" aria-hidden="true"></ion-icon>
</ion-label> <ion-label>
</ion-item> <p class="item-heading">{{ 'addon.mod_forum.unlockdiscussion' | translate }}</p>
<ion-item button class="ion-text-wrap" (click)="setPinState(true)" *ngIf="canPin && !discussion.pinned" detail="false"> </ion-label>
<ion-icon name="fas-map-pin" slot="start" aria-hidden="true"></ion-icon> </ion-item>
<ion-label> <ion-item button class="ion-text-wrap" (click)="setPinState(true)" *ngIf="canPin && !discussion.pinned" detail="false">
<p class="item-heading">{{ 'addon.mod_forum.pindiscussion' | translate }}</p> <ion-icon name="fas-map-pin" slot="start" aria-hidden="true"></ion-icon>
</ion-label> <ion-label>
</ion-item> <p class="item-heading">{{ 'addon.mod_forum.pindiscussion' | translate }}</p>
<ion-item button class="ion-text-wrap" (click)="setPinState(false)" *ngIf="canPin && discussion.pinned" detail="false"> </ion-label>
<ion-icon name="fas-map-pin" slot="start" class="icon-slash" aria-hidden="true"></ion-icon> </ion-item>
<ion-label> <ion-item button class="ion-text-wrap" (click)="setPinState(false)" *ngIf="canPin && discussion.pinned" detail="false">
<p class="item-heading">{{ 'addon.mod_forum.unpindiscussion' | translate }}</p> <ion-icon name="fas-map-pin" slot="start" class="icon-slash" aria-hidden="true"></ion-icon>
</ion-label> <ion-label>
</ion-item> <p class="item-heading">{{ 'addon.mod_forum.unpindiscussion' | translate }}</p>
<ion-item button class="ion-text-wrap" (click)="toggleFavouriteState(true)" *ngIf="discussion.canfavourite && !discussion.starred" </ion-label>
detail="false"> </ion-item>
<ion-icon name="fas-star" slot="start" aria-hidden="true"></ion-icon> <ion-item button class="ion-text-wrap" (click)="toggleFavouriteState(true)" *ngIf="discussion.canfavourite && !discussion.starred"
<ion-label> detail="false">
<p class="item-heading">{{ 'addon.mod_forum.addtofavourites' | translate }}</p> <ion-icon name="fas-star" slot="start" aria-hidden="true"></ion-icon>
</ion-label> <ion-label>
</ion-item> <p class="item-heading">{{ 'addon.mod_forum.addtofavourites' | translate }}</p>
<ion-item button class="ion-text-wrap" (click)="toggleFavouriteState(false)" *ngIf="discussion.canfavourite && discussion.starred" </ion-label>
detail="false"> </ion-item>
<ion-icon name="fas-star" slot="start" class="icon-slash" aria-hidden="true"></ion-icon> <ion-item button class="ion-text-wrap" (click)="toggleFavouriteState(false)" *ngIf="discussion.canfavourite && discussion.starred"
<ion-label> detail="false">
<p class="item-heading">{{ 'addon.mod_forum.removefromfavourites' | translate }}</p> <ion-icon name="fas-star" slot="start" class="icon-slash" aria-hidden="true"></ion-icon>
</ion-label> <ion-label>
</ion-item> <p class="item-heading">{{ 'addon.mod_forum.removefromfavourites' | translate }}</p>
</ion-label>
</ion-item>
</ion-list>
</ion-content>

View File

@ -1,21 +1,26 @@
<core-loading [hideUntil]="loaded" [fullscreen]="false"> <ion-content>
<ion-item button class="ion-text-wrap" (click)="editPost()" *ngIf="offlinePost || canEdit" detail="false"> <core-loading [hideUntil]="loaded" [fullscreen]="false">
<ion-icon name="fas-pen" slot="start" aria-hidden="true"></ion-icon> <ion-list>
<ion-label> <ion-item button class="ion-text-wrap" (click)="editPost()" *ngIf="offlinePost || canEdit" detail="false">
<p class="item-heading">{{ 'addon.mod_forum.edit' | translate }}</p> <ion-icon name="fas-pen" slot="start" aria-hidden="true"></ion-icon>
</ion-label> <ion-label>
</ion-item> <p class="item-heading">{{ 'addon.mod_forum.edit' | translate }}</p>
<ion-item button class="ion-text-wrap" (click)="deletePost()" *ngIf="offlinePost || canDelete" detail="false"> </ion-label>
<ion-icon name="fas-trash" slot="start" aria-hidden="true"></ion-icon> </ion-item>
<ion-label> <ion-item button class="ion-text-wrap" (click)="deletePost()" *ngIf="offlinePost || canDelete" detail="false">
<p class="item-heading" *ngIf="!offlinePost">{{ 'addon.mod_forum.delete' | translate }}</p> <ion-icon name="fas-trash" slot="start" aria-hidden="true"></ion-icon>
<p class="item-heading" *ngIf="offlinePost">{{ 'core.discard' | translate }}</p> <ion-label>
</ion-label> <p class="item-heading" *ngIf="!offlinePost">{{ 'addon.mod_forum.delete' | translate }}</p>
</ion-item> <p class="item-heading" *ngIf="offlinePost">{{ 'core.discard' | translate }}</p>
<ion-item class="ion-text-wrap" [href]="url" *ngIf="url" core-link capture="false" button detail="false" [showBrowserWarning]="false"> </ion-label>
<ion-icon name="fas-up-right-from-square" slot="start" aria-hidden="true"></ion-icon> </ion-item>
<ion-label> <ion-item class="ion-text-wrap" [href]="url" *ngIf="url" core-link capture="false" button detail="false"
<p class="item-heading">{{ 'core.openinbrowser' | translate }}</p> [showBrowserWarning]="false">
</ion-label> <ion-icon name="fas-up-right-from-square" slot="start" aria-hidden="true"></ion-icon>
</ion-item> <ion-label>
</core-loading> <p class="item-heading">{{ 'core.openinbrowser' | translate }}</p>
</ion-label>
</ion-item>
</ion-list>
</core-loading>
</ion-content>

View File

@ -49,11 +49,11 @@
"pinupdated": "The pin option has been updated.", "pinupdated": "The pin option has been updated.",
"postaddedsuccess": "Your post was successfully added.", "postaddedsuccess": "Your post was successfully added.",
"postingroup": "Posting in group \"{{groupname}}\".", "postingroup": "Posting in group \"{{groupname}}\".",
"postisprivatereply": "This is a private reply. It is only visible to you and anyone with the capability to view private replies, such as teachers or managers.", "postisprivatereply": "This is a private reply. (Teachers and other users with the capability to view private replies can also see it.)",
"posttoforum": "Post to forum", "posttoforum": "Post to forum",
"posttomygroups": "Post a copy to all groups", "posttomygroups": "Post a copy to all groups",
"privatereply": "Reply privately", "privatereply": "Reply privately",
"qandanotify": "This is a question and answer forum. In order to see other responses to these questions, you must first post your answer", "qandanotify": "This is a question and answer forum. To see other replies, you must first post your reply.",
"re": "Re:", "re": "Re:",
"refreshposts": "Refresh posts", "refreshposts": "Refresh posts",
"removefromfavourites": "Unstar this discussion", "removefromfavourites": "Unstar this discussion",

View File

@ -1,6 +1,8 @@
<ion-radio-group [(ngModel)]="selectedMode" (ionChange)="modePicked()"> <ion-content>
<ion-item class="ion-text-wrap" *ngFor="let mode of modes"> <ion-radio-group [(ngModel)]="selectedMode" (ionChange)="modePicked()">
<ion-label>{{ mode.langkey | translate }}</ion-label> <ion-item class="ion-text-wrap" *ngFor="let mode of modes">
<ion-radio slot="end" [value]="mode.key"></ion-radio> <ion-label>{{ mode.langkey | translate }}</ion-label>
</ion-item> <ion-radio slot="end" [value]="mode.key"></ion-radio>
</ion-radio-group> </ion-item>
</ion-radio-group>
</ion-content>

View File

@ -10,7 +10,7 @@
"clearchoice": "Clear my choice", "clearchoice": "Clear my choice",
"comment": "Comment", "comment": "Comment",
"completedon": "Completed on", "completedon": "Completed on",
"confirmclose": "Once you submit, you will no longer be able to change your answers for this attempt.", "confirmclose": "Once you submit your answers, you wont be able to change them.",
"confirmcontinueoffline": "This attempt has not been synchronised since {{$a}}. If you have continued this attempt in another device since then, you may lose data.", "confirmcontinueoffline": "This attempt has not been synchronised since {{$a}}. If you have continued this attempt in another device since then, you may lose data.",
"confirmleavequizonerror": "An error occurred while saving the answers. Are you sure you want to leave the quiz?", "confirmleavequizonerror": "An error occurred while saving the answers. Are you sure you want to leave the quiz?",
"confirmstart": "Your attempt will have a time limit of {{$a}}. When you start, the timer will begin to count down and cannot be paused. You must finish your attempt before it expires. Are you sure you wish to start now?", "confirmstart": "Your attempt will have a time limit of {{$a}}. When you start, the timer will begin to count down and cannot be paused. You must finish your attempt before it expires. Are you sure you wish to start now?",

View File

@ -888,7 +888,7 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
await Promise.all(this.loadedSubwikis.map(async (subwiki) => { await Promise.all(this.loadedSubwikis.map(async (subwiki) => {
let groupLabel = ''; let groupLabel = '';
if (subwiki.groupid == 0 && subwiki.userid == 0) { if (subwiki.groupid === 0 && subwiki.userid === 0) {
// Add 'All participants' subwiki if needed at the start. // Add 'All participants' subwiki if needed at the start.
if (!allParticipants) { if (!allParticipants) {
subwikiList.unshift({ subwikiList.unshift({
@ -902,7 +902,7 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
allParticipants = true; allParticipants = true;
} }
} else { } else {
if (subwiki.groupid != 0 && userGroups.length > 0) { if (subwiki.groupid !== 0 && userGroups.length > 0) {
// Get groupLabel if it has groupId. // Get groupLabel if it has groupId.
const group = userGroups.find(group => group.id == subwiki.groupid); const group = userGroups.find(group => group.id == subwiki.groupid);
groupLabel = group?.name ?? ''; groupLabel = group?.name ?? '';
@ -910,7 +910,7 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
groupLabel = Translate.instant('addon.mod_wiki.notingroup'); groupLabel = Translate.instant('addon.mod_wiki.notingroup');
} }
if (subwiki.userid != 0) { if (subwiki.userid !== 0) {
if (!multiLevelList && subwiki.groupid != 0) { if (!multiLevelList && subwiki.groupid != 0) {
multiLevelList = true; multiLevelList = true;
} }
@ -956,8 +956,6 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
showMyGroupsLabel: boolean, showMyGroupsLabel: boolean,
multiLevelList: boolean, multiLevelList: boolean,
): void { ): void {
subwikiList.sort((a, b) => a.groupid - b.groupid);
this.groupWiki = showMyGroupsLabel; this.groupWiki = showMyGroupsLabel;
this.subwikiData.count = subwikiList.length; this.subwikiData.count = subwikiList.length;
@ -1039,34 +1037,39 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
grouping.subwikis.push(subwiki); grouping.subwikis.push(subwiki);
}); });
} else if (showMyGroupsLabel) { } else if (showMyGroupsLabel) {
const noGrouping: AddonModWikiSubwikiListGrouping = { label: '', subwikis: [] }; const noGroupSubwikis: AddonModWikiSubwikiListSubwiki[] = [];
const myGroupsGrouping: AddonModWikiSubwikiListGrouping = { label: Translate.instant('core.mygroups'), subwikis: [] }; const myGroupsSubwikis: AddonModWikiSubwikiListSubwiki[] = [];
const otherGroupsGrouping: AddonModWikiSubwikiListGrouping = { const otherGroupsSubwikis: AddonModWikiSubwikiListSubwiki[] = [];
label: Translate.instant('core.othergroups'),
subwikis: [],
};
// As we loop over each subwiki, add it to the current group // As we loop over each subwiki, add it to the current group.
subwikiList.forEach((subwiki) => { subwikiList.forEach((subwiki) => {
// Add the subwiki to the currently active grouping. // Add the subwiki to the currently active grouping.
if (subwiki.canedit === undefined) { if (subwiki.groupid === 0 && subwiki.userid === 0) {
noGrouping.subwikis.push(subwiki); // All participants
noGroupSubwikis.push(subwiki);
} else if (subwiki.canedit) { } else if (subwiki.canedit) {
myGroupsGrouping.subwikis.push(subwiki); myGroupsSubwikis.push(subwiki);
} else { } else {
otherGroupsGrouping.subwikis.push(subwiki); otherGroupsSubwikis.push(subwiki);
} }
}); });
// Add each grouping to the subwikis if (myGroupsSubwikis.length > 0 && otherGroupsSubwikis.length > 0) {
if (noGrouping.subwikis.length > 0) { // Add each grouping to the subwikis.
this.subwikiData.subwikis.push(noGrouping); if (noGroupSubwikis.length > 0) {
} this.subwikiData.subwikis.push({ label: '', subwikis: noGroupSubwikis });
if (myGroupsGrouping.subwikis.length > 0) { }
this.subwikiData.subwikis.push(myGroupsGrouping);
} if (myGroupsSubwikis.length > 0) {
if (otherGroupsGrouping.subwikis.length > 0) { this.subwikiData.subwikis.push({ label: Translate.instant('core.mygroups'), subwikis: myGroupsSubwikis });
this.subwikiData.subwikis.push(otherGroupsGrouping); }
if (otherGroupsSubwikis.length > 0) {
this.subwikiData.subwikis.push({ label: Translate.instant('core.othergroups'), subwikis: otherGroupsSubwikis });
}
} else {
// Mix it again since it does not have groups and other groups.
this.subwikiData.subwikis.push({ label: '', subwikis: subwikiList });
} }
} else { } else {
this.subwikiData.subwikis.push({ label: '', subwikis: subwikiList }); this.subwikiData.subwikis.push({ label: '', subwikis: subwikiList });

View File

@ -1,19 +1,21 @@
<ion-list> <ion-content>
<ng-container *ngFor="let group of subwikis"> <ion-list>
<ion-item-divider *ngIf="group.label"> <ng-container *ngFor="let group of subwikis">
<ion-label> <ion-item-divider *ngIf="group.label">
<core-format-text [text]="group.label" contextLevel="course" [contextInstanceId]="courseId" [wsNotFiltered]="true" <ion-label>
class="item-heading"> <core-format-text [text]="group.label" contextLevel="course" [contextInstanceId]="courseId" [wsNotFiltered]="true"
</core-format-text> class="item-heading">
</ion-label> </core-format-text>
</ion-item-divider> </ion-label>
<ion-item class="ion-text-wrap" *ngFor="let subwiki of group.subwikis" (click)="openSubwiki(subwiki)" button </ion-item-divider>
[attr.aria-current]="isSubwikiSelected(subwiki) ? 'page' : 'false'" detail="false"> <ion-item class="ion-text-wrap" *ngFor="let subwiki of group.subwikis" (click)="openSubwiki(subwiki)" button
<ion-label> [attr.aria-current]="isSubwikiSelected(subwiki) ? 'page' : 'false'" detail="false">
<core-format-text [text]="subwiki.name" contextLevel="course" [contextInstanceId]="courseId" [wsNotFiltered]="true"> <ion-label>
</core-format-text> <core-format-text [text]="subwiki.name" contextLevel="course" [contextInstanceId]="courseId" [wsNotFiltered]="true">
</ion-label> </core-format-text>
<ion-icon *ngIf="isSubwikiSelected(subwiki)" name="fas-check" slot="end" aria-hidden="true"></ion-icon> </ion-label>
</ion-item> <ion-icon *ngIf="isSubwikiSelected(subwiki)" name="fas-check" slot="end" aria-hidden="true"></ion-icon>
</ng-container> </ion-item>
</ion-list> </ng-container>
</ion-list>
</ion-content>

View File

@ -38,10 +38,10 @@ export class AddonModWikiSubwikiPickerComponent {
isSubwikiSelected(subwiki: AddonModWikiSubwiki): boolean { isSubwikiSelected(subwiki: AddonModWikiSubwiki): boolean {
if (subwiki.id > 0 && this.currentSubwiki.id > 0) { if (subwiki.id > 0 && this.currentSubwiki.id > 0) {
return subwiki.id == this.currentSubwiki.id; return subwiki.id === this.currentSubwiki.id;
} }
return subwiki.userid == this.currentSubwiki.userid && subwiki.groupid == this.currentSubwiki.groupid; return subwiki.userid === this.currentSubwiki.userid && subwiki.groupid === this.currentSubwiki.groupid;
} }
/** /**

View File

@ -1,30 +1,33 @@
<ion-list [id]="uniqueId" role="menu"> <ion-content>
<ion-list-header *ngIf="title"> <ion-list [id]="uniqueId" role="menu">
<ion-label>{{title}}</ion-label> <ion-list-header *ngIf="title">
</ion-list-header> <ion-label>{{title}}</ion-label>
<ion-item class="ion-text-wrap" *ngFor="let item of items" core-link [capture]="item.captureLink" [autoLogin]="item.autoLogin" </ion-list-header>
[href]="item.href" (click)="itemClicked($event, item)" [attr.aria-label]="item.ariaAction" [hidden]="item.hidden" <ion-item class="ion-text-wrap" *ngFor="let item of items" core-link [capture]="item.captureLink" [autoLogin]="item.autoLogin"
[detail]="(item.href && !item.iconAction) || null" role="menuitem" [button]="(item.href && !item.iconAction)" [href]="item.href" (click)="itemClicked($event, item)" [attr.aria-label]="item.ariaAction" [hidden]="item.hidden"
[showBrowserWarning]="item.showBrowserWarning"> [detail]="(item.href && !item.iconAction) || null" role="menuitem" [button]="(item.href && !item.iconAction)"
<ion-label> [showBrowserWarning]="item.showBrowserWarning">
<p class="item-heading"> <ion-label>
<core-format-text [clean]="true" [text]="item.content" [filter]="false"></core-format-text> <p class="item-heading">
</p> <core-format-text [clean]="true" [text]="item.content" [filter]="false"></core-format-text>
</ion-label> </p>
<ng-container *ngIf="(item.href || item.action) && item.iconAction"> </ion-label>
<ion-icon *ngIf="item.iconAction != 'spinner' && item.iconAction != 'toggle'" [name]="item.iconAction" <ng-container *ngIf="(item.href || item.action) && item.iconAction">
[class.icon-slash]="item.iconSlash" slot="end" aria-hidden="true"> <ion-icon *ngIf="item.iconAction != 'spinner' && item.iconAction != 'toggle'" [name]="item.iconAction"
</ion-icon> [class.icon-slash]="item.iconSlash" slot="end" aria-hidden="true">
<ion-spinner *ngIf="item.iconAction == 'spinner'" slot="end" [attr.aria-label]="'core.loading' | translate"> </ion-icon>
</ion-spinner> <ion-spinner *ngIf="item.iconAction == 'spinner'" slot="end" [attr.aria-label]="'core.loading' | translate">
<ion-toggle *ngIf="item.iconAction == 'toggle'" [(ngModel)]="item.toggle" (ionChange)="item.toggleChanged($event)" slot="end"> </ion-spinner>
</ion-toggle> <ion-toggle *ngIf="item.iconAction == 'toggle'" [(ngModel)]="item.toggle" (ionChange)="item.toggleChanged($event)"
</ng-container> slot="end">
<ion-badge class="{{item.badgeClass}}" slot="end" *ngIf="item.badge"> </ion-toggle>
<span [attr.ara-hidden]="!!item.badgeA11yText">{{item.badge}}</span> </ng-container>
<span class="sr-only" *ngIf="item.badgeA11yText"> <ion-badge class="{{item.badgeClass}}" slot="end" *ngIf="item.badge">
{{ item.badgeA11yText | translate: {$a : item.badge } }} <span [attr.ara-hidden]="!!item.badgeA11yText">{{item.badge}}</span>
</span> <span class="sr-only" *ngIf="item.badgeA11yText">
</ion-badge> {{ item.badgeA11yText | translate: {$a : item.badge } }}
</ion-item> </span>
</ion-list> </ion-badge>
</ion-item>
</ion-list>
</ion-content>

View File

@ -64,7 +64,7 @@
</core-loading> </core-loading>
</ion-content> </ion-content>
<ion-footer class="footer-adjustable" *ngIf="commentsLoaded && canAddComments"> <ion-footer class="footer-adjustable" *ngIf="commentsLoaded && canAddComments">
<ion-toolbar color="contrast"> <ion-toolbar>
<core-send-message-form [sendDisabled]="sending" [message]="newComment" (onSubmit)="addComment($event)" <core-send-message-form [sendDisabled]="sending" [message]="newComment" (onSubmit)="addComment($event)"
[placeholder]="'core.comments.addcomment' | translate"> [placeholder]="'core.comments.addcomment' | translate">
</core-send-message-form> </core-send-message-form>

View File

@ -1,40 +1,42 @@
<ion-list> <ion-content>
<ion-item button class="ion-text-wrap" (click)="action('download')" *ngIf="downloadCourseEnabled" detail="false"> <ion-list>
<ion-icon *ngIf="!prefetch.loading" [name]="prefetch.icon" slot="start" aria-hidden="true"></ion-icon> <ion-item button class="ion-text-wrap" (click)="action('download')" *ngIf="downloadCourseEnabled" detail="false">
<ion-spinner *ngIf="prefetch.loading" slot="start" [attr.aria-label]="'core.loading' | translate"></ion-spinner> <ion-icon *ngIf="!prefetch.loading" [name]="prefetch.icon" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-spinner *ngIf="prefetch.loading" slot="start" [attr.aria-label]="'core.loading' | translate"></ion-spinner>
<p class="item-heading">{{ prefetch.statusTranslatable | translate }}</p> <ion-label>
</ion-label> <p class="item-heading">{{ prefetch.statusTranslatable | translate }}</p>
</ion-item> </ion-label>
<ion-item button class="ion-text-wrap" (click)="action('delete')" detail="false" </ion-item>
*ngIf="prefetch.status == 'downloaded' || prefetch.status == 'outdated'"> <ion-item button class="ion-text-wrap" (click)="action('delete')" detail="false"
<ion-icon name="fas-trash" slot="start" aria-hidden="true"></ion-icon> *ngIf="prefetch.status == 'downloaded' || prefetch.status == 'outdated'">
<ion-label> <ion-icon name="fas-trash" slot="start" aria-hidden="true"></ion-icon>
<p class="item-heading">{{ 'addon.storagemanager.deletedata' | translate }}</p> <ion-label>
</ion-label> <p class="item-heading">{{ 'addon.storagemanager.deletedata' | translate }}</p>
</ion-item> </ion-label>
<ion-item button class="ion-text-wrap" (click)="action('hide')" *ngIf="!course.hidden" detail="false"> </ion-item>
<ion-icon name="fas-eye" slot="start" aria-hidden="true"></ion-icon> <ion-item button class="ion-text-wrap" (click)="action('hide')" *ngIf="!course.hidden" detail="false">
<ion-label> <ion-icon name="fas-eye" slot="start" aria-hidden="true"></ion-icon>
<p class="item-heading">{{ 'core.courses.hidecourse' | translate }}</p> <ion-label>
</ion-label> <p class="item-heading">{{ 'core.courses.hidecourse' | translate }}</p>
</ion-item> </ion-label>
<ion-item button class="ion-text-wrap" (click)="action('show')" *ngIf="course.hidden" detail="false"> </ion-item>
<ion-icon name="fas-eye-slash" slot="start" aria-hidden="true"></ion-icon> <ion-item button class="ion-text-wrap" (click)="action('show')" *ngIf="course.hidden" detail="false">
<ion-label> <ion-icon name="fas-eye-slash" slot="start" aria-hidden="true"></ion-icon>
<p class="item-heading">{{ 'core.courses.show' | translate }}</p> <ion-label>
</ion-label> <p class="item-heading">{{ 'core.courses.show' | translate }}</p>
</ion-item> </ion-label>
<ion-item button class="ion-text-wrap" (click)="action('favourite')" *ngIf="!course.isfavourite" detail="false"> </ion-item>
<ion-icon name="fas-star" slot="start" aria-hidden="true"></ion-icon> <ion-item button class="ion-text-wrap" (click)="action('favourite')" *ngIf="!course.isfavourite" detail="false">
<ion-label> <ion-icon name="fas-star" slot="start" aria-hidden="true"></ion-icon>
<p class="item-heading">{{ 'core.courses.addtofavourites' | translate }}</p> <ion-label>
</ion-label> <p class="item-heading">{{ 'core.courses.addtofavourites' | translate }}</p>
</ion-item> </ion-label>
<ion-item button class="ion-text-wrap" (click)="action('unfavourite')" *ngIf="course.isfavourite" detail="false"> </ion-item>
<ion-icon name="far-star" slot="start" aria-hidden="true"></ion-icon> <ion-item button class="ion-text-wrap" (click)="action('unfavourite')" *ngIf="course.isfavourite" detail="false">
<ion-label> <ion-icon name="far-star" slot="start" aria-hidden="true"></ion-icon>
<p class="item-heading">{{ 'core.courses.removefromfavourites' | translate }}</p> <ion-label>
</ion-label> <p class="item-heading">{{ 'core.courses.removefromfavourites' | translate }}</p>
</ion-item> </ion-label>
</ion-list> </ion-item>
</ion-list>
</ion-content>

View File

@ -45,7 +45,7 @@
</button> </button>
</ion-slide> </ion-slide>
<ion-slide> <ion-slide>
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.strike" [title]="'core.editor.strike' | translate" <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.strike" [title]="'core.editor.strikethrough' | translate"
(click)="buttonAction($event, 'strikethrough', 'strike')" (keyup)="buttonAction($event, 'strikethrough', 'strike')" (click)="buttonAction($event, 'strikethrough', 'strike')" (keyup)="buttonAction($event, 'strikethrough', 'strike')"
(mousedown)="downAction($event)" (keydown)="downAction($event)" tabindex="0"> (mousedown)="downAction($event)" (keydown)="downAction($event)" tabindex="0">
<ion-icon name="fas-strikethrough" aria-hidden="true"></ion-icon> <ion-icon name="fas-strikethrough" aria-hidden="true"></ion-icon>

View File

@ -7,11 +7,11 @@
"h5": "Heading (small)", "h5": "Heading (small)",
"hidetoolbar": "Hide toolbar", "hidetoolbar": "Hide toolbar",
"italic": "Italic", "italic": "Italic",
"orderedlist": "Ordered list", "orderedlist": "Ordered List",
"p": "Paragraph", "p": "Paragraph",
"strike": "Strike through", "strikethrough": "Strikethrough",
"textrecovered": "A draft version of this text was automatically restored.", "textrecovered": "A draft version of this text was automatically restored.",
"toggle": "Toggle editor", "toggle": "Toggle editor",
"underline": "Underline", "underline": "Underline",
"unorderedlist": "Unordered list" "unorderedlist": "Bulleted List"
} }

View File

@ -19,7 +19,7 @@
"credentialsdescription": "Please provide your username and password to log in.", "credentialsdescription": "Please provide your username and password to log in.",
"credentialshelp": "If you have problems logging in, try again later or contact your school or learning provider.", "credentialshelp": "If you have problems logging in, try again later or contact your school or learning provider.",
"credentialssupportsubject": "Need help logging in", "credentialssupportsubject": "Need help logging in",
"emailconfirmsent": "<p>An email should have been sent to your address at <b>{{$a}}</b></p><p>It contains easy instructions to complete your registration.</p>", "emailconfirmsent": "<p>An email should have been sent to your address at <b>{{$a}}</b></p>\n <p>It contains easy instructions to complete your registration.</p>\n <p>If you continue to have difficulty, contact the site administrator.</p>",
"emailconfirmsentnoemail": "<p>An email should have been sent to your address.</p><p>It contains easy instructions to complete your registration.</p>", "emailconfirmsentnoemail": "<p>An email should have been sent to your address.</p><p>It contains easy instructions to complete your registration.</p>",
"emailconfirmsentsuccess": "Confirmation email sent successfully", "emailconfirmsentsuccess": "Confirmation email sent successfully",
"emailnotmatch": "Emails do not match", "emailnotmatch": "Emails do not match",
@ -71,7 +71,7 @@
"loginsteps": "For full access to this site, you first need to create an account.", "loginsteps": "For full access to this site, you first need to create an account.",
"missingemail": "Missing email address", "missingemail": "Missing email address",
"missingfirstname": "Missing given name", "missingfirstname": "Missing given name",
"missinglastname": "Missing surname", "missinglastname": "Missing last name",
"mobileservicesnotenabled": "Mobile services are not enabled on the site.", "mobileservicesnotenabled": "Mobile services are not enabled on the site.",
"mustconfirm": "You need to confirm your account", "mustconfirm": "You need to confirm your account",
"newaccount": "New account", "newaccount": "New account",

View File

@ -40,7 +40,7 @@ Feature: Test signup in app
And I should find "Password required" in the app And I should find "Password required" in the app
And I should find "Missing email address" in the app And I should find "Missing email address" in the app
And I should find "Missing given name" in the app And I should find "Missing given name" in the app
And I should find "Missing surname" in the app And I should find "Missing last name" in the app
When I set the following fields to these values in the app: When I set the following fields to these values in the app:
| Username | u1 | | Username | u1 |
@ -48,7 +48,7 @@ Feature: Test signup in app
| Email address | u1@u1.com | | Email address | u1@u1.com |
| Email (again) | u2@u1.com | | Email (again) | u2@u1.com |
| First name | User | | First name | User |
| Surname | Test | | Last name | Test |
| City/town | Barcelona | | City/town | Barcelona |
| Country | Spain | | Country | Spain |
Then I should find "Emails do not match" in the app Then I should find "Emails do not match" in the app
@ -98,7 +98,7 @@ Feature: Test signup in app
| Email address | u1@u1.com | | Email address | u1@u1.com |
| Email (again) | u1@u1.com | | Email (again) | u1@u1.com |
| First name | User | | First name | User |
| Surname | Test | | Last name | Test |
| City/town | Barcelona | | City/town | Barcelona |
| Country | Spain | | Country | Spain |
And I press "Create my new account" in the app And I press "Create my new account" in the app
@ -147,7 +147,7 @@ Feature: Test signup in app
| Email address | u1@u1.com | | Email address | u1@u1.com |
| Email (again) | u1@u1.com | | Email (again) | u1@u1.com |
| First name | User | | First name | User |
| Surname | Test | | Last name | Test |
| City/town | Barcelona | | City/town | Barcelona |
| Country | Spain | | Country | Spain |
And I press "Create my new account" in the app And I press "Create my new account" in the app

View File

@ -1,6 +1,5 @@
{ {
"address": "Address", "address": "Address",
"useraccount": "User account",
"city": "City/town", "city": "City/town",
"completeprofile": "Complete profile", "completeprofile": "Complete profile",
"completeprofilehelp": "If you have problems completing your profile, try again later or contact your school or learning provider.", "completeprofilehelp": "If you have problems completing your profile, try again later or contact your school or learning provider.",
@ -20,7 +19,7 @@
"firstname": "First name", "firstname": "First name",
"interests": "Interests", "interests": "Interests",
"lastcourseaccess": "Last access to course", "lastcourseaccess": "Last access to course",
"lastname": "Surname", "lastname": "Last name",
"manager": "Manager", "manager": "Manager",
"newpicture": "New picture", "newpicture": "New picture",
"noparticipants": "No participants found for this course", "noparticipants": "No participants found for this course",
@ -35,6 +34,7 @@
"supportmessagesent": "Your message has been sent.", "supportmessagesent": "Your message has been sent.",
"supportsubject": "[App] {{subject}}", "supportsubject": "[App] {{subject}}",
"teacher": "Non-editing teacher", "teacher": "Non-editing teacher",
"useraccount": "User account",
"userwithid": "User with ID {{id}}", "userwithid": "User with ID {{id}}",
"webpage": "Web page" "webpage": "Web page"
} }

View File

@ -174,8 +174,8 @@
"minutes": "minutes", "minutes": "minutes",
"misc": "Miscellaneous", "misc": "Miscellaneous",
"mod_assign": "Assignment", "mod_assign": "Assignment",
"mod_book": "Book",
"mod_bigbluebuttonbn": "BigBlueButton", "mod_bigbluebuttonbn": "BigBlueButton",
"mod_book": "Book",
"mod_chat": "Chat", "mod_chat": "Chat",
"mod_choice": "Choice", "mod_choice": "Choice",
"mod_data": "Database", "mod_data": "Database",
@ -187,7 +187,7 @@
"mod_glossary": "Glossary", "mod_glossary": "Glossary",
"mod_h5pactivity": "H5P", "mod_h5pactivity": "H5P",
"mod_imscp": "IMS content package", "mod_imscp": "IMS content package",
"mod_label": "Text and media", "mod_label": "Text and media area",
"mod_lesson": "Lesson", "mod_lesson": "Lesson",
"mod_lti": "External tool", "mod_lti": "External tool",
"mod_page": "Page", "mod_page": "Page",

View File

@ -538,7 +538,7 @@ export class CoreTextUtilsProvider {
* @returns Error message, undefined if not found. * @returns Error message, undefined if not found.
*/ */
getErrorMessageFromError(error?: CoreAnyError): string | undefined { getErrorMessageFromError(error?: CoreAnyError): string | undefined {
if (typeof error == 'string') { if (typeof error === 'string') {
return error; return error;
} }

View File

@ -253,10 +253,6 @@ ion-tabs.hide-header ion-header {
display: none; display: none;
} }
ion-footer ion-toolbar.ion-color-contrast {
background-color: var(--contrast-background);
}
ion-footer { ion-footer {
background-color: var(--contrast-background); background-color: var(--contrast-background);
} }

View File

@ -228,6 +228,10 @@ html {
} }
} }
ion-popover.ios {
--min-width: 250px;
}
ion-toast { ion-toast {
--color: var(--ion-color-step-50); --color: var(--ion-color-step-50);
--button-color: var(--primary); --button-color: var(--primary);