Merge pull request #2216 from crazyserver/MOBILE-3213

Mobile 3213
main
Juan Leyva 2019-12-17 11:43:42 +01:00 committed by GitHub
commit dbb9e86e4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 162 additions and 73 deletions

View File

@ -2,6 +2,10 @@ ion-app.app-root addon-mod-forum-post .addon-mod_forum-post {
background-color: $white; background-color: $white;
border-bottom: 1px solid $list-md-border-color; border-bottom: 1px solid $list-md-border-color;
@include darkmode() {
background-color: $core-dark-item-bg-color;
}
.addon-forum-star { .addon-forum-star {
color: $core-star-color; color: $core-star-color;
} }

View File

@ -2,7 +2,7 @@ ion-app.app-root page-addon-mod-forum-discussion {
.highlight .card-header .item { .highlight .card-header .item {
background-color: $gray-lighter; background-color: $gray-lighter;
@include darkmode() { @include darkmode() {
background-color: $black; background-color: $gray-dark;
} }
} }

View File

@ -22,6 +22,7 @@ import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader'; import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
import { CoreUserProvider } from '@core/user/providers/user';
import { CoreSplitViewComponent } from '@components/split-view/split-view'; import { CoreSplitViewComponent } from '@components/split-view/split-view';
import { CoreRatingProvider, CoreRatingInfo } from '@core/rating/providers/rating'; import { CoreRatingProvider, CoreRatingInfo } from '@core/rating/providers/rating';
import { CoreRatingOfflineProvider } from '@core/rating/providers/offline'; import { CoreRatingOfflineProvider } from '@core/rating/providers/offline';
@ -57,7 +58,7 @@ export class AddonModForumDiscussionPage implements OnDestroy {
isOnline: boolean; isOnline: boolean;
isSplitViewOn: boolean; isSplitViewOn: boolean;
postHasOffline: boolean; postHasOffline: boolean;
sort: SortType = 'flat-oldest'; sort: SortType = 'nested';
trackPosts: boolean; trackPosts: boolean;
replyData = { replyData = {
replyingTo: 0, replyingTo: 0,
@ -96,19 +97,20 @@ export class AddonModForumDiscussionPage implements OnDestroy {
constructor(navParams: NavParams, constructor(navParams: NavParams,
network: Network, network: Network,
zone: NgZone, zone: NgZone,
private appProvider: CoreAppProvider, protected appProvider: CoreAppProvider,
private eventsProvider: CoreEventsProvider, protected eventsProvider: CoreEventsProvider,
private sitesProvider: CoreSitesProvider, protected sitesProvider: CoreSitesProvider,
private domUtils: CoreDomUtilsProvider, protected domUtils: CoreDomUtilsProvider,
private utils: CoreUtilsProvider, protected utils: CoreUtilsProvider,
private translate: TranslateService, protected translate: TranslateService,
private uploaderProvider: CoreFileUploaderProvider, protected uploaderProvider: CoreFileUploaderProvider,
private forumProvider: AddonModForumProvider, protected forumProvider: AddonModForumProvider,
private forumOffline: AddonModForumOfflineProvider, protected forumOffline: AddonModForumOfflineProvider,
private forumHelper: AddonModForumHelperProvider, protected forumHelper: AddonModForumHelperProvider,
private forumSync: AddonModForumSyncProvider, protected forumSync: AddonModForumSyncProvider,
private ratingOffline: CoreRatingOfflineProvider, protected ratingOffline: CoreRatingOfflineProvider,
@Optional() private svComponent: CoreSplitViewComponent, protected userProvider: CoreUserProvider,
@Optional() protected svComponent: CoreSplitViewComponent,
protected navCtrl: NavController) { protected navCtrl: NavController) {
this.courseId = navParams.get('courseId'); this.courseId = navParams.get('courseId');
this.cmId = navParams.get('cmId'); this.cmId = navParams.get('cmId');
@ -134,7 +136,29 @@ export class AddonModForumDiscussionPage implements OnDestroy {
* View loaded. * View loaded.
*/ */
ionViewDidLoad(): void { ionViewDidLoad(): void {
this.sitesProvider.getCurrentSite().getLocalSiteConfig('AddonModForumDiscussionSort', this.sort).then((value) => { this.sitesProvider.getCurrentSite().getLocalSiteConfig('AddonModForumDiscussionSort').catch(() => {
this.userProvider.getUserPreference('forum_displaymode').catch(() => {
// Ignore errors.
}).then((value) => {
const sortValue = value && parseInt(value, 10);
switch (sortValue) {
case 1:
this.sort = 'flat-oldest';
break;
case -1:
this.sort = 'flat-newest';
break;
case 3:
this.sort = 'nested';
break;
case 2: // Threaded not implemented.
default:
// Not set, use default sort.
// @TODO add fallback to $CFG->forum_displaymode.
}
});
}).then((value) => {
this.sort = value; this.sort = value;
}).finally(() => { }).finally(() => {
this.fetchPosts(true, false, true).then(() => { this.fetchPosts(true, false, true).then(() => {

View File

@ -51,8 +51,8 @@
<h3>{{ 'addon.mod_scorm.gradeforattempt' | translate }} {{attempt.number}}</h3> <h3>{{ 'addon.mod_scorm.gradeforattempt' | translate }} {{attempt.number}}</h3>
<p item-content *ngIf="attempt.grade != -1">{{ attempt.grade }}</p> <p item-content *ngIf="attempt.grade != -1">{{ attempt.grade }}</p>
<p item-content *ngIf="attempt.grade == -1">{{ 'addon.mod_scorm.cannotcalculategrade' | translate }}</p> <p item-content *ngIf="attempt.grade == -1">{{ 'addon.mod_scorm.cannotcalculategrade' | translate }}</p>
<p item-content *ngIf="scorm.maxattempt == 0 || attempt.number <= scorm.maxattempt">{{ 'addon.mod_scorm.offlineattemptnote' | translate }}</p> <p *ngIf="scorm.maxattempt == 0 || attempt.number <= scorm.maxattempt">{{ 'addon.mod_scorm.offlineattemptnote' | translate }}</p>
<p item-content *ngIf="scorm.maxattempt != 0 && attempt.number > scorm.maxattempt">{{ 'addon.mod_scorm.offlineattemptovermax' | translate }}</p> <p *ngIf="scorm.maxattempt != 0 && attempt.number > scorm.maxattempt">{{ 'addon.mod_scorm.offlineattemptovermax' | translate }}</p>
</ion-item> </ion-item>
<ion-item text-wrap *ngIf="scorm.displayattemptstatus && scorm.gradeMethodReadable"> <ion-item text-wrap *ngIf="scorm.displayattemptstatus && scorm.gradeMethodReadable">
<h3>{{ 'addon.mod_scorm.grademethod' | translate }}</h3> <h3>{{ 'addon.mod_scorm.grademethod' | translate }}</h3>
@ -95,9 +95,9 @@
<!-- If data shown doesn't belong to last attempt, show a warning. --> <!-- If data shown doesn't belong to last attempt, show a warning. -->
<p *ngIf="attemptToContinue">{{ 'addon.mod_scorm.dataattemptshown' | translate:{number: attemptToContinue} }}</p> <p *ngIf="attemptToContinue">{{ 'addon.mod_scorm.dataattemptshown' | translate:{number: attemptToContinue} }}</p>
<p>{{ currentOrganization.title }}</p> <p>{{ currentOrganization.title }}</p>
<div *ngFor="let sco of toc" class="core-padding-{{sco.level}}"> <div *ngFor="let sco of toc" class="core-padding-{{sco.level}} addon-mod_scorm-type-{{sco.scormtype}}">
<p *ngIf="sco.isvisible"> <p *ngIf="sco.isvisible">
<img [src]="sco.image.url" [alt]="sco.image.description" /> <core-icon [name]="sco.image.icon" [label]="sco.image.description" item-start></core-icon>
<a *ngIf="sco.prereq && sco.launch" (click)="open($event, sco.id)"><core-format-text [text]="sco.title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-format-text></a> <a *ngIf="sco.prereq && sco.launch" (click)="open($event, sco.id)"><core-format-text [text]="sco.title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-format-text></a>
<span *ngIf="!sco.prereq || !sco.launch"><core-format-text [text]="sco.title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-format-text></span> <span *ngIf="!sco.prereq || !sco.launch"><core-format-text [text]="sco.title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-format-text></span>
<span *ngIf="accessInfo && accessInfo.canviewscores && sco.score_raw">({{ 'addon.mod_scorm.score' | translate }}: {{sco.score_raw}})</span> <span *ngIf="accessInfo && accessInfo.canviewscores && sco.score_raw">({{ 'addon.mod_scorm.score' | translate }}: {{sco.score_raw}})</span>

View File

@ -1,9 +1,13 @@
ion-app.app-root addon-mod-scorm-index { ion-app.app-root addon-mod-scorm-index,
ion-app.app-root page-addon-mod-scorm-toc {
.addon-mod_scorm-toc { .addon-mod_scorm-toc {
img { // Hide all non sco icons using css to maintain padding.
width: auto; ion-icon {
display: inline; opacity: 0;
}
.addon-mod_scorm-type-sco ion-icon {
opacity: 1
} }
} }
} }

View File

@ -10,7 +10,7 @@
</ion-header> </ion-header>
<ion-content> <ion-content>
<nav> <nav>
<ion-list> <ion-list class="addon-mod_scorm-toc">
<ion-item text-wrap *ngIf="attemptToContinue"> <ion-item text-wrap *ngIf="attemptToContinue">
<p>{{ 'addon.mod_scorm.dataattemptshown' | translate:{number: attemptToContinue} }}</p> <p>{{ 'addon.mod_scorm.dataattemptshown' | translate:{number: attemptToContinue} }}</p>
</ion-item> </ion-item>
@ -23,8 +23,8 @@
<!-- List of SCOs. --> <!-- List of SCOs. -->
<ng-container *ngFor="let sco of toc"> <ng-container *ngFor="let sco of toc">
<a *ngIf="sco.isvisible" ion-item text-wrap [ngClass]="'core-padding-' + sco.level" [class.core-nav-item-selected]="selected == sco.id" (click)="loadSco(sco)" [attr.disabled]="!sco.prereq || !sco.launch ? true : null" [attr.detail-none]="!sco.prereq || !sco.launch ? true : null"> <a *ngIf="sco.isvisible" ion-item text-wrap [ngClass]="'core-padding-' + sco.level + ' addon-mod_scorm-type-' + sco.scormtype" [class.core-nav-item-selected]="selected == sco.id" [class]="" (click)="loadSco(sco)" [attr.disabled]="!sco.prereq || !sco.launch ? true : null" [attr.detail-none]="!sco.prereq || !sco.launch ? true : null">
<img [src]="sco.image.url" [alt]="sco.image.description" /> <core-icon [name]="sco.image.icon" [label]="sco.image.description" item-start></core-icon>
<core-format-text [text]="sco.title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"></core-format-text> <core-format-text [text]="sco.title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"></core-format-text>
<span *ngIf="accessInfo && accessInfo.canviewscores && sco.score_raw">({{ 'addon.mod_scorm.score' | translate }}: {{sco.score_raw}})</span> <span *ngIf="accessInfo && accessInfo.canviewscores && sco.score_raw">({{ 'addon.mod_scorm.score' | translate }}: {{sco.score_raw}})</span>
</a> </a>

View File

@ -16,6 +16,7 @@ import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular'; import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { CoreDirectivesModule } from '@directives/directives.module'; import { CoreDirectivesModule } from '@directives/directives.module';
import { CoreComponentsModule } from '@components/components.module';
import { AddonModScormTocPage } from './toc'; import { AddonModScormTocPage } from './toc';
@NgModule({ @NgModule({
@ -24,6 +25,7 @@ import { AddonModScormTocPage } from './toc';
], ],
imports: [ imports: [
CoreDirectivesModule, CoreDirectivesModule,
CoreComponentsModule,
IonicPageModule.forChild(AddonModScormTocPage), IonicPageModule.forChild(AddonModScormTocPage),
TranslateModule.forChild() TranslateModule.forChild()
], ],

View File

@ -106,6 +106,22 @@ export class AddonModScormProvider {
'b': 'browsed', 'b': 'browsed',
'n': 'notattempted' 'n': 'notattempted'
}; };
protected static STATUS_TO_ICON = {
assetc: 'fa-file-archive-o',
asset: 'fa-file-archive-o',
browsed: 'fa-book',
completed: 'fa-check-square-o',
failed: 'fa-times',
incomplete: 'fa-pencil-square-o',
minus: 'fa-minus',
notattempted: 'fa-square-o',
passed: 'fa-check',
plus: 'fa-plus',
popdown: 'fa-window-close-o',
popup: 'fa-window-restore',
suspend: 'fa-pause',
wait: 'fa-clock-o',
};
protected ROOT_CACHE_KEY = 'mmaModScorm:'; protected ROOT_CACHE_KEY = 'mmaModScorm:';
protected logger; protected logger;
@ -1048,39 +1064,56 @@ export class AddonModScormProvider {
* @param incomplete Whether the SCORM is incomplete. * @param incomplete Whether the SCORM is incomplete.
* @return Image URL and description. * @return Image URL and description.
*/ */
getScoStatusIcon(sco: any, incomplete?: boolean): {url: string, description: string} { getScoStatusIcon(sco: any, incomplete?: boolean): {icon: string, description: string} {
let imageName = '', let imageName = '',
descName = '', descName = '',
status; suspendedStr = '';
if (sco.scormtype == 'sco') { const status = sco.status;
// Not an asset, calculate image using status.
status = sco.status;
if (this.VALID_STATUSES.indexOf(status) < 0) {
// Status empty or not valid, use 'notattempted'.
status = 'notattempted';
}
if (!incomplete) { if (sco.isvisible) {
// Check if SCO is completed or not. If SCORM is incomplete there's no need to check SCO. if (this.VALID_STATUSES.indexOf(status) >= 0) {
incomplete = this.isStatusIncomplete(status); if (sco.scormtype == 'sco') {
} imageName = status;
descName = status;
} else {
imageName = 'asset';
descName = 'assetlaunched';
}
if (incomplete && sco.exitvalue == 'suspend') { if (!incomplete) {
imageName = 'suspend'; // Check if SCO is completed or not. If SCORM is incomplete there's no need to check SCO.
descName = 'suspended'; incomplete = this.isStatusIncomplete(status);
}
if (incomplete && sco.exitvalue == 'suspend') {
imageName = 'suspend';
suspendedStr = ' - ' + this.translate.instant('addon.mod_scorm.suspended');
}
} else { } else {
imageName = sco.status; incomplete = true;
descName = sco.status;
if (sco.scormtype == 'sco') {
// Status empty or not valid, use 'notattempted'.
imageName = 'notattempted';
} else {
imageName = 'asset';
}
descName = imageName;
} }
} else {
imageName = 'asset';
descName = (!sco.status || sco.status == 'notattempted') ? 'asset' : 'assetlaunched';
} }
if (imageName == '') {
imageName = 'notattempted';
descName = 'notattempted';
suspendedStr = '';
}
sco.incomplete = incomplete;
return { return {
url: 'assets/img/scorm/' + imageName + '.gif', icon: AddonModScormProvider.STATUS_TO_ICON[imageName],
description: this.translate.instant('addon.mod_scorm.' + descName) description: this.translate.instant('addon.mod_scorm.' + descName) + suspendedStr
}; };
} }

View File

@ -39,8 +39,8 @@
<div *ngIf="question.multiArray && question.multiArray.length" [attr.padding-top]="index == 1"> <div *ngIf="question.multiArray && question.multiArray.length" [attr.padding-top]="index == 1">
<h3 padding-horizontal>{{ question.text }}</h3> <h3 padding-horizontal>{{ question.text }}</h3>
<ion-grid no-padding> <ion-grid no-padding>
<ion-row no-padding align-items-center class="hidden-phone"> <ion-row no-padding nowrap align-items-center class="hidden-phone">
<ion-col col-7> <ion-col col-6>
<div padding>{{ 'addon.mod_survey.responses' | translate }}</div> <div padding>{{ 'addon.mod_survey.responses' | translate }}</div>
</ion-col> </ion-col>
<ion-col text-center *ngFor="let option of question.optionsArray"> <ion-col text-center *ngFor="let option of question.optionsArray">
@ -56,7 +56,7 @@
<!-- Subquestion --> <!-- Subquestion -->
<ion-grid no-padding *ngIf="question.parent !== 0" text-wrap [class.even]="isEven"> <ion-grid no-padding *ngIf="question.parent !== 0" text-wrap [class.even]="isEven">
<ion-row no-padding nowrap align-items-center radio-group [(ngModel)]="answers[question.name]" [required]="question.required"> <ion-row no-padding nowrap align-items-center radio-group [(ngModel)]="answers[question.name]" [required]="question.required">
<ion-col col-7> <ion-col col-6>
<ion-label padding-horizontal [core-mark-required]="question.required" id="addon-mod_survey-{{question.name}}"><strong>{{question.num}}.</strong> {{ question.text }}</ion-label> <ion-label padding-horizontal [core-mark-required]="question.required" id="addon-mod_survey-{{question.name}}"><strong>{{question.num}}.</strong> {{ question.text }}</ion-label>
</ion-col> </ion-col>
@ -77,13 +77,13 @@
<ng-container *ngIf="(!question.multiArray || question.multiArray.length == 0) && question.parent === 0"> <ng-container *ngIf="(!question.multiArray || question.multiArray.length == 0) && question.parent === 0">
<ion-grid no-padding text-wrap *ngIf="question.type > 0" [class.even]="isEven"> <ion-grid no-padding text-wrap *ngIf="question.type > 0" [class.even]="isEven">
<ion-row no-padding align-items-center> <ion-row no-padding align-items-center>
<ion-col col-7> <ion-col col-6>
<ion-label [core-mark-required]="question.required" padding-horizontal id="addon-mod_survey-{{question.name}}"><strong>{{question.num}}.</strong> {{ question.text }}</ion-label> <ion-label [core-mark-required]="question.required" padding-horizontal id="addon-mod_survey-{{question.name}}"><strong>{{question.num}}.</strong> {{ question.text }}</ion-label>
</ion-col> </ion-col>
<ion-col col-5> <ion-col col-6>
<ion-select padding [(ngModel)]="answers[question.name]" [attr.aria-labelledby]="'addon-mod_survey-'+question.name" interface="action-sheet" [required]="question.required"> <ion-select padding [(ngModel)]="answers[question.name]" [attr.aria-labelledby]="'addon-mod_survey-'+question.name" interface="action-sheet" [required]="question.required">
<ion-option *ngFor="let option of question.optionsArray; let value=index;" [value]="value">{{option}}</ion-option> <ion-option *ngFor="let option of question.optionsArray; let value=index;" [value]="value">{{option}}</ion-option>
</ion-select> </ion-select>
</ion-col> </ion-col>
</ion-row> </ion-row>
</ion-grid> </ion-grid>

View File

@ -163,13 +163,10 @@ export class AddonModSurveyIndexComponent extends CoreCourseModuleMainActivityCo
* @return If answers are valid * @return If answers are valid
*/ */
isValidResponse(): boolean { isValidResponse(): boolean {
for (const x in this.answers) { return !this.questions.some((question) => {
if (this.answers[x] === -1) { return question.required && question.name &&
return false; (question.type === 0 ? this.answers[question.name] == '' : parseInt(this.answers[question.name], 10) === -1);
} });
}
return true;
} }
/** /**

View File

@ -4,6 +4,11 @@ $addon-mod-wiki-toc-title-color: $gray-darker !default;
$addon-mod-wiki-toc-border-color: $gray-dark !default; $addon-mod-wiki-toc-border-color: $gray-dark !default;
$addon-mod-wiki-toc-background-color: $gray-light !default; $addon-mod-wiki-toc-background-color: $gray-light !default;
$addon-mod-wiki-dark-toc-title-color: $white !default;
$addon-mod-wiki-dark-toc-border-color: $gray-dark !default;
$addon-mod-wiki-dark-toc-background-color: $gray-darker !default;
$addon-mod-wiki-dark-newentry-link-color: $red-light !default;
ion-app.app-root addon-mod-wiki-index { ion-app.app-root addon-mod-wiki-index {
background-color: $white; background-color: $white;
@include darkmode() { @include darkmode() {
@ -28,6 +33,17 @@ ion-app.app-root addon-mod-wiki-index {
a { a {
color: $link-color; color: $link-color;
} }
@include darkmode() {
border: 1px solid $addon-mod-wiki-dark-toc-border-color;
background: $addon-mod-wiki-dark-toc-background-color;
p {
color: $core-dark-text-color !important;
}
a {
color: $core-dark-link-color;
}
}
margin: 16px; margin: 16px;
padding: 8px; padding: 8px;
} }
@ -55,6 +71,9 @@ ion-app.app-root addon-mod-wiki-index {
.wiki_newentry { .wiki_newentry {
color: $addon-mod-wiki-newentry-link-color; color: $addon-mod-wiki-newentry-link-color;
font-style: italic; font-style: italic;
@include darkmode() {
color: $addon-mod-wiki-dark-newentry-link-color !important;
}
} }
/* Hide edit section links */ /* Hide edit section links */

View File

@ -500,7 +500,7 @@ ion-app.app-root {
@include darkmode() { @include darkmode() {
ion-select.core-button-select, ion-select.core-button-select,
.core-button-select { .core-button-select {
background-color: $core-dark-item-divider-bg-color; background-color: $core-dark-item-bg-color;
&.select-md, &.select-md,
@ -509,7 +509,7 @@ ion-app.app-root {
&.button-ios, &.button-ios,
&.select-wp, &.select-wp,
&.button-wp { &.button-wp {
background: $core-dark-item-divider-bg-color; background: $core-dark-item-bg-color;
} }
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 362 B

View File

@ -82,6 +82,7 @@ export class CoreIconComponent implements OnChanges, OnDestroy {
!this.ariaLabel && this.newElement.setAttribute('aria-hidden', 'true'); !this.ariaLabel && this.newElement.setAttribute('aria-hidden', 'true');
!this.ariaLabel && this.newElement.setAttribute('role', 'presentation'); !this.ariaLabel && this.newElement.setAttribute('role', 'presentation');
this.ariaLabel && this.newElement.setAttribute('aria-label', this.ariaLabel); this.ariaLabel && this.newElement.setAttribute('aria-label', this.ariaLabel);
this.ariaLabel && this.newElement.setAttribute('title', this.ariaLabel);
const attrs = this.element.attributes; const attrs = this.element.attributes;
for (let i = attrs.length - 1; i >= 0; i--) { for (let i = attrs.length - 1; i >= 0; i--) {

View File

@ -11,7 +11,7 @@
<core-loading [hideUntil]="loaded"> <core-loading [hideUntil]="loaded">
<!-- Section selector. --> <!-- Section selector. -->
<core-dynamic-component [component]="sectionSelectorComponent" [data]="data"> <core-dynamic-component [component]="sectionSelectorComponent" [data]="data">
<div text-wrap *ngIf="displaySectionSelector && sections && sections.length" padding class="clearfix" ion-row justify-content-between class="safe-padding-horizontal" [class.core-section-download]="downloadEnabled"> <div text-wrap *ngIf="displaySectionSelector && sections && sections.length" padding class="clearfix" ion-row justify-content-between class="safe-padding-horizontal core-button-selector-row" [class.core-section-download]="downloadEnabled">
<button float-start ion-button icon-start icon-end (click)="showSectionSelector($event)" color="light" class="core-button-select button-no-uppercase" ion-col [attr.aria-label]="('core.course.sections' | translate) + ': ' + (selectedSection && (selectedSection.formattedName || selectedSection.name))" aria-haspopup="true" [attr.aria-expanded]="sectionSelectorExpanded" aria-controls="core-course-section-selector" id="core-course-section-button"> <button float-start ion-button icon-start icon-end (click)="showSectionSelector($event)" color="light" class="core-button-select button-no-uppercase" ion-col [attr.aria-label]="('core.course.sections' | translate) + ': ' + (selectedSection && (selectedSection.formattedName || selectedSection.name))" aria-haspopup="true" [attr.aria-expanded]="sectionSelectorExpanded" aria-controls="core-course-section-selector" id="core-course-section-button">
<core-icon name="fa-folder"></core-icon> <core-icon name="fa-folder"></core-icon>
<span class="core-button-select-text">{{selectedSection && (selectedSection.formattedName || selectedSection.name) || 'core.course.sections' | translate }}</span> <span class="core-button-select-text">{{selectedSection && (selectedSection.formattedName || selectedSection.name) || 'core.course.sections' | translate }}</span>

View File

@ -64,6 +64,10 @@ ion-app.app-root core-course-format {
@include padding(null, 0, null, null); @include padding(null, 0, null, null);
} }
.core-button-selector-row {
@include safe-area-padding-start($content-padding !important, $content-padding);
}
.core-course-section-nav-buttons { .core-course-section-nav-buttons {
.button-inner core-format-text { .button-inner core-format-text {
white-space: nowrap; white-space: nowrap;

View File

@ -88,7 +88,7 @@ export class ZipMock extends Zip {
const destParent = destination.substring(0, source.lastIndexOf('/')), const destParent = destination.substring(0, source.lastIndexOf('/')),
destFolderName = destination.substr(source.lastIndexOf('/') + 1); destFolderName = destination.substr(source.lastIndexOf('/') + 1);
return this.file.createDir(destParent, destFolderName, false); return this.file.createDir(destParent, destFolderName, true);
}).then(() => { }).then(() => {
const promises = [], const promises = [],

View File

@ -1017,7 +1017,7 @@ export class CoreFileProvider {
return this.zip.unzip(fileEntry.toURL(), destFolder, onProgress); return this.zip.unzip(fileEntry.toURL(), destFolder, onProgress);
}).then((result) => { }).then((result) => {
if (result == -1) { if (result == -1) {
return Promise.reject(null); return Promise.reject('Unzip failed.');
} }
}); });
} }

View File

@ -3,8 +3,8 @@ $core-dark-text-secondary-color: $gray-light !default;
$core-dark-link-color: $blue-light !default; $core-dark-link-color: $blue-light !default;
$core-dark-item-bg-color: $gray-darker !default; $core-dark-item-bg-color: $gray-darker !default;
$core-dark-item-divider-bg-color: $black !default; $core-dark-item-divider-bg-color: $gray-dark !default;
$core-dark-background-color: $gray-dark !default; $core-dark-background-color: $black !default;
// Login. // Login.
$core-dark-login-page-background-color: radial-gradient(white, $gray-dark) !default; $core-dark-login-page-background-color: radial-gradient(white, $gray-dark) !default;
@ -31,7 +31,8 @@ ion-app.app-root .ion-page {
.item, .item,
.item-select, .item-select,
ion-card, ion-card,
.card-header { .card-header,
.card-content {
color: $core-dark-text-color; color: $core-dark-text-color;
background-color: $core-dark-item-bg-color; background-color: $core-dark-item-bg-color;