Merge pull request #3066 from crazyserver/MOBILE-3814

Mobile 3814
main
Dani Palou 2022-01-24 09:30:30 +01:00 committed by GitHub
commit 5a2016cb67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 98 additions and 34 deletions

View File

@ -1515,7 +1515,6 @@
"core.course.confirmdownloadzerosize": "local_moodlemobileapp", "core.course.confirmdownloadzerosize": "local_moodlemobileapp",
"core.course.confirmlimiteddownload": "local_moodlemobileapp", "core.course.confirmlimiteddownload": "local_moodlemobileapp",
"core.course.confirmpartialdownloadsize": "local_moodlemobileapp", "core.course.confirmpartialdownloadsize": "local_moodlemobileapp",
"core.course.contents": "local_moodlemobileapp",
"core.course.couldnotloadsectioncontent": "local_moodlemobileapp", "core.course.couldnotloadsectioncontent": "local_moodlemobileapp",
"core.course.couldnotloadsections": "local_moodlemobileapp", "core.course.couldnotloadsections": "local_moodlemobileapp",
"core.course.coursesummary": "moodle", "core.course.coursesummary": "moodle",
@ -2274,7 +2273,6 @@
"core.updaterequireddesc": "local_moodlemobileapp", "core.updaterequireddesc": "local_moodlemobileapp",
"core.upgraderunning": "error", "core.upgraderunning": "error",
"core.user": "moodle", "core.user": "moodle",
"core.user.account": "local_moodlemobileapp",
"core.user.address": "moodle", "core.user.address": "moodle",
"core.user.city": "moodle", "core.user.city": "moodle",
"core.user.contact": "local_moodlemobileapp", "core.user.contact": "local_moodlemobileapp",
@ -2300,6 +2298,7 @@
"core.user.sendemail": "local_moodlemobileapp", "core.user.sendemail": "local_moodlemobileapp",
"core.user.student": "moodle/defaultcoursestudent", "core.user.student": "moodle/defaultcoursestudent",
"core.user.teacher": "moodle/noneditingteacher", "core.user.teacher": "moodle/noneditingteacher",
"core.user.useraccount": "moodle",
"core.user.userwithid": "local_moodlemobileapp", "core.user.userwithid": "local_moodlemobileapp",
"core.user.webpage": "moodle", "core.user.webpage": "moodle",
"core.userdeleted": "moodle", "core.userdeleted": "moodle",

View File

@ -26,7 +26,6 @@
"confirmdownloadzerosize": "You are about to start downloading.{{availableSpace}} Are you sure you want to continue?", "confirmdownloadzerosize": "You are about to start downloading.{{availableSpace}} Are you sure you want to continue?",
"confirmpartialdownloadsize": "You are about to download <strong>at least</strong> {{size}}.{{availableSpace}} Are you sure you want to continue?", "confirmpartialdownloadsize": "You are about to download <strong>at least</strong> {{size}}.{{availableSpace}} Are you sure you want to continue?",
"confirmlimiteddownload": "You are not currently connected to Wi-Fi. ", "confirmlimiteddownload": "You are not currently connected to Wi-Fi. ",
"contents": "Contents",
"gotonextactivity": "Continue to next activity", "gotonextactivity": "Continue to next activity",
"gotonextactivitynotfound": "Next activity not found. It's possible that it has been hidden or deleted.", "gotonextactivitynotfound": "Next activity not found. It's possible that it has been hidden or deleted.",
"gotopreviousactivity": "Continue to previous activity", "gotopreviousactivity": "Continue to previous activity",

View File

@ -385,7 +385,7 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy {
openCourseSummary(): void { openCourseSummary(): void {
CoreNavigator.navigateToSitePath( CoreNavigator.navigateToSitePath(
'/course/' + this.course.id + '/preview', '/course/' + this.course.id + '/preview',
{ params: { course: this.course, avoidOpenCourse: true } }, { params: { course: this.course } },
); );
} }

View File

@ -51,7 +51,7 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy {
protected isGuest?: boolean; protected isGuest?: boolean;
protected contentsTab: CoreTabsOutletTab = { protected contentsTab: CoreTabsOutletTab = {
page: CONTENTS_PAGE_NAME, page: CONTENTS_PAGE_NAME,
title: 'core.course.contents', title: 'core.course',
pageParams: {}, pageParams: {},
}; };

View File

@ -21,8 +21,8 @@
</div> </div>
</div> </div>
<div class="core-course-thumb-parallax-content" *ngIf="course"> <div class="core-course-thumb-parallax-content" *ngIf="course">
<ion-item class="ion-text-wrap" (click)="openCourse()" [attr.aria-label]="course.fullname" <ion-item class="ion-text-wrap" (click)="openCourse()" [attr.aria-label]="course.fullname" [detail]="canAccessCourse"
[detail]="!avoidOpenCourse && canAccessCourse" [button]="!avoidOpenCourse && canAccessCourse"> [button]="canAccessCourse">
<ion-icon name="fas-graduation-cap" fixed-width slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-graduation-cap" fixed-width slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<h2> <h2>
@ -121,11 +121,10 @@
<h2 *ngIf="prefetchCourseData.status == statusDownloaded">{{ 'core.course.refreshcourse' | translate }}</h2> <h2 *ngIf="prefetchCourseData.status == statusDownloaded">{{ 'core.course.refreshcourse' | translate }}</h2>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item button (click)="openCourse()" [attr.aria-label]="course.fullname" *ngIf="!avoidOpenCourse && canAccessCourse" <ion-item button (click)="openCourse()" [attr.aria-label]="course.fullname" *ngIf="canAccessCourse" detail="true">
detail="true">
<ion-icon name="fas-briefcase" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-briefcase" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<h2>{{ 'core.course.contents' | translate }}</h2> <h2>{{ 'core.course' | translate }}</h2>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item [href]="courseUrl" core-link [attr.aria-label]="course.fullname" button detail="false" [showBrowserWarning]="false"> <ion-item [href]="courseUrl" core-link [attr.aria-label]="course.fullname" button detail="false" [showBrowserWarning]="false">

View File

@ -51,7 +51,6 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
selfEnrolInstances: CoreCourseEnrolmentMethod[] = []; selfEnrolInstances: CoreCourseEnrolmentMethod[] = [];
paypalEnabled = false; paypalEnabled = false;
dataLoaded = false; dataLoaded = false;
avoidOpenCourse = false;
prefetchCourseData: CorePrefetchStatusInfo = { prefetchCourseData: CorePrefetchStatusInfo = {
icon: '', icon: '',
statusTranslatable: 'core.loading', statusTranslatable: 'core.loading',
@ -97,7 +96,6 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
*/ */
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {
this.course = CoreNavigator.getRouteParam('course'); this.course = CoreNavigator.getRouteParam('course');
this.avoidOpenCourse = !!CoreNavigator.getRouteBooleanParam('avoidOpenCourse');
if (!this.course) { if (!this.course) {
CoreNavigator.back(); CoreNavigator.back();
@ -238,8 +236,7 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
* Open the course. * Open the course.
*/ */
openCourse(): void { openCourse(): void {
if (!this.canAccessCourse || this.avoidOpenCourse) { if (!this.canAccessCourse) {
// Course cannot be opened or we are avoiding opening because we accessed from inside a course.
return; return;
} }

View File

@ -4,7 +4,10 @@
<ion-back-button [text]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<h1>{{ 'core.courses.mycourses' | translate }}</h1> <h1>
<core-format-text [text]="siteName" contextLevel="system" [contextInstanceId]="0"></core-format-text>
<img src="assets/img/top_logo.png" class="core-header-logo" [alt]="siteName">
</h1>
</ion-title> </ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button *ngIf="searchEnabled" (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate"> <ion-button *ngIf="searchEnabled" (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate">
@ -30,6 +33,9 @@
<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]="loaded"> <core-loading [hideUntil]="loaded">
<div class="ion-padding-horizontal">
<h2>{{ 'core.courses.mycourses' | translate }}</h2>
</div>
<ion-list> <ion-list>
<core-block *ngIf="loadedBlock?.visible" [block]="loadedBlock" contextLevel="user" [instanceId]="userId" <core-block *ngIf="loadedBlock?.visible" [block]="loadedBlock" contextLevel="user" [instanceId]="userId"
[extraData]="{'downloadEnabled': true}"></core-block> [extraData]="{'downloadEnabled': true}"></core-block>

View File

@ -36,6 +36,7 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy {
@ViewChild(CoreBlockComponent) block!: CoreBlockComponent; @ViewChild(CoreBlockComponent) block!: CoreBlockComponent;
siteName = '';
searchEnabled = false; searchEnabled = false;
downloadCoursesEnabled = false; downloadCoursesEnabled = false;
userId: number; userId: number;
@ -50,6 +51,8 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy {
this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => { this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
this.searchEnabled = !CoreCourses.isSearchCoursesDisabledInSite(); this.searchEnabled = !CoreCourses.isSearchCoursesDisabledInSite();
this.downloadCoursesEnabled = !CoreCourses.isDownloadCoursesDisabledInSite(); this.downloadCoursesEnabled = !CoreCourses.isDownloadCoursesDisabledInSite();
this.loadSiteName();
}, CoreSites.getCurrentSiteId()); }, CoreSites.getCurrentSiteId());
this.userId = CoreSites.getCurrentSiteUserId(); this.userId = CoreSites.getCurrentSiteUserId();
@ -62,8 +65,9 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy {
this.searchEnabled = !CoreCourses.isSearchCoursesDisabledInSite(); this.searchEnabled = !CoreCourses.isSearchCoursesDisabledInSite();
this.downloadCoursesEnabled = !CoreCourses.isDownloadCoursesDisabledInSite(); this.downloadCoursesEnabled = !CoreCourses.isDownloadCoursesDisabledInSite();
this.loadContent(); this.loadSiteName();
this.loadContent();
} }
/** /**
@ -97,6 +101,13 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy {
this.loaded = true; this.loaded = true;
} }
/**
* Load the site name.
*/
protected loadSiteName(): void {
this.siteName = CoreSites.getRequiredCurrentSite().getSiteName() || '';
}
/** /**
* Load fallback blocks. * Load fallback blocks.
*/ */

View File

@ -1,3 +1,3 @@
<core-user-avatar *ngIf="isMainScreen && siteInfo" [user]="siteInfo" class="core-bar-button-image clickable" [linkProfile]="false" <core-user-avatar *ngIf="isMainScreen && siteInfo" [user]="siteInfo" class="core-bar-button-image clickable" [linkProfile]="false"
(ariaButtonClick)="openUserMenu($event)" role="button" tabindex="0" [attr.aria-label]="'core.user.account' | translate"> (ariaButtonClick)="openUserMenu($event)" role="button" tabindex="0" [attr.aria-label]="'core.user.useraccount' | translate">
</core-user-avatar> </core-user-avatar>

View File

@ -2,7 +2,7 @@
<ion-toolbar> <ion-toolbar>
<ion-title> <ion-title>
<h2> <h2>
{{'core.user.account' | translate}} {{'core.user.useraccount' | translate}}
</h2> </h2>
</ion-title> </ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
@ -17,6 +17,9 @@
<ion-item button class="core-usermenu-siteinfo ion-text-wrap" *ngIf="siteInfo" lines="full" detail="false" [href]="siteUrl" <ion-item button class="core-usermenu-siteinfo ion-text-wrap" *ngIf="siteInfo" lines="full" detail="false" [href]="siteUrl"
core-link auto-login="yes"> core-link auto-login="yes">
<ion-label> <ion-label>
<!-- Show site logo. -->
<img class="core-usermenu-site-logo" *ngIf="siteLogo && siteLogoLoaded" [src]="siteLogo" role="presentation" alt=""
onError="this.class='image-not-found'">
<p class="core-usermenu-sitename"> <p class="core-usermenu-sitename">
<core-format-text [text]="siteName" contextLevel="system" [contextInstanceId]="0" [wsNotFiltered]="true"> <core-format-text [text]="siteName" contextLevel="system" [contextInstanceId]="0" [wsNotFiltered]="true">
</core-format-text> </core-format-text>

View File

@ -8,6 +8,10 @@
} }
.core-usermenu-siteinfo { .core-usermenu-siteinfo {
text-align: center;
ion-label {
margin: 0;
}
--padding-top: 10px; --padding-top: 10px;
--padding-bottom: 10px; --padding-bottom: 10px;
} }
@ -19,9 +23,21 @@
} }
.core-usermenu-sitename { .core-usermenu-sitename {
font-size: 16px; font-weight: bold;
font-size: 20px;
line-height: 24px;
} }
img.core-usermenu-site-logo {
margin-bottom: 8px;
max-height: var(--core-user-menu-site-logo-max-height);
}
img.image-not-found {
display: none;
}
@if ($core-user-hide-sitename) { @if ($core-user-hide-sitename) {
.core-usermenu-sitename { .core-usermenu-sitename {
display: none; display: none;

View File

@ -12,8 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { CoreConstants } from '@/core/constants';
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Component, OnDestroy, OnInit } from '@angular/core';
import { CoreSiteInfo } from '@classes/site'; import { CoreSite, CoreSiteInfo } from '@classes/site';
import { CoreLoginSitesComponent } from '@features/login/components/sites/sites'; import { CoreLoginSitesComponent } from '@features/login/components/sites/sites';
import { CoreLoginHelper } from '@features/login/services/login-helper'; import { CoreLoginHelper } from '@features/login/services/login-helper';
import { CoreUser, CoreUserProfile } from '@features/user/services/user'; import { CoreUser, CoreUserProfile } from '@features/user/services/user';
@ -36,12 +37,13 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
siteInfo?: CoreSiteInfo; siteInfo?: CoreSiteInfo;
siteName?: string; siteName?: string;
siteLogo?: string;
siteLogoLoaded = false;
siteUrl?: string; siteUrl?: string;
handlers: CoreUserProfileHandlerData[] = []; handlers: CoreUserProfileHandlerData[] = [];
handlersLoaded = false; handlersLoaded = false;
loaded = false; loaded = false;
user?: CoreUserProfile; user?: CoreUserProfile;
moreSites = false;
protected subscription!: Subscription; protected subscription!: Subscription;
@ -49,10 +51,6 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
* @inheritdoc * @inheritdoc
*/ */
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {
// Check if there are more sites to switch.
const sites = await CoreSites.getSites();
this.moreSites = sites.length > 1;
const currentSite = CoreSites.getRequiredCurrentSite(); const currentSite = CoreSites.getRequiredCurrentSite();
this.siteInfo = currentSite.getInfo(); this.siteInfo = currentSite.getInfo();
this.siteName = currentSite.getSiteName(); this.siteName = currentSite.getSiteName();
@ -60,6 +58,8 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
this.loaded = true; this.loaded = true;
this.loadSiteLogo(currentSite);
// Load the handlers. // Load the handlers.
if (this.siteInfo) { if (this.siteInfo) {
this.user = await CoreUser.getProfile(this.siteInfo.userid); this.user = await CoreUser.getProfile(this.siteInfo.userid);
@ -82,6 +82,31 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
} }
} }
/**
* Load site logo from current site public config.
*
* @param currentSite Current site object.
* @return Promise resolved when done.
*/
protected async loadSiteLogo(currentSite: CoreSite): Promise<void> {
if (CoreConstants.CONFIG.forceLoginLogo) {
this.siteLogo = 'assets/img/login_logo.png';
this.siteLogoLoaded = true;
return;
}
try {
const siteConfig = await currentSite.getPublicConfig();
this.siteLogo = CoreLoginHelper.getLogoUrl(siteConfig);
} catch {
// Ignore errors.
} finally {
this.siteLogoLoaded = true;
}
}
/** /**
* Opens User profile page. * Opens User profile page.
* *

View File

@ -55,7 +55,7 @@ export class CoreMainMenuHomePage implements OnInit {
} }
/** /**
* Initialize the component. * @inheritdoc
*/ */
ngOnInit(): void { ngOnInit(): void {
this.route.queryParams.subscribe((params: Partial<CoreRedirectPayload> & { urlToOpen?: string }) => { this.route.queryParams.subscribe((params: Partial<CoreRedirectPayload> & { urlToOpen?: string }) => {
@ -121,7 +121,7 @@ export class CoreMainMenuHomePage implements OnInit {
* Load the site name. * Load the site name.
*/ */
protected loadSiteName(): void { protected loadSiteName(): void {
this.siteName = CoreSites.getCurrentSite()?.getSiteName() || ''; this.siteName = CoreSites.getRequiredCurrentSite().getSiteName() || '';
} }
/** /**

View File

@ -13,12 +13,6 @@
<ion-content> <ion-content>
<ion-list> <ion-list>
<ion-item button class="ion-text-wrap" detail="false" (click)="openPage('deviceinfo')">
<ion-icon name="fas-mobile" slot="start" aria-hidden="true"></ion-icon>
<ion-label>
<h2>{{ appName }} {{ versionName }}</h2>
</ion-label>
</ion-item>
<ion-item button class="ion-text-wrap" (click)="openPage('licenses')" detail="true"> <ion-item button class="ion-text-wrap" (click)="openPage('licenses')" detail="true">
<ion-icon name="far-copyright" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="far-copyright" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.settings.opensourcelicenses' | translate }}</ion-label> <ion-label>{{ 'core.settings.opensourcelicenses' | translate }}</ion-label>
@ -40,3 +34,12 @@
</ion-item> </ion-item>
</ion-list> </ion-list>
</ion-content> </ion-content>
<ion-footer class="ion-no-border">
<ion-item button class="ion-text-wrap ion-text-center core-about-deviceinfo" detail="false" (click)="openPage('deviceinfo')"
lines="none">
<ion-label>
<h2>{{ appName }} {{ versionName }}</h2>
</ion-label>
</ion-item>
</ion-footer>

View File

@ -0,0 +1,3 @@
.core-about-deviceinfo {
--background: transparent;
}

View File

@ -24,6 +24,7 @@ import { CoreNavigator } from '@services/navigator';
@Component({ @Component({
selector: 'page-core-app-settings-about', selector: 'page-core-app-settings-about',
templateUrl: 'about.html', templateUrl: 'about.html',
styleUrls: ['about.scss'],
}) })
export class CoreSettingsAboutPage { export class CoreSettingsAboutPage {

View File

@ -1,6 +1,6 @@
{ {
"address": "Address", "address": "Address",
"account": "Account", "useraccount": "User account",
"city": "City/town", "city": "City/town",
"contact": "Contact", "contact": "Contact",
"country": "Country", "country": "Country",

View File

@ -264,6 +264,8 @@
--core-course-module-navigation-max-height: 56px; --core-course-module-navigation-max-height: 56px;
--core-course-module-navigation-background: var(--contrast-background); --core-course-module-navigation-background: var(--contrast-background);
--core-user-menu-site-logo-max-height: 32px;
--addon-calendar-event-category-color: var(--purple); --addon-calendar-event-category-color: var(--purple);
--addon-calendar-event-course-color: var(--red); --addon-calendar-event-course-color: var(--red);
--addon-calendar-event-group-color: var(--yellow); --addon-calendar-event-group-color: var(--yellow);