Merge pull request #3203 from crazyserver/MOBILE-3833

Mobile 3833
main
Dani Palou 2022-03-24 12:03:33 +01:00 committed by GitHub
commit 042619dd61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 113 additions and 143 deletions

View File

@ -51,12 +51,18 @@ jobs:
apt:
packages:
- libsecret-1-dev
- php5-cli
- php5-common
- stage: build
name: "Build iOS"
language: node_js
if: env(BUILD_IOS) = 1 AND (env(DEPLOY) = 1 OR (env(DEPLOY) = 2 AND tag IS NOT blank))
os: osx
osx_image: xcode12.5
osx_image: xcode13.1
addons:
homebrew:
packages:
- jq
- stage: test
name: "End to end tests (mod_forum and mod_messages)"
services:

View File

@ -69,7 +69,7 @@
</ion-row>
<core-empty-box *ngIf="filteredCourses.length == 0" image="assets/img/icons/courses.svg"
[message]="'addon.block_myoverview.nocourses' | translate" inline="true">
[message]="'addon.block_myoverview.nocourses' | translate">
</core-empty-box>
<!-- List of courses. -->

View File

@ -8,7 +8,7 @@
</div>
</ion-item-divider>
<core-loading [hideUntil]="loaded" [fullscreen]="false">
<core-empty-box *ngIf="courses.length == 0" image="assets/img/icons/courses.svg" inline="true"
<core-empty-box *ngIf="courses.length == 0" image="assets/img/icons/courses.svg"
[message]="'addon.block_recentlyaccessedcourses.nocourses' | translate"></core-empty-box>
<!-- List of courses. -->
<div [hidden]="courses.length === 0" [id]="scrollElementId" class="core-horizontal-scroll"

View File

@ -37,7 +37,7 @@
</div>
</div>
<core-empty-box *ngIf="items.length <= 0" image="assets/img/icons/activities.svg" inline="true"
<core-empty-box *ngIf="items.length <= 0" image="assets/img/icons/activities.svg"
[message]="'addon.block_recentlyaccesseditems.noitems' | translate"></core-empty-box>
</core-loading>

View File

@ -8,7 +8,7 @@
</div>
</ion-item-divider>
<core-loading [hideUntil]="loaded" [fullscreen]="false">
<core-empty-box *ngIf="courses.length == 0" image="assets/img/icons/courses.svg" inline="true"
<core-empty-box *ngIf="courses.length == 0" image="assets/img/icons/courses.svg"
[message]="'addon.block_starredcourses.nocourses' | translate"></core-empty-box>
<!-- List of courses. -->
<div [hidden]="courses.length === 0" [id]="scrollElementId" class="core-horizontal-scroll"

View File

@ -79,5 +79,5 @@
<p>{{'addon.block_timeline.noevents' | translate}}</p>
</ion-label>
</ion-item>
<core-empty-box *ngIf="empty && !course" image="assets/img/icons/activities.svg" inline="true"
[message]="'addon.block_timeline.noevents' | translate"></core-empty-box>
<core-empty-box *ngIf="empty && !course" image="assets/img/icons/activities.svg" [message]="'addon.block_timeline.noevents' | translate">
</core-empty-box>

View File

@ -66,7 +66,7 @@
<addon-block-timeline-events [events]="course.events" [canLoadMore]="course.canLoadMore" (loadMore)="loadMore(course)"
[course]="course" [from]="dataFrom" [to]="dataTo"></addon-block-timeline-events>
</ng-container>
<core-empty-box *ngIf="timelineCourses.courses.length == 0" image="assets/img/icons/courses.svg" inline="true"
<core-empty-box *ngIf="timelineCourses.courses.length == 0" image="assets/img/icons/courses.svg"
[message]="'addon.block_timeline.noevents' | translate"></core-empty-box>
</core-loading>
</core-loading>

View File

@ -59,7 +59,7 @@
</ion-item>
</ion-card>
<core-empty-box *ngIf="!day.filteredEvents || !day.filteredEvents.length" icon="fas-calendar" inline="true"
<core-empty-box *ngIf="!day.filteredEvents || !day.filteredEvents.length" icon="fas-calendar"
[message]="'addon.calendar.noevents' | translate">
</core-empty-box>

View File

@ -52,7 +52,7 @@
</ion-item>
</ion-card>
<ion-card class="core-info-card" *ngIf="access && access.entrieslefttoview">>
<ion-card class="core-info-card" *ngIf="access && access.entrieslefttoview">
<ion-item>
<ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>
@ -61,7 +61,7 @@
</ion-item>
</ion-card>
<ion-card class="core-info-card" *ngIf="access && access.entrieslefttoadd">>
<ion-card class="core-info-card" *ngIf="access && access.entrieslefttoadd">
<ion-item>
<ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>

View File

@ -60,7 +60,7 @@
<core-format-text *ngIf="pageContent" [component]="component" [componentId]="componentId" [text]="pageContent"
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
</core-format-text>
<core-empty-box *ngIf="!pageContent" icon="fas-file-alt" [message]="'addon.mod_wiki.nocontent' | translate" inline="true">
<core-empty-box *ngIf="!pageContent" icon="fas-file-alt" [message]="'addon.mod_wiki.nocontent' | translate">
</core-empty-box>
</article>

View File

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { CoreDom } from '@singletons/dom';
import { CoreEventObserver } from '@singletons/events';
@ -365,7 +364,7 @@ export class AddonQtypeDdImageOrTextQuestion {
this.pollForImageLoad();
});
this.resizeListener = CoreDomUtils.onWindowResize(() => {
this.resizeListener = CoreDom.onWindowResize(() => {
this.repositionDragsForQuestion();
});
}

View File

@ -619,7 +619,7 @@ export class AddonQtypeDdMarkerQuestion {
this.pollForImageLoad();
});
this.resizeListener = CoreDomUtils.onWindowResize(() => {
this.resizeListener = CoreDom.onWindowResize(() => {
this.redrawDragsAndDrops();
});
}

View File

@ -13,7 +13,6 @@
// limitations under the License.
import { CoreFormatTextDirective } from '@directives/format-text';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreTextUtils } from '@services/utils/text';
import { CoreUtils } from '@services/utils/utils';
import { CoreComponentsRegistry } from '@singletons/components-registry';
@ -208,7 +207,7 @@ export class AddonQtypeDdwtosQuestion {
this.positionDragItems();
this.resizeListener = CoreDomUtils.onWindowResize(() => {
this.resizeListener = CoreDom.onWindowResize(() => {
this.positionDragItems();
});
}

View File

@ -33,7 +33,7 @@ import { Platform, Translate } from '@singletons';
import { CoreSettingsHelper } from '@features/settings/services/settings-helper';
import { CoreAriaRoleTab, CoreAriaRoleTabFindable } from './aria-role-tab';
import { CoreEventObserver } from '@singletons/events';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreDom } from '@singletons/dom';
/**
* Class to abstract some common code for tabs.
@ -135,7 +135,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
await this.initializeTabs();
}
this.resizeListener = CoreDomUtils.onWindowResize(() => {
this.resizeListener = CoreDom.onWindowResize(() => {
this.windowResized();
});
}

View File

@ -1,8 +1,4 @@
<div class="core-empty-box ion-padding" [class.core-empty-box-inline]="(!image && !icon) || inline">
<div class="core-empty-box-content">
<img *ngIf="image && !icon" [src]="image" role="presentation" alt="">
<ion-icon *ngIf="icon" [name]="icon" aria-hidden="true"></ion-icon>
<p *ngIf="message" [class.ion-padding-top]="image || icon">{{ message }}</p>
<ng-content></ng-content>
</div>
</div>
<img *ngIf="image && !icon" [src]="image" role="presentation" alt="">
<ion-icon *ngIf="icon" [name]="icon" aria-hidden="true"></ion-icon>
<p *ngIf="message">{{ message }}</p>
<ng-content></ng-content>

View File

@ -1,74 +1,35 @@
@import "~theme/globals";
:host {
display: contents;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex-grow: 1;
color: var(--text-color);
margin: 0 auto;
text-align: center;
padding: 16px;
--image-size: 120px;
.core-empty-box {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: table;
height: 100%;
width: 100%;
margin: 0;
clear: both;
pointer-events: none;
.core-empty-box-content {
margin: 0;
display: table-cell;
text-align: center;
vertical-align: middle;
pointer-events: auto;
}
&.core-empty-box-inline {
position: relative;
z-index: initial;
top: initial;
right: initial;
bottom: 0;
left: initial;
height: auto;
}
ion-icon {
font-size: 120px;
}
img {
height: 125px;
width: 145px;
margin: 0 auto;
}
p {
font-size: 120%;
}
ion-icon {
font-size: var(--image-size);
}
img {
height: var(--image-size);
}
p {
font-size: 120%;
}
&.core-empty-box-clickable .core-empty-box {
&.core-empty-box-clickable {
z-index: 0;
}
}
@media (max-height: 550px) {
.core-empty-box {
position: relative;
height: auto;
margin-top: 50px;
ion-icon {
font-size: 100px;
}
img {
height: 104px;
width: 121px;
}
}
}
&.core-empty-inline .core-empty-box {
position: relative;
z-index: initial;
height: auto;
@include media-breakpoint-down(sm) {
:host {
--image-size: 100px;
}
}

View File

@ -32,12 +32,11 @@ export class CoreEmptyBoxComponent {
@Input() message = ''; // Message to display.
@Input() icon?: string; // Name of the icon to use.
@Input() image?: string; // Image source. If an icon is provided, image won't be used.
/**
* If this has to be shown inline instead of occupying whole page.
* If image or icon is not supplied, it's true by default.
*/
@Input() inline = false;
@Input() flipIconRtl = false; // Whether to flip the icon in RTL. Defaults to false.
/**
* @deprecated not used anymore.
*/
@Input() inline = false;
}

View File

@ -10,7 +10,7 @@
--menu-display: flex;
--content-display: block;
--content-outlet-display: none;
--content-placeholder-display: var(--content-display);
--content-placeholder-display: flex;
top: 0;
right: 0;
@ -70,6 +70,7 @@
--menu-min-width: 0px;
--menu-max-width: 100%;
--content-display: none;
--content-placeholder-display: none;
--menu-border-width: 0px;
--menu-box-shadow: none;
--menu-z: 0px;

View File

@ -21,7 +21,6 @@ import { CoreComponentsRegistry } from '@singletons/components-registry';
import { CoreFormatTextDirective } from './format-text';
import { CoreEventObserver } from '@singletons/events';
import { CoreLoadingComponent } from '@components/loading/loading';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreCancellablePromise } from '@classes/cancellable-promise';
import { CoreDom } from '@singletons/dom';
@ -154,7 +153,7 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
}
});
this.resizeListener = CoreDomUtils.onWindowResize(() => {
this.resizeListener = CoreDom.onWindowResize(() => {
this.calculateHeight();
}, 50);
}

View File

@ -18,9 +18,9 @@ import { CoreLoadingComponent } from '@components/loading/loading';
import { CoreTabsOutletComponent } from '@components/tabs-outlet/tabs-outlet';
import { CoreSettingsHelper } from '@features/settings/services/settings-helper';
import { ScrollDetail } from '@ionic/core';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { CoreComponentsRegistry } from '@singletons/components-registry';
import { CoreDom } from '@singletons/dom';
import { CoreEventObserver } from '@singletons/events';
import { CoreMath } from '@singletons/math';
import { Subscription } from 'rxjs';
@ -156,7 +156,7 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
this.enteredPromise.reject(new Error('[collapsible-header] Waiting for ionViewDidEnter timeout reached'));
}, 5000);
this.resizeListener = CoreDomUtils.onWindowResize(() => {
this.resizeListener = CoreDom.onWindowResize(() => {
this.initializeFloatingTitle();
}, 50);

View File

@ -15,7 +15,6 @@
import { Directive, ElementRef, Input, OnDestroy, OnInit } from '@angular/core';
import { CoreCancellablePromise } from '@classes/cancellable-promise';
import { CoreLoadingComponent } from '@components/loading/loading';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { Translate } from '@singletons';
import { CoreComponentsRegistry } from '@singletons/components-registry';
@ -90,7 +89,7 @@ export class CoreCollapsibleItemDirective implements OnInit, OnDestroy {
await this.calculateHeight();
this.resizeListener = CoreDomUtils.onWindowResize(() => {
this.resizeListener = CoreDom.onWindowResize(() => {
this.calculateHeight();
}, 50);
}

View File

@ -254,7 +254,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
);
});
this.resizeListener = CoreDomUtils.onWindowResize(() => {
this.resizeListener = CoreDom.onWindowResize(() => {
this.windowResized();
}, 50);

View File

@ -29,7 +29,7 @@ import { filter } from 'rxjs/operators';
import { NavigationEnd } from '@angular/router';
import { trigger, state, style, transition, animate } from '@angular/animations';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreDom } from '@singletons/dom';
/**
* Page that displays the main menu of the app.
@ -122,7 +122,7 @@ export class CoreMainMenuPage implements OnInit, OnDestroy {
}
});
this.resizeListener = CoreDomUtils.onWindowResize(() => {
this.resizeListener = CoreDom.onWindowResize(() => {
this.initHandlers();
});
document.addEventListener('ionBackButton', this.backButtonFunction);

View File

@ -26,7 +26,7 @@ import { CoreContentLinksHelper } from '@features/contentlinks/services/contentl
import { CoreTextUtils } from '@services/utils/text';
import { Translate } from '@singletons';
import { CoreMainMenuDeepLinkManager } from '@features/mainmenu/classes/deep-link-manager';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreDom } from '@singletons/dom';
/**
* Page that displays the more page of the app.
@ -73,7 +73,7 @@ export class CoreMainMenuMorePage implements OnInit, OnDestroy {
this.initHandlers();
});
this.resizeListener = CoreDomUtils.onWindowResize(() => {
this.resizeListener = CoreDom.onWindowResize(() => {
this.initHandlers();
});

View File

@ -53,7 +53,6 @@ import { NavigationStart } from '@angular/router';
import { filter } from 'rxjs/operators';
import { Subscription } from 'rxjs';
import { CoreComponentsRegistry } from '@singletons/components-registry';
import { CoreEventObserver } from '@singletons/events';
import { CoreDom } from '@singletons/dom';
/*
@ -93,30 +92,6 @@ export class CoreDomUtilsProvider {
this.debugDisplay = debugDisplay != 0;
}
/**
* Window resize is widely checked and may have many performance issues, debouce usage is needed to avoid calling it too much.
* This function helps setting up the debounce feature and remove listener easily.
*
* @param resizeFunction Function to execute on resize.
* @param debounceDelay Debounce time in ms.
* @return Event observer to call off when finished.
*/
onWindowResize(resizeFunction: (ev?: Event) => void, debounceDelay = 20): CoreEventObserver {
const resizeListener = CoreUtils.debounce(async (ev?: Event) => {
await this.waitForResizeDone();
resizeFunction(ev);
}, debounceDelay);
window.addEventListener('resize', resizeListener);
return {
off: (): void => {
window.removeEventListener('resize', resizeListener);
},
};
}
/**
* Equivalent to element.closest(). If the browser doesn't support element.closest, it will
* traverse the parents to achieve the same functionality.
@ -1902,7 +1877,7 @@ export class CoreDomUtilsProvider {
/**
* Trigger form cancelled event.
*
* @param form Form element.
* @param formRef Form element.
* @param siteId The site affected. If not provided, no site affected.
* @deprecated since 3.9.5. Function has been moved to CoreForms.
*/
@ -1913,7 +1888,7 @@ export class CoreDomUtilsProvider {
/**
* Trigger form submitted event.
*
* @param form Form element.
* @param formRef Form element.
* @param online Whether the action was done in offline or not.
* @param siteId The site affected. If not provided, no site affected.
* @deprecated since 3.9.5. Function has been moved to CoreForms.
@ -1924,7 +1899,7 @@ export class CoreDomUtilsProvider {
/**
* In iOS the resize event is triggered before the window size changes. Wait for the size to change.
* Use of this function is discouraged. Please use onWindowResize to check window resize event.
* Use of this function is discouraged. Please use CoreDom.onWindowResize to check window resize event.
*
* @param windowWidth Initial window width.
* @param windowHeight Initial window height.

View File

@ -13,6 +13,9 @@
// limitations under the License.
import { CoreCancellablePromise } from '@classes/cancellable-promise';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { CoreEventObserver } from '@singletons/events';
/**
* Singleton with helper functions for dom.
@ -147,6 +150,30 @@ export class CoreDom {
slot.addEventListener('slotchange', slotListener);;
}
/**
* Window resize is widely checked and may have many performance issues, debouce usage is needed to avoid calling it too much.
* This function helps setting up the debounce feature and remove listener easily.
*
* @param resizeFunction Function to execute on resize.
* @param debounceDelay Debounce time in ms.
* @return Event observer to call off when finished.
*/
static onWindowResize(resizeFunction: (ev?: Event) => void, debounceDelay = 20): CoreEventObserver {
const resizeListener = CoreUtils.debounce(async (ev?: Event) => {
await CoreDomUtils.waitForResizeDone();
resizeFunction(ev);
}, debounceDelay);
window.addEventListener('resize', resizeListener);
return {
off: (): void => {
window.removeEventListener('resize', resizeListener);
},
};
}
/**
* Scroll to a certain element.
*

View File

@ -29,6 +29,8 @@
--core-header-toolbar-border-width: 0;
ion-toolbar {
--background: transparent;
--core-header-buttons-background: var(--ion-background-color);
--core-header-buttons-color: var(--text-color);
}
h1 {

View File

@ -152,9 +152,11 @@ ion-toolbar {
// Header.
ion-header {
z-index: 12; // To hide ion-slides on scroll.
--core-header-buttons-background: var(--core-header-toolbar-background);
ion-toolbar {
--core-header-buttons-background: var(--core-header-toolbar-background);
--core-header-buttons-color: var(--core-header-toolbar-color);
ion-spinner {
margin: 10px;
}
@ -164,11 +166,11 @@ ion-header {
.in-toolbar.button-solid,
.button.button-clear,
.button.button-solid {
--color: var(--core-header-toolbar-color);
--color: var(--core-header-buttons-color);
--background: var(--core-header-buttons-background);
--ion-toolbar-color: var(--core-header-toolbar-color);
--ion-toolbar-color: var(--core-header-buttons-color);
--border-radius: var(--huge-radius);
--primary: var(--core-header-toolbar-color);
--primary: var(--core-header-buttons-color);
}
ion-back-button::part(text) {
display: none;
@ -1490,7 +1492,11 @@ ion-header.no-title {
--core-header-toolbar-border-width: 0;
--core-header-toolbar-background: transparent;
--core-header-shadow: none !important;
--core-header-buttons-background: var(--ion-background-color);
ion-toolbar {
--core-header-buttons-background: var(--ion-background-color);
--core-header-buttons-color: var(--text-color);
}
}
// To make core-swipe-slides fill the remaining height.
@ -1514,7 +1520,8 @@ ion-header.no-title {
}
.has-spacer {
.has-spacer,
.core-flex-fill {
display: flex;
flex-direction: column;
min-height: 100%;