From 2af25ff8fda2de7494a8ba3751f448600d3911ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Tue, 6 Oct 2020 16:12:56 +0200 Subject: [PATCH 1/3] MOBILE-3565 settings: Settings pages --- src/app/app-routing.module.ts | 4 + src/app/components/icon/icon.scss | 14 +- src/app/components/icon/icon.ts | 2 + src/app/core/login/login.module.ts | 1 + src/app/core/login/pages/site/site.html | 4 +- src/app/core/login/pages/sites/sites.html | 6 +- src/app/core/settings/lang/en.json | 73 ++++++ src/app/core/settings/pages/about/about.html | 29 +++ .../core/settings/pages/about/about.page.ts | 55 +++++ src/app/core/settings/pages/app/app.html | 33 +++ src/app/core/settings/pages/app/app.page.ts | 65 +++++ .../settings/pages/deviceinfo/deviceinfo.html | 142 +++++++++++ .../pages/deviceinfo/deviceinfo.page.ts | 232 ++++++++++++++++++ .../settings/pages/deviceinfo/deviceinfo.scss | 4 + .../core/settings/settings-routing.module.ts | 45 ++++ src/app/core/settings/settings.module.ts | 46 ++++ src/app/lang/en.json | 11 + src/assets/lang/en.json | 82 ++++++- 18 files changed, 838 insertions(+), 10 deletions(-) create mode 100644 src/app/core/settings/lang/en.json create mode 100644 src/app/core/settings/pages/about/about.html create mode 100644 src/app/core/settings/pages/about/about.page.ts create mode 100644 src/app/core/settings/pages/app/app.html create mode 100644 src/app/core/settings/pages/app/app.page.ts create mode 100644 src/app/core/settings/pages/deviceinfo/deviceinfo.html create mode 100644 src/app/core/settings/pages/deviceinfo/deviceinfo.page.ts create mode 100644 src/app/core/settings/pages/deviceinfo/deviceinfo.scss create mode 100644 src/app/core/settings/settings-routing.module.ts create mode 100644 src/app/core/settings/settings.module.ts create mode 100644 src/app/lang/en.json diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 024498f24..52ae40f71 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -25,6 +25,10 @@ const routes: Routes = [ path: 'login', loadChildren: () => import('./core/login/login.module').then( m => m.CoreLoginModule), }, + { + path: 'settings', + loadChildren: () => import('./core/settings/settings.module').then( m => m.CoreAppSettingsPageModule), + }, ]; @NgModule({ diff --git a/src/app/components/icon/icon.scss b/src/app/components/icon/icon.scss index 0b3467edb..5c7d48d76 100644 --- a/src/app/components/icon/icon.scss +++ b/src/app/components/icon/icon.scss @@ -1,11 +1,11 @@ // TODO ionic 5 :host-context([dir=rtl]) ion-icon { - &.core-icon-dir-flip, - &.fa-caret-right, - &.ion-md-send, &.ion-ios-send { - -webkit-transform: scale(-1, 1); - transform: scale(-1, 1); - } + &.core-icon-dir-flip, + &.fa-caret-right, + &.ion-md-send, &.ion-ios-send { + -webkit-transform: scale(-1, 1); + transform: scale(-1, 1); + } } // Slash @@ -19,6 +19,8 @@ :host { &.fa { font-size: 24px; + contain: none; + text-align: center; } // Center font awesome icons diff --git a/src/app/components/icon/icon.ts b/src/app/components/icon/icon.ts index 830ed8375..42d1176ca 100644 --- a/src/app/components/icon/icon.ts +++ b/src/app/components/icon/icon.ts @@ -71,6 +71,8 @@ export class CoreIconComponent implements OnChanges, OnDestroy { if (this.fixedWidth) { this.newElement.classList.add('fa-fw'); } + } else { + this.newElement.setAttribute('name', this.name); } !this.label && this.newElement.setAttribute('aria-hidden', 'true'); diff --git a/src/app/core/login/login.module.ts b/src/app/core/login/login.module.ts index 89a65c544..3a102970b 100644 --- a/src/app/core/login/login.module.ts +++ b/src/app/core/login/login.module.ts @@ -34,6 +34,7 @@ import { CoreLoginHelperProvider } from './services/helper'; CommonModule, IonicModule, CoreLoginRoutingModule, + CoreComponentsModule, TranslateModule.forChild(), FormsModule, ReactiveFormsModule, diff --git a/src/app/core/login/pages/site/site.html b/src/app/core/login/pages/site/site.html index 811b44a34..40f5a58b9 100644 --- a/src/app/core/login/pages/site/site.html +++ b/src/app/core/login/pages/site/site.html @@ -7,7 +7,9 @@ {{ 'core.login.connecttomoodle' | translate }} - + + + diff --git a/src/app/core/login/pages/sites/sites.html b/src/app/core/login/pages/sites/sites.html index be0a4b1b5..45c01774c 100644 --- a/src/app/core/login/pages/sites/sites.html +++ b/src/app/core/login/pages/sites/sites.html @@ -7,9 +7,11 @@ {{ 'core.settings.sites' | translate }} - - + + + + diff --git a/src/app/core/settings/lang/en.json b/src/app/core/settings/lang/en.json new file mode 100644 index 000000000..96673bccc --- /dev/null +++ b/src/app/core/settings/lang/en.json @@ -0,0 +1,73 @@ +{ + "about": "About", + "appsettings": "App settings", + "appversion": "App version", + "cannotsyncloggedout": "This site cannot be synchronised because you've logged out. Please try again when you're logged in the site again.", + "cannotsyncoffline": "Cannot synchronise offline.", + "cannotsyncwithoutwifi": "Cannot synchronise because the current settings only allow to synchronise when connected to Wi-Fi. Please connect to a Wi-Fi network.", + "colorscheme": "Color Scheme", + "colorscheme-auto": "Auto (based on system settings)", + "colorscheme-dark": "Dark", + "colorscheme-light": "Light", + "compilationinfo": "Compilation info", + "copyinfo": "Copy device info on the clipboard", + "cordovadevicemodel": "Cordova device model", + "cordovadeviceosversion": "Cordova device OS version", + "cordovadeviceplatform": "Cordova device platform", + "cordovadeviceuuid": "Cordova device UUID", + "cordovaversion": "Cordova version", + "currentlanguage": "Current language", + "debugdisplay": "Display debug messages", + "debugdisplaydescription": "If enabled, error modals will display more data about the error if possible.", + "deletesitefiles": "Are you sure that you want to delete the downloaded files and cached data from the site '{{sitename}}'? You won't be able to use the app in offline mode.", + "deletesitefilestitle": "Delete site files", + "deviceinfo": "Device info", + "deviceos": "Device OS", + "disableall": "Disable notifications", + "disabled": "Disabled", + "displayformat": "Display format", + "enabledownloadsection": "Enable download sections", + "enablefirebaseanalytics": "Enable Firebase analytics", + "enablefirebaseanalyticsdescription": "If enabled, the app will collect anonymous data usage.", + "enablerichtexteditor": "Enable text editor", + "enablerichtexteditordescription": "If enabled, a text editor will be available when entering content.", + "enablesyncwifi": "Allow sync only when on Wi-Fi", + "entriesincache": "{{$a}} entries in cache", + "errordeletesitefiles": "Error deleting site files.", + "errorsyncsite": "Error synchronising site data. Please check your Internet connection and try again.", + "estimatedfreespace": "Estimated free space", + "filesystemroot": "File system root", + "fontsize": "Text size", + "fontsizecharacter": "A", + "forcedsetting": "This setting has been forced by your site configuration.", + "general": "General", + "language": "Language", + "license": "Licence", + "localnotifavailable": "Local notifications available", + "locationhref": "Web view URL", + "locked": "Locked", + "loggedin": "Online", + "loggedoff": "Offline", + "navigatorlanguage": "Navigator language", + "navigatoruseragent": "Navigator userAgent", + "networkstatus": "Internet connection status", + "opensourcelicenses": "Open Source Licences", + "preferences": "Preferences", + "privacypolicy": "Privacy policy", + "publisher": "Publisher", + "pushid": "Push notifications ID", + "reportinbackground": "Report errors automatically", + "screen": "Screen information", + "settings": "Settings", + "showdownloadoptions": "Show download options", + "siteinfo": "Site info", + "sites": "Sites", + "spaceusage": "Space usage", + "spaceusagehelp": "Deleting the stored information of the site will remove all the site offline data. This information allows you to use the app when offline. ", + "synchronization": "Synchronisation", + "synchronizenow": "Synchronise now", + "synchronizenowhelp": "Synchronising a site will send pending changes and all offline activity stored in the device and will synchronise some data like messages and notifications.", + "syncsettings": "Synchronisation settings", + "total": "Total", + "wificonnection": "Wi-Fi connection" +} diff --git a/src/app/core/settings/pages/about/about.html b/src/app/core/settings/pages/about/about.html new file mode 100644 index 000000000..bf1262e5f --- /dev/null +++ b/src/app/core/settings/pages/about/about.html @@ -0,0 +1,29 @@ + + + + + + + + {{ 'core.settings.about' | translate}} + + + + + + +

{{ appName }} {{ versionName }}

+
+ + + {{ 'core.settings.opensourcelicenses' | translate }} + + + + {{ 'core.settings.privacypolicy' | translate }} + + + + {{ 'core.settings.deviceinfo' | translate }} + +
diff --git a/src/app/core/settings/pages/about/about.page.ts b/src/app/core/settings/pages/about/about.page.ts new file mode 100644 index 000000000..cf00be122 --- /dev/null +++ b/src/app/core/settings/pages/about/about.page.ts @@ -0,0 +1,55 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { CoreSites } from '@services/sites'; +import { Component } from '@angular/core'; +import { Router } from '@angular/router'; +import { CoreConstants } from '@core/constants'; +import { CoreApp } from '@services/app'; + +@Component({ + selector: 'settings-about', + templateUrl: 'about.html', +}) +export class CoreSettingsAboutPage { + + appName: string; + versionName: string; + privacyPolicy: string; + + constructor( + protected router: Router, + ) { + const currentSite = CoreSites.instance.getCurrentSite(); + + this.appName = CoreApp.instance.isDesktop() ? CoreConstants.CONFIG.desktopappname : CoreConstants.CONFIG.appname; + this.versionName = CoreConstants.CONFIG.versionname; + + // Calculate the privacy policy to use. + this.privacyPolicy = (currentSite && (currentSite.getStoredConfig('tool_mobile_apppolicy') || + currentSite.getStoredConfig('sitepolicy'))) || CoreConstants.CONFIG.privacypolicy; + } + + /** + * Opens a page. + * + * @param page The component deeplink name you want to push onto the navigation stack. + */ + openPage(page: string): void { + // const navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl; + // navCtrl.push(page); + this.router.navigate(['/settings/' + page]); + } + +} diff --git a/src/app/core/settings/pages/app/app.html b/src/app/core/settings/pages/app/app.html new file mode 100644 index 000000000..584a4e456 --- /dev/null +++ b/src/app/core/settings/pages/app/app.html @@ -0,0 +1,33 @@ + + + + + + + {{ 'core.settings.appsettings' | translate}} + + + + + + + {{ 'core.settings.general' | translate }} + + + + {{ 'core.settings.spaceusage' | translate }} + + + + {{ 'core.settings.synchronization' | translate }} + + + + {{ 'core.sharedfiles.sharedfiles' | translate }} + + + + {{ 'core.settings.about' | translate }} + + diff --git a/src/app/core/settings/pages/app/app.page.ts b/src/app/core/settings/pages/app/app.page.ts new file mode 100644 index 000000000..8d1dac8a4 --- /dev/null +++ b/src/app/core/settings/pages/app/app.page.ts @@ -0,0 +1,65 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { CoreApp } from '@services/app'; +import { Component } from '@angular/core'; +import { ActivatedRoute, Params, Router } from '@angular/router'; + +@Component({ + selector: 'app-settings', + templateUrl: 'app.html', +}) +export class CoreAppSettingsPage { + + // @ViewChild(CoreSplitViewComponent) splitviewCtrl?: CoreSplitViewComponent; + + isIOS: boolean; + selectedPage?: string; + + constructor( + protected route: ActivatedRoute, + protected router: Router, // Will be removed when splitview is implemented + ) { + this.isIOS = CoreApp.instance.isIOS(); + this.selectedPage = route.snapshot.paramMap.get('page') || undefined; + + if (this.selectedPage) { + this.openSettings(this.selectedPage); + } + } + + /** + * View loaded. + */ + ionViewDidLoad(): void { + if (this.selectedPage) { + this.openSettings(this.selectedPage); + } /* else if (this.splitviewCtrl!.isOn()) { + this.openSettings('general'); + }*/ + } + + /** + * Open a settings page. + * + * @param page Page to open. + * @param params Params of the page to open. + */ + openSettings(page: string, params?: Params): void { + this.selectedPage = page; + // this.splitviewCtrl!.push(page, params); + this.router.navigate(['../'+page], { relativeTo: this.route, queryParams: params }); + } + +} diff --git a/src/app/core/settings/pages/deviceinfo/deviceinfo.html b/src/app/core/settings/pages/deviceinfo/deviceinfo.html new file mode 100644 index 000000000..0fdd400de --- /dev/null +++ b/src/app/core/settings/pages/deviceinfo/deviceinfo.html @@ -0,0 +1,142 @@ + + + + + + + {{ 'core.settings.deviceinfo' | translate }} + + + + + + + + + + + + +

{{ 'core.settings.appversion' | translate}}

+

{{ deviceInfo.versionName }} ({{ deviceInfo.versionCode }})

+
+
+ + +

{{ 'core.settings.compilationinfo' | translate }}

+

{{ deviceInfo.compilationTime | coreFormatDate: "LLL Z": false }}

+

{{ deviceInfo.lastCommit }}

+
+
+ + +

{{ 'core.settings.siteinfo' | translate }} *

+

{{ deviceInfo.siteUrl }}

+

{{ deviceInfo.siteVersion }}

+

{{ deviceInfo.siteId }}

+
+
+ + +

{{ 'core.settings.filesystemroot' | translate }}

+

{{ deviceInfo.fileSystemRoot }}

+

{{ deviceInfo.fileSystemRoot }}

+
+
+ + +

{{ 'core.settings.navigatoruseragent' | translate }}

+

{{ deviceInfo.userAgent }}

+
+
+ + +

{{ 'core.settings.navigatorlanguage' | translate }}

+

{{ deviceInfo.browserLanguage }}

+
+
+ + +

{{ 'core.settings.currentlanguage' | translate }}

+

{{ currentLangName }} ({{ deviceInfo.currentLanguage }})

+
+
+ + +

{{ 'core.settings.locationhref' | translate }}

+

{{ deviceInfo.locationHref }}

+
+
+ + +

{{ 'core.settings.displayformat' | translate }}

+

{{ 'core.' + deviceInfo.deviceType | translate }}

+
+
+ + +

{{ 'core.settings.deviceos' | translate}}

+

{{ deviceOsTranslated }}

+
+
+ + +

{{ 'core.settings.screen' | translate }}

+

{{ deviceInfo.screen }}

+
+
+ + +

{{ 'core.settings.networkstatus' | translate}}

+

{{ 'core.' + deviceInfo.networkStatus | translate }}

+
+
+ + +

{{ 'core.settings.wificonnection' | translate}}

+

{{ 'core.' + deviceInfo.wifiConnection | translate }}

+
+
+ + +

{{ 'core.settings.cordovaversion' | translate }}

+

{{ deviceInfo.cordovaVersion }}

+
+
+ + +

{{ 'core.settings.cordovadeviceplatform' | translate }}

+

{{ deviceInfo.platform }}

+
+
+ + +

{{ 'core.settings.cordovadeviceosversion' | translate }}

+

{{ deviceInfo.osVersion }}

+
+
+ + +

{{ 'core.settings.cordovadevicemodel' | translate}}

+

{{ deviceInfo.model }}

+
+
+ + +

{{ 'core.settings.cordovadeviceuuid'}}

+

{{ deviceInfo.uuid }}

+
+
+ + +

{{ 'core.settings.pushid' | translate }}

+

{{ deviceInfo.pushId }}

+
+
+ + +

{{ 'core.settings.localnotifavailable' | translate }}

+

{{ 'core.' + deviceInfo.localNotifAvailable | translate }}

+
+
+
diff --git a/src/app/core/settings/pages/deviceinfo/deviceinfo.page.ts b/src/app/core/settings/pages/deviceinfo/deviceinfo.page.ts new file mode 100644 index 000000000..322fb6585 --- /dev/null +++ b/src/app/core/settings/pages/deviceinfo/deviceinfo.page.ts @@ -0,0 +1,232 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { CoreApp } from '@services/app'; +import { Component, OnDestroy } from '@angular/core'; +import { CoreConstants } from '@core/constants'; +import { CoreLocalNotifications } from '@services/local-notifications'; +import { Device, Platform, Translate, Network, NgZone } from '@singletons/core.singletons'; +import { CoreLang } from '@services/lang'; +import { CoreFile } from '@services/file'; +import { CoreSites } from '@services/sites'; +import { CoreUtils } from '@services/utils/utils'; +import { Subscription } from 'rxjs'; + +/** + * Device Info to be shown and copied to clipboard. + */ +interface CoreSettingsDeviceInfo { + versionName: string; + versionCode: number; + compilationTime: number; + lastCommit: string; + siteUrl?: string; + isPrefixedUrl?: boolean; + siteId?: string; + siteVersion?: string; + fileSystemRoot?: string; + userAgent?: string; + deviceOs?: string; + browserLanguage?: string; + currentLanguage?: string; + locationHref?: string; + deviceType: string; + screen?: string; + networkStatus: string; + wifiConnection: string; + cordovaVersion?: string; + platform?: string; + osVersion?: string; + model?: string; + uuid?: string; + pushId: string; + localNotifAvailable: string; +} + + +@Component({ + selector: 'settings-deviceinfo', + templateUrl: 'deviceinfo.html', + styleUrls: ['deviceinfo.scss'], +}) +export class CoreSettingsDeviceInfoPage implements OnDestroy { + + deviceInfo: CoreSettingsDeviceInfo; + deviceOsTranslated?: string; + currentLangName?: string; + fsClickable = false; + + protected onlineObserver?: Subscription; + + constructor() { + const appProvider = CoreApp.instance; + const sitesProvider = CoreSites.instance; + const device = Device.instance; + const translate = Translate.instance; + const navigator = window.navigator; + + this.deviceInfo = { + versionName: CoreConstants.CONFIG.versionname, + versionCode: CoreConstants.CONFIG.versioncode, + compilationTime: CoreConstants.BUILD.compilationTime || 0, + lastCommit: CoreConstants.BUILD.lastCommitHash || '', + networkStatus: appProvider.isOnline() ? 'online' : 'offline', + wifiConnection: appProvider.isWifi() ? 'yes' : 'no', + localNotifAvailable: CoreLocalNotifications.instance.isAvailable() ? 'yes' : 'no', + pushId: '',// TODO pushNotificationsProvider.getPushId(), + deviceType: '', + }; + + if (window.location && window.location.href) { + const url = window.location.href; + this.deviceInfo.locationHref = url.indexOf('#') > 0 ? url.substr(0, url.indexOf('#')) : url; + } + + if (window.screen) { + this.deviceInfo.screen = window.innerWidth + 'x' + window.innerHeight + + ' (' + window.screen.width + 'x' + window.screen.height + ')'; + } + + if (appProvider.isMobile()) { + this.deviceInfo.deviceType = Platform.instance.is('tablet') ? 'tablet' : 'phone'; + if (appProvider.isAndroid()) { + this.deviceInfo.deviceOs = 'android'; + this.deviceOsTranslated = 'Android'; + } else if (appProvider.isIOS()) { + this.deviceInfo.deviceOs = 'ios'; + this.deviceOsTranslated = 'iOS'; + } else { + const matches = navigator.userAgent.match(/\(([^)]*)\)/); + if (matches && matches.length > 1) { + this.deviceInfo.deviceOs = matches[1]; + this.deviceOsTranslated = matches[1]; + } else { + this.deviceInfo.deviceOs = 'unknown'; + this.deviceOsTranslated = translate.instant('core.unknown'); + } + } + } else { + this.deviceInfo.deviceType = appProvider.isDesktop() ? 'desktop' : 'browser'; + if (appProvider.isLinux()) { + this.deviceInfo.deviceOs = 'linux'; + this.deviceOsTranslated = 'Linux'; + } else if (appProvider.isMac()) { + this.deviceInfo.deviceOs = 'mac'; + this.deviceOsTranslated = 'MacOS'; + } else if (appProvider.isWindows()) { + this.deviceInfo.deviceOs = 'windows'; + this.deviceOsTranslated = 'Windows'; + } else { + const matches = navigator.userAgent.match(/\(([^)]*)\)/); + if (matches && matches.length > 1) { + this.deviceInfo.deviceOs = matches[1]; + this.deviceOsTranslated = matches[1]; + } else { + this.deviceInfo.deviceOs = 'unknown'; + this.deviceOsTranslated = translate.instant('core.unknown'); + } + } + } + + if (navigator) { + if (navigator.userAgent) { + this.deviceInfo.userAgent = navigator.userAgent; + } + + if (navigator.language) { + this.deviceInfo.browserLanguage = navigator.language; + } + } + + if (device) { + if (device.cordova) { + this.deviceInfo.cordovaVersion = device.cordova; + } + if (device.platform) { + this.deviceInfo.platform = device.platform; + } + if (device.version) { + this.deviceInfo.osVersion = device.version; + } + if (device.model) { + this.deviceInfo.model = device.model; + } + if (device.uuid) { + this.deviceInfo.uuid = device.uuid; + } + } + + const currentSite = sitesProvider.getCurrentSite(); + + this.deviceInfo.siteUrl = (currentSite?.getURL()) || + (typeof CoreConstants.CONFIG.siteurl == 'string' && CoreConstants.CONFIG.siteurl) || undefined; + this.deviceInfo.isPrefixedUrl = !!CoreConstants.CONFIG.siteurl; + this.deviceInfo.siteId = currentSite?.getId(); + this.deviceInfo.siteVersion = currentSite?.getInfo()?.release; + + // Refresh online status when changes. + this.onlineObserver = Network.instance.onChange().subscribe(() => { + // Execute the callback in the Angular zone, so change detection doesn't stop working. + NgZone.instance.run(() => { + this.deviceInfo!.networkStatus = appProvider.isOnline() ? 'online' : 'offline'; + }); + }); + + this.asyncInit(); + } + + /** + * Async part of the constructor. + */ + protected async asyncInit(): Promise { + const fileProvider = CoreFile.instance; + + const lang = await CoreLang.instance.getCurrentLanguage(); + this.deviceInfo.currentLanguage = lang; + this.currentLangName = CoreConstants.CONFIG.languages[lang]; + + if (fileProvider.isAvailable()) { + const basepath = await fileProvider.getBasePath(); + this.deviceInfo.fileSystemRoot = basepath; + this.fsClickable = fileProvider.usesHTMLAPI(); + } + } + + /** + * Copies device info into the clipboard. + */ + copyInfo(): void { + CoreUtils.instance.copyToClipboard(JSON.stringify(this.deviceInfo)); + } + + /** + * Copies device info item into the clipboard. + * + * @param e Event. + */ + copyItemInfo(e: Event): void { + const el = e.target; + const text = el?.closest('ion-item')?.textContent?.trim(); + + text && CoreUtils.instance.copyToClipboard(text); + } + + /** + * Page destroyed. + */ + ngOnDestroy(): void { + this.onlineObserver && this.onlineObserver.unsubscribe(); + } + +} diff --git a/src/app/core/settings/pages/deviceinfo/deviceinfo.scss b/src/app/core/settings/pages/deviceinfo/deviceinfo.scss new file mode 100644 index 000000000..b988af545 --- /dev/null +++ b/src/app/core/settings/pages/deviceinfo/deviceinfo.scss @@ -0,0 +1,4 @@ +.item { + user-select: text; + cursor: text; +} diff --git a/src/app/core/settings/settings-routing.module.ts b/src/app/core/settings/settings-routing.module.ts new file mode 100644 index 000000000..b00808bee --- /dev/null +++ b/src/app/core/settings/settings-routing.module.ts @@ -0,0 +1,45 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { CoreAppSettingsPage } from './pages/app/app.page'; +import { CoreSettingsAboutPage } from './pages/about/about.page'; +import { CoreSettingsDeviceInfoPage } from './pages/deviceinfo/deviceinfo.page'; + +const routes: Routes = [ + { + path: 'about', + component: CoreSettingsAboutPage, + }, + { + path: 'deviceinfo', + component: CoreSettingsDeviceInfoPage, + }, + { + path: 'app', + component: CoreAppSettingsPage, + }, + { + path: '', + redirectTo: 'app', + pathMatch: 'full', + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class CoreAppSettingsRoutingModule {} diff --git a/src/app/core/settings/settings.module.ts b/src/app/core/settings/settings.module.ts new file mode 100644 index 000000000..cef43ab4c --- /dev/null +++ b/src/app/core/settings/settings.module.ts @@ -0,0 +1,46 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { IonicModule } from '@ionic/angular'; +import { TranslateModule } from '@ngx-translate/core'; + +import { CoreAppSettingsRoutingModule } from './settings-routing.module'; +import { CorePipesModule } from '@pipes/pipes.module'; +import { CoreComponentsModule } from '@components/components.module'; +import { CoreDirectivesModule } from '@directives/directives.module'; + +import { CoreAppSettingsPage } from './pages/app/app.page'; +import { CoreSettingsAboutPage } from './pages/about/about.page'; +import { CoreSettingsDeviceInfoPage } from './pages/deviceinfo/deviceinfo.page'; + +@NgModule({ + imports: [ + CommonModule, + IonicModule, + CoreAppSettingsRoutingModule, + CorePipesModule, + CoreComponentsModule, + CoreDirectivesModule, + TranslateModule.forChild(), + ], + declarations: [ + CoreAppSettingsPage, + CoreSettingsAboutPage, + CoreSettingsDeviceInfoPage, + ], +}) +export class CoreAppSettingsPageModule {} diff --git a/src/app/lang/en.json b/src/app/lang/en.json new file mode 100644 index 000000000..00ce91b93 --- /dev/null +++ b/src/app/lang/en.json @@ -0,0 +1,11 @@ +{ + "back": "Back", + "browser": "Browser", + "copiedtoclipboard": "Text copied to clipboard", + "no": "No", + "offline": "Offline", + "ok": "OK", + "online": "Online", + "unknown": "Unknown", + "yes": "Yes" +} diff --git a/src/assets/lang/en.json b/src/assets/lang/en.json index 5ada0eb7d..2c01ee081 100644 --- a/src/assets/lang/en.json +++ b/src/assets/lang/en.json @@ -300,5 +300,85 @@ "assets.mimetypes.text/rtf": "RTF document", "assets.mimetypes.text/vtt": "Web Video Text Track", "assets.mimetypes.video": "Video file ({{$a.EXT}})", - "core.login.yourenteredsite": "Connect to your site" + "core.back": "Back", + "core.browser": "Browser", + "core.copiedtoclipboard": "Text copied to clipboard", + "core.login.yourenteredsite": "Connect to your site", + "core.no": "No", + "core.offline": "Offline", + "core.ok": "OK", + "core.online": "Online", + "core.settings.about": "About", + "core.settings.appsettings": "App settings", + "core.settings.appversion": "App version", + "core.settings.cannotsyncloggedout": "This site cannot be synchronised because you've logged out. Please try again when you're logged in the site again.", + "core.settings.cannotsyncoffline": "Cannot synchronise offline.", + "core.settings.cannotsyncwithoutwifi": "Cannot synchronise because the current settings only allow to synchronise when connected to Wi-Fi. Please connect to a Wi-Fi network.", + "core.settings.colorscheme": "Color Scheme", + "core.settings.colorscheme-auto": "Auto (based on system settings)", + "core.settings.colorscheme-dark": "Dark", + "core.settings.colorscheme-light": "Light", + "core.settings.compilationinfo": "Compilation info", + "core.settings.copyinfo": "Copy device info on the clipboard", + "core.settings.cordovadevicemodel": "Cordova device model", + "core.settings.cordovadeviceosversion": "Cordova device OS version", + "core.settings.cordovadeviceplatform": "Cordova device platform", + "core.settings.cordovadeviceuuid": "Cordova device UUID", + "core.settings.cordovaversion": "Cordova version", + "core.settings.currentlanguage": "Current language", + "core.settings.debugdisplay": "Display debug messages", + "core.settings.debugdisplaydescription": "If enabled, error modals will display more data about the error if possible.", + "core.settings.deletesitefiles": "Are you sure that you want to delete the downloaded files and cached data from the site '{{sitename}}'? You won't be able to use the app in offline mode.", + "core.settings.deletesitefilestitle": "Delete site files", + "core.settings.deviceinfo": "Device info", + "core.settings.deviceos": "Device OS", + "core.settings.disableall": "Disable notifications", + "core.settings.disabled": "Disabled", + "core.settings.displayformat": "Display format", + "core.settings.enabledownloadsection": "Enable download sections", + "core.settings.enablefirebaseanalytics": "Enable Firebase analytics", + "core.settings.enablefirebaseanalyticsdescription": "If enabled, the app will collect anonymous data usage.", + "core.settings.enablerichtexteditor": "Enable text editor", + "core.settings.enablerichtexteditordescription": "If enabled, a text editor will be available when entering content.", + "core.settings.enablesyncwifi": "Allow sync only when on Wi-Fi", + "core.settings.entriesincache": "{{$a}} entries in cache", + "core.settings.errordeletesitefiles": "Error deleting site files.", + "core.settings.errorsyncsite": "Error synchronising site data. Please check your Internet connection and try again.", + "core.settings.estimatedfreespace": "Estimated free space", + "core.settings.filesystemroot": "File system root", + "core.settings.fontsize": "Text size", + "core.settings.fontsizecharacter": "A", + "core.settings.forcedsetting": "This setting has been forced by your site configuration.", + "core.settings.general": "General", + "core.settings.language": "Language", + "core.settings.license": "Licence", + "core.settings.localnotifavailable": "Local notifications available", + "core.settings.locationhref": "Web view URL", + "core.settings.locked": "Locked", + "core.settings.loggedin": "Online", + "core.settings.loggedoff": "Offline", + "core.settings.navigatorlanguage": "Navigator language", + "core.settings.navigatoruseragent": "Navigator userAgent", + "core.settings.networkstatus": "Internet connection status", + "core.settings.opensourcelicenses": "Open Source Licences", + "core.settings.preferences": "Preferences", + "core.settings.privacypolicy": "Privacy policy", + "core.settings.publisher": "Publisher", + "core.settings.pushid": "Push notifications ID", + "core.settings.reportinbackground": "Report errors automatically", + "core.settings.screen": "Screen information", + "core.settings.settings": "Settings", + "core.settings.showdownloadoptions": "Show download options", + "core.settings.siteinfo": "Site info", + "core.settings.sites": "Sites", + "core.settings.spaceusage": "Space usage", + "core.settings.spaceusagehelp": "Deleting the stored information of the site will remove all the site offline data. This information allows you to use the app when offline. ", + "core.settings.synchronization": "Synchronisation", + "core.settings.synchronizenow": "Synchronise now", + "core.settings.synchronizenowhelp": "Synchronising a site will send pending changes and all offline activity stored in the device and will synchronise some data like messages and notifications.", + "core.settings.syncsettings": "Synchronisation settings", + "core.settings.total": "Total", + "core.settings.wificonnection": "Wi-Fi connection", + "core.unknown": "Unknown", + "core.yes": "Yes" } \ No newline at end of file From 0f694769ed6e4cacb74733f8d9774196fa229528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Thu, 22 Oct 2020 13:30:23 +0200 Subject: [PATCH 2/3] MOBILE-3565 core: Add core-fab directive --- src/app/directives/directives.module.ts | 5 +- src/app/directives/fab.ts | 63 +++++++++++++++++++ ...{long-press.directive.ts => long-press.ts} | 0 src/theme/app.scss | 1 + src/theme/variables.scss | 2 + 5 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/app/directives/fab.ts rename src/app/directives/{long-press.directive.ts => long-press.ts} (100%) create mode 100644 src/theme/app.scss diff --git a/src/app/directives/directives.module.ts b/src/app/directives/directives.module.ts index e23a738a3..0d389ce22 100644 --- a/src/app/directives/directives.module.ts +++ b/src/app/directives/directives.module.ts @@ -17,8 +17,9 @@ import { NgModule } from '@angular/core'; import { CoreAutoFocusDirective } from './auto-focus'; import { CoreExternalContentDirective } from './external-content'; import { CoreFormatTextDirective } from './format-text'; -import { CoreLongPressDirective } from './long-press.directive'; +import { CoreLongPressDirective } from './long-press'; import { CoreSupressEventsDirective } from './supress-events'; +import { CoreFabDirective } from './fab'; @NgModule({ declarations: [ @@ -27,6 +28,7 @@ import { CoreSupressEventsDirective } from './supress-events'; CoreFormatTextDirective, CoreLongPressDirective, CoreSupressEventsDirective, + CoreFabDirective, ], imports: [], exports: [ @@ -35,6 +37,7 @@ import { CoreSupressEventsDirective } from './supress-events'; CoreFormatTextDirective, CoreLongPressDirective, CoreSupressEventsDirective, + CoreFabDirective, ], }) export class CoreDirectivesModule {} diff --git a/src/app/directives/fab.ts b/src/app/directives/fab.ts new file mode 100644 index 000000000..433d16bf5 --- /dev/null +++ b/src/app/directives/fab.ts @@ -0,0 +1,63 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Directive, OnDestroy } from '@angular/core'; +import { IonContent } from '@ionic/angular'; + +/** + * Directive to move ion-fab components as direct children of the nearest ion-content. + * + * Example usage: + * + * + */ +@Directive({ + selector: 'ion-fab[core-fab]', +}) +export class CoreFabDirective implements OnDestroy { + + protected static readonly PADDINGBOTTOM = 56; + + protected element?: HTMLElement; + protected done = false; + + constructor(protected content: IonContent) { + this.asyncInit(); + } + + /** + * Initialize Component. + */ + async asyncInit(): Promise { + if (this.content) { + this.element = await this.content.getScrollElement(); + if (!this.done) { + const bottom = parseInt(this.element.style.paddingBottom, 10) || 0; + this.element.style.paddingBottom = (bottom + CoreFabDirective.PADDINGBOTTOM) + 'px'; + this.done = true; + } + } + } + + /** + * Destroy component. + */ + ngOnDestroy(): void { + if (this.done && this.element) { + const bottom = parseInt(this.element.style.paddingBottom, 10) || 0; + this.element.style.paddingBottom = (bottom + CoreFabDirective.PADDINGBOTTOM) + 'px'; + } + } + +} diff --git a/src/app/directives/long-press.directive.ts b/src/app/directives/long-press.ts similarity index 100% rename from src/app/directives/long-press.directive.ts rename to src/app/directives/long-press.ts diff --git a/src/theme/app.scss b/src/theme/app.scss new file mode 100644 index 000000000..a653a15bc --- /dev/null +++ b/src/theme/app.scss @@ -0,0 +1 @@ +// Add here base app styles. diff --git a/src/theme/variables.scss b/src/theme/variables.scss index ae34d8a76..3705ca0a1 100644 --- a/src/theme/variables.scss +++ b/src/theme/variables.scss @@ -134,3 +134,5 @@ --background: var(--ion-background-color); } } + +@import "app.scss"; From 2f16be7a0c4f5521d5487bc46dea803bd2434446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Thu, 22 Oct 2020 11:17:21 +0200 Subject: [PATCH 3/3] MOBILE-3565 login: Fix sites page styles --- src/app/core/login/login.module.ts | 4 +- .../pages/credentials/credentials.page.ts | 4 +- src/app/core/login/pages/site/site.html | 7 +-- src/app/core/login/pages/site/site.page.ts | 4 +- src/app/core/login/pages/sites/sites.html | 46 ++++++++++--------- src/app/core/login/pages/sites/sites.page.ts | 13 +++--- src/app/core/login/pages/sites/sites.scss | 3 -- src/app/services/utils/url.ts | 2 +- src/theme/app.scss | 5 ++ src/types/global.d.ts | 2 +- 10 files changed, 48 insertions(+), 42 deletions(-) delete mode 100644 src/app/core/login/pages/sites/sites.scss diff --git a/src/app/core/login/login.module.ts b/src/app/core/login/login.module.ts index 3a102970b..5bfd7fd32 100644 --- a/src/app/core/login/login.module.ts +++ b/src/app/core/login/login.module.ts @@ -19,8 +19,8 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { IonicModule } from '@ionic/angular'; import { TranslateModule } from '@ngx-translate/core'; -import { CoreComponentsModule } from '@/app/components/components.module'; -import { CoreDirectivesModule } from '@/app/directives/directives.module'; +import { CoreComponentsModule } from '@components/components.module'; +import { CoreDirectivesModule } from '@directives/directives.module'; import { CoreLoginRoutingModule } from './login-routing.module'; import { CoreLoginCredentialsPage } from './pages/credentials/credentials.page'; diff --git a/src/app/core/login/pages/credentials/credentials.page.ts b/src/app/core/login/pages/credentials/credentials.page.ts index 6e399917f..d189c504f 100644 --- a/src/app/core/login/pages/credentials/credentials.page.ts +++ b/src/app/core/login/pages/credentials/credentials.page.ts @@ -22,9 +22,9 @@ import { CoreSites } from '@services/sites'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreUtils } from '@services/utils/utils'; import { CoreLoginHelper, CoreLoginHelperProvider } from '@core/login/services/helper'; -import { CoreConstants } from '@/app/core/constants'; +import { CoreConstants } from '@core/constants'; import { Translate } from '@singletons/core.singletons'; -import { CoreSiteIdentityProvider, CoreSitePublicConfigResponse } from '@/app/classes/site'; +import { CoreSiteIdentityProvider, CoreSitePublicConfigResponse } from '@classes/site'; import { CoreEvents } from '@singletons/events'; /** diff --git a/src/app/core/login/pages/site/site.html b/src/app/core/login/pages/site/site.html index 40f5a58b9..559e7cf3e 100644 --- a/src/app/core/login/pages/site/site.html +++ b/src/app/core/login/pages/site/site.html @@ -1,14 +1,15 @@ - + {{ 'core.login.connecttomoodle' | translate }} - - + + diff --git a/src/app/core/login/pages/site/site.page.ts b/src/app/core/login/pages/site/site.page.ts index cfd05ec96..4ce8d7381 100644 --- a/src/app/core/login/pages/site/site.page.ts +++ b/src/app/core/login/pages/site/site.page.ts @@ -24,10 +24,10 @@ import { CoreDomUtils } from '@services/utils/dom'; import { CoreLoginHelper, CoreLoginHelperProvider } from '@core/login/services/helper'; import { CoreSite } from '@classes/site'; import { CoreError } from '@classes/errors/error'; -import { CoreConstants } from '@/app/core/constants'; +import { CoreConstants } from '@core/constants'; import { Translate } from '@singletons/core.singletons'; import { CoreUrl } from '@singletons/url'; -import { CoreUrlUtils } from '@/app/services/utils/url'; +import { CoreUrlUtils } from '@services/utils/url'; import { NavController } from '@ionic/angular'; /** diff --git a/src/app/core/login/pages/sites/sites.html b/src/app/core/login/pages/sites/sites.html index 45c01774c..805287344 100644 --- a/src/app/core/login/pages/sites/sites.html +++ b/src/app/core/login/pages/sites/sites.html @@ -1,39 +1,43 @@ - + {{ 'core.settings.sites' | translate }} - + - - - + + + - - + + {{ 'core.pictureof' | translate:{$a: site.fullName} }} -

{{site.fullName}}

-

-

{{site.siteUrl}}

- {{site.badge}} - - - -
-
- - - - - + +

{{site.fullName}}

+

+

{{site.siteUrl}}

+
+ {{site.badge}} + + + + + + + + + +
diff --git a/src/app/core/login/pages/sites/sites.page.ts b/src/app/core/login/pages/sites/sites.page.ts index 8605780a1..c05b8974f 100644 --- a/src/app/core/login/pages/sites/sites.page.ts +++ b/src/app/core/login/pages/sites/sites.page.ts @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { CoreDomUtils } from '@/app/services/utils/dom'; -import { CoreUtils } from '@/app/services/utils/utils'; +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreUtils } from '@services/utils/utils'; import { Component, OnInit } from '@angular/core'; import { CoreSiteBasicInfo, CoreSites } from '@services/sites'; @@ -26,7 +26,6 @@ import { CoreLoginHelper } from '../../services/helper'; @Component({ selector: 'page-core-login-sites', templateUrl: 'sites.html', - styleUrls: ['sites.scss'], }) export class CoreLoginSitesPage implements OnInit { @@ -76,13 +75,12 @@ export class CoreLoginSitesPage implements OnInit { * Delete a site. * * @param e Click event. - * @param index Position of the site. + * @param site Site to delete. * @return Promise resolved when done. */ - async deleteSite(e: Event, index: number): Promise { + async deleteSite(e: Event, site: CoreSiteBasicInfo): Promise { e.stopPropagation(); - const site = this.sites[index]; const siteName = site.siteName || ''; // @todo: Format text: siteName. @@ -97,7 +95,8 @@ export class CoreLoginSitesPage implements OnInit { try { await CoreSites.instance.deleteSite(site.id); - this.sites.splice(index, 1); + const index = this.sites.findIndex((listedSite) => listedSite.id == site.id); + index >= 0 && this.sites.splice(index, 1); this.showDelete = false; // If there are no sites left, go to add site. diff --git a/src/app/core/login/pages/sites/sites.scss b/src/app/core/login/pages/sites/sites.scss deleted file mode 100644 index abe0054de..000000000 --- a/src/app/core/login/pages/sites/sites.scss +++ /dev/null @@ -1,3 +0,0 @@ -.item-ios .item-button[icon-only] ion-icon { - font-size: 2.1em; -} diff --git a/src/app/services/utils/url.ts b/src/app/services/utils/url.ts index 51725c131..7fc7ee464 100644 --- a/src/app/services/utils/url.ts +++ b/src/app/services/utils/url.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { CoreLang } from '@services/lang'; import { CoreTextUtils } from '@services/utils/text'; -import { CoreConstants } from '@/app/core/constants'; +import { CoreConstants } from '@core/constants'; import { makeSingleton } from '@singletons/core.singletons'; import { CoreUrl } from '@singletons/url'; diff --git a/src/theme/app.scss b/src/theme/app.scss index a653a15bc..033a25fa9 100644 --- a/src/theme/app.scss +++ b/src/theme/app.scss @@ -1 +1,6 @@ // Add here base app styles. + +ion-toolbar ion-back-button, +ion-toolbar .in-toolbar.button-clear { + --color: var(--ion-color-primary-contrast); +} diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 26369b55c..fe9f98a26 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -14,7 +14,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { CoreSitesDemoSiteData } from '@/app/services/sites'; +import { CoreSitesDemoSiteData } from '@services/sites'; declare global {