Merge pull request #2824 from crazyserver/MOBILE-3320

Mobile 3320
main
Dani Palou 2021-06-11 08:13:43 +02:00 committed by GitHub
commit 7aae777e89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 75 additions and 44 deletions

View File

@ -79,7 +79,7 @@
<!-- Subquestion -->
<ion-radio-group [(ngModel)]="answers[question.name]" [required]="question.required" [name]="question.name">
<ion-row *ngIf="question.parent !== 0" class="ion-align-items-center ion-padding" [class.even]="isEven">
<ion-row *ngIf="question.parent !== 0" class="ion-align-items-center ion-padding-horizontal" [class.even]="isEven">
<ion-col size="7">
<ion-label id="addon-mod_survey-{{question.id}}">
@ -91,9 +91,10 @@
<!-- Tablet view: radio buttons -->
<ion-col class="ion-hide-md-down ion-text-center" size="1"
*ngFor="let option of question.optionsArray; let value=index;">
*ngFor="let option of question.optionsArray; let value=index;"
>
<!-- Empty slot to avoid errors on migration tslint checks -->
<ion-radio [value]="value + 1" [attr.aria-labelledby]="'addon-mod_survey-'+question.id" slot="">
<ion-radio [value]="value + 1" [attr.aria-label]="question.num + '. '+question.text + ': ' + option">
</ion-radio>
</ion-col>
<ion-col class="ion-hide-md-up" size="5">

View File

@ -17,6 +17,12 @@
.even {
background-color: var(--even-background);
}
ion-radio {
height: var(--a11y-min-target-size);
width: var(--a11y-min-target-size);
padding: 12px;
}
}
:host-context(body.dark) {

View File

@ -1,4 +1,4 @@
<div *ngIf="ddQuestion && (ddQuestion.text || ddQuestion.text === '')" class="addon-qtype-ddwtos-container">
<div *ngIf="ddQuestion && (ddQuestion.text || ddQuestion.text === '')">
<!-- Content is outside the core-loading to let the script calculate drag items position -->
<core-loading [hideUntil]="ddQuestion.loaded"></core-loading>
@ -10,16 +10,18 @@
<ion-label>{{ 'core.question.howtodraganddrop' | translate }}</ion-label>
</ion-item>
</ion-card>
<core-format-text [component]="component" [componentId]="componentId" [text]="ddQuestion.text"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId" #questiontext
(afterRender)="textRendered()">
</core-format-text>
<div class="addon-qtype-ddwtos-container">
<core-format-text [component]="component" [componentId]="componentId" [text]="ddQuestion.text"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId" #questiontext
(afterRender)="textRendered()">
</core-format-text>
<core-format-text *ngIf="ddQuestion.answers" [component]="component" [componentId]="componentId"
[text]="ddQuestion.answers" [filter]="false" (afterRender)="answersRendered()">
</core-format-text>
<core-format-text *ngIf="ddQuestion.answers" [component]="component" [componentId]="componentId"
[text]="ddQuestion.answers" [filter]="false" (afterRender)="answersRendered()">
</core-format-text>
<div class="drags"></div>
<div class="drags"></div>
</div>
</ion-label>
</ion-item>
</div>

View File

@ -3,6 +3,7 @@
// Style ddwtos content a bit. Almost all these styles are copied from Moodle.
.addon-qtype-ddwtos-container {
min-height: 80px; // To display the loading.
position: relative;
}
core-format-text ::ng-deep, .drags ::ng-deep {

View File

@ -61,7 +61,6 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
numTabsShown = 0;
direction = 'ltr';
description = '';
lastScroll = 0;
slidesOpts = {
initialSlide: 0,
slidesPerView: 3,
@ -89,6 +88,8 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
protected slidesSwiper: any; // eslint-disable-line @typescript-eslint/no-explicit-any
protected slidesSwiperLoaded = false;
protected scrollElements: Record<string | number, HTMLElement> = {}; // Scroll elements for each loaded tab.
protected lastScroll = 0;
protected previousLastScroll = 0;
tabAction: CoreTabsRoleTab<T>;
@ -164,6 +165,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
this.tabBarElement!.classList.remove('tabs-hidden');
if (scroll === 0) {
this.tabBarElement!.style.height = '';
this.previousLastScroll = this.lastScroll;
this.lastScroll = 0;
} else if (scroll !== undefined) {
this.tabBarElement!.style.height = (this.tabBarHeight - scroll) + 'px';
@ -253,17 +255,13 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
return;
}
if (!this.tabsShown) {
if (window.innerHeight >= CoreTabsBaseComponent.MAX_HEIGHT_TO_HIDE_TABS) {
// Ensure tabbar is shown.
this.tabsShown = true;
this.tabBarElement?.classList.remove('tabs-hidden');
this.lastScroll = 0;
this.calculateTabBarHeight();
} else {
// Don't recalculate.
return;
}
if (window.innerHeight >= CoreTabsBaseComponent.MAX_HEIGHT_TO_HIDE_TABS) {
// Ensure tabbar is shown.
this.applyScroll(true, 0);
this.calculateTabBarHeight();
} else if (!this.tabsShown) {
// Don't recalculate.
return;
}
await this.calculateMaxSlides();
@ -504,7 +502,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
return;
}
if (scrollTop == this.lastScroll) {
if (scrollTop == this.lastScroll || scrollTop == this.previousLastScroll) {
// Ensure scroll has been modified to avoid flicks.
return;
}
@ -522,6 +520,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
}
// Use lastScroll after moving the tabs to avoid flickering.
this.previousLastScroll = this.lastScroll;
this.lastScroll = scrollTop;
}

View File

@ -2,7 +2,8 @@
<ion-spinner color="primary"></ion-spinner>
<p class="core-loading-message" *ngIf="message" role="status">{{message}}</p>
</div>
<div #content class="core-loading-content" [id]="uniqueId" [attr.aria-busy]="hideUntil" [@coreShowHideAnimation]>
<ng-content *ngIf="hideUntil">
<div #content class="core-loading-content" [id]="uniqueId" [attr.aria-busy]="!hideUntil" [@coreShowHideAnimation]
[class.opacity-hide]="!hideUntil">
<ng-content *ngIf="loaded">
</ng-content>
</div>

View File

@ -43,6 +43,10 @@
flex-direction: column;
}
.core-loading-content {
@include core-transition(opacity, 200ms);
}
.core-loading-message {
@include margin(10px, 0, 0, 0);
}

View File

@ -55,6 +55,7 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit {
uniqueId: string;
protected element: HTMLElement; // Current element.
loaded = false; // Only comes true once.
constructor(element: ElementRef) {
this.element = element.nativeElement;
@ -83,6 +84,7 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit {
if (this.hideUntil) {
this.element.classList.add('core-loading-loaded');
}
this.loaded = !!this.hideUntil;
this.content?.nativeElement.classList.toggle('core-loading-content', !!this.hideUntil);
}
@ -94,6 +96,10 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit {
*/
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
if (changes.hideUntil) {
if (!this.loaded) {
this.loaded = !!this.hideUntil; // Only comes true once.
}
if (this.hideUntil) {
setTimeout(() => {
// Content is loaded so, center the spinner on the content itself.

View File

@ -34,7 +34,7 @@
<span class="sr-only">{{ 'core.login.sitebadgedescription' | translate:{ count: site.badge } }}</span>
</ion-badge>
<ion-button *ngIf="showDelete" slot="end" fill="clear" color="danger" (click)="deleteSite($event, site)"
[attr.aria-label]="'core.delete' | translate">
[attr.aria-label]="'core.delete' | translate" [@coreSlideInOut]="'fromRight'">
<ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button>
</ion-item>

View File

@ -22,6 +22,7 @@ import { CoreLoginHelper } from '@features/login/services/login-helper';
import { CoreNavigator } from '@services/navigator';
import { CorePushNotifications } from '@features/pushnotifications/services/pushnotifications';
import { CoreFilter } from '@features/filter/services/filter';
import { CoreAnimations } from '@components/animations';
/**
* Page that displays a "splash screen" while the app is being initialized.
@ -29,6 +30,7 @@ import { CoreFilter } from '@features/filter/services/filter';
@Component({
selector: 'page-core-login-sites',
templateUrl: 'sites.html',
animations: [CoreAnimations.SLIDE_IN_OUT],
})
export class CoreLoginSitesPage implements OnInit {

View File

@ -63,8 +63,11 @@ export class CoreSettingsHelperProvider {
protected syncPromises: { [s: string]: Promise<void> } = {};
protected prefersDark?: MediaQueryList;
protected colorSchemes: CoreColorScheme[] = [];
protected currentColorScheme = CoreColorScheme.LIGHT;
constructor() {
this.prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
if (!CoreConstants.CONFIG.forceColorScheme) {
// Update color scheme when a user enters or leaves a site, or when the site info is updated.
const applySiteScheme = (): void => {
@ -72,7 +75,6 @@ export class CoreSettingsHelperProvider {
// Dark mode is disabled, force light mode.
this.setColorScheme(CoreColorScheme.LIGHT);
} else {
this.prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
// Reset color scheme settings.
this.initColorScheme();
}
@ -86,7 +88,12 @@ export class CoreSettingsHelperProvider {
// Reset color scheme settings.
this.initColorScheme();
});
} else {
this.initColorScheme();
}
// Listen for changes to the prefers-color-scheme media query.
this.prefersDark.addEventListener && this.prefersDark.addEventListener('change', this.toggleDarkModeListener.bind(this));
}
/**
@ -432,17 +439,10 @@ export class CoreSettingsHelperProvider {
* @param colorScheme Name of the color scheme.
*/
setColorScheme(colorScheme: CoreColorScheme): void {
this.currentColorScheme = colorScheme;
if (colorScheme == CoreColorScheme.SYSTEM && this.prefersDark) {
// Listen for changes to the prefers-color-scheme media query.
this.prefersDark.addEventListener &&
this.prefersDark.addEventListener('change', this.toggleDarkModeListener);
this.toggleDarkMode(this.prefersDark.matches);
} else {
// Stop listening to changes.
this.prefersDark?.removeEventListener &&
this.prefersDark?.removeEventListener('change', this.toggleDarkModeListener);
this.toggleDarkMode(colorScheme == CoreColorScheme.DARK);
}
}
@ -460,11 +460,9 @@ export class CoreSettingsHelperProvider {
/**
* Listener function to toggle dark mode.
*
* @param e Event object.
*/
protected toggleDarkModeListener = (e: MediaQueryListEvent): void => {
document.body.classList.toggle('dark', e.matches);
protected toggleDarkModeListener(): void {
this.setColorScheme(this.currentColorScheme);
};
/**

View File

@ -654,10 +654,17 @@ export class CoreAppProvider {
const useLightText = CoreColors.isWhiteContrastingBetter(color);
const statusBar = StatusBar.instance;
statusBar.backgroundColorByHexString(color);
useLightText ? statusBar.styleLightContent() : statusBar.styleDefault();
this.isIOS() && statusBar.overlaysWebView(false);
// styleDefault will use white text on iOS when darkmode is on. Force the background to black.
if (this.isIOS() && !useLightText && window.matchMedia('(prefers-color-scheme: dark)').matches) {
statusBar.backgroundColorByHexString('#000000');
statusBar.styleLightContent();
} else {
statusBar.backgroundColorByHexString(color);
useLightText ? statusBar.styleLightContent() : statusBar.styleDefault();
}
}
/**

View File

@ -180,6 +180,11 @@ core-format-text {
ion-icon {
flex: 1;
align-self: center;
/** Fix iOS icon size */
margin: 0 auto;
position: absolute;
left: 0;
right: 0;
}
&:hover {
@ -338,7 +343,6 @@ core-rich-text-editor .core-rte-editor {
select,
input:not([type=checkbox]):not([type=radio]):not([type=hidden]) {
height: 30px;
line-height: 30px;
display: inline-block;
border: 1px solid var(--gray-dark);
background: var(--background-contrast);