forked from EVOgeek/Vmeda.Online
		
	
						commit
						fc72d481b6
					
				| @ -1095,12 +1095,14 @@ | ||||
|   "addon.notes.publishstate": "notes", | ||||
|   "addon.notes.sitenotes": "notes", | ||||
|   "addon.notes.warningnotenotsent": "local_moodlemobileapp", | ||||
|   "addon.notifications.allownotifications": "local_moodlemobileapp", | ||||
|   "addon.notifications.errorgetnotifications": "local_moodlemobileapp", | ||||
|   "addon.notifications.markallread": "moodle", | ||||
|   "addon.notifications.notificationpreferences": "message", | ||||
|   "addon.notifications.notifications": "local_moodlemobileapp", | ||||
|   "addon.notifications.playsound": "local_moodlemobileapp", | ||||
|   "addon.notifications.therearentnotificationsyet": "local_moodlemobileapp", | ||||
|   "addon.notifications.typeofnotification": "local_moodlemobileapp", | ||||
|   "addon.notifications.unreadnotification": "message", | ||||
|   "addon.privatefiles.couldnotloadfiles": "local_moodlemobileapp", | ||||
|   "addon.privatefiles.emptyfilelist": "local_moodlemobileapp", | ||||
|  | ||||
| @ -1,9 +1,11 @@ | ||||
| { | ||||
|     "allownotifications": "Allow notifications", | ||||
|     "errorgetnotifications": "Error getting notifications.", | ||||
|     "markallread": "Mark all as read", | ||||
|     "notificationpreferences": "Notification preferences", | ||||
|     "notifications": "Notifications", | ||||
|     "playsound": "Play sound", | ||||
|     "therearentnotificationsyet": "There are no notifications.", | ||||
|     "typeofnotification": "Type of notification", | ||||
|     "unreadnotification": "Unread notification: {{$a}}" | ||||
| } | ||||
|  | ||||
| @ -24,23 +24,32 @@ | ||||
|     <core-loading [hideUntil]="preferencesLoaded"> | ||||
|         <ion-card> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="preferences"> | ||||
|                 <ion-label>{{ 'addon.notifications.notifications' | translate }}</ion-label> | ||||
|                 <ion-toggle [(ngModel)]="preferences.enableall" (ngModelChange)="enableAll(preferences.enableall)"></ion-toggle> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ 'addon.notifications.allownotifications' | translate }}</p> | ||||
|                 </ion-label> | ||||
|                 <ion-toggle [(ngModel)]="preferences.enableall" (ngModelChange)="enableAll(preferences.enableall)" slot="end"></ion-toggle> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="canChangeSound"> | ||||
|                 <ion-label>{{ 'addon.notifications.playsound' | translate }}</ion-label> | ||||
|                 <ion-toggle [(ngModel)]="notificationSound" (ngModelChange)="changeNotificationSound(notificationSound)"> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ 'addon.notifications.playsound' | translate }}</p> | ||||
|                 </ion-label> | ||||
|                 <ion-toggle [(ngModel)]="notificationSound" (ngModelChange)="changeNotificationSound(notificationSound)" slot="end"> | ||||
|                 </ion-toggle> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| 
 | ||||
|         <ion-card> | ||||
|             <ion-item class="ion-text-wrap only-links" *ngIf="preferences?.processors?.length" lines="none" [button]="false"> | ||||
|                 <ion-label class="addon-notification-type-form"> | ||||
|                     <p class="item-heading">{{ 'addon.notifications.typeofnotification' | translate }}</p> | ||||
|                 </ion-label> | ||||
|                 <!-- Show processor selector. --> | ||||
|         <core-combobox *ngIf="preferences && preferences.processors && preferences.processors.length > 0" [selection]="currentProcessorName" | ||||
|             (onChange)="changeProcessor($event)"> | ||||
|             <ion-select-option class="ion-text-wrap" *ngFor="let processor of preferences.processors" [value]="processor.name"> | ||||
|                 <ion-select [(ngModel)]="currentProcessorName" (ionChange)="changeProcessor($event)" interface="popover"> | ||||
|                     <ion-select-option class="ion-text-wrap" *ngFor="let processor of preferences?.processors" [value]="processor.name"> | ||||
|                         {{ processor.displayname }} | ||||
|                     </ion-select-option> | ||||
|         </core-combobox> | ||||
|                 </ion-select> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <ng-container *ngIf="loggedInOffLegacyMode"> | ||||
|                 <ng-container *ngTemplateOutlet="legacySettings; context: {preferences: preferences}"></ng-container> | ||||
| @ -49,13 +58,15 @@ | ||||
|             <ng-container *ngIf="!loggedInOffLegacyMode"> | ||||
|                 <ng-container *ngTemplateOutlet="settings; context: {preferences: preferences}"></ng-container> | ||||
|             </ng-container> | ||||
|         </ion-card> | ||||
|     </core-loading> | ||||
| 
 | ||||
| </ion-content> | ||||
| 
 | ||||
| 
 | ||||
| <!-- 3.11 or downwards version --> | ||||
| <!-- 3.11 downwards version --> | ||||
| <ng-template #legacySettings let-preferences="preferences"> | ||||
|     <ion-card *ngFor="let component of components" class="ion-margin-top"> | ||||
|     <ng-container *ngFor="let component of components" class="ion-margin-top"> | ||||
|         <ion-card-header class="ion-no-padding"> | ||||
|             <ion-item class="ion-text-wrap divider"> | ||||
|                 <ion-label class="ion-text-wrap"> | ||||
| @ -108,7 +119,9 @@ | ||||
| 
 | ||||
|             <!-- Phone view --> | ||||
|             <ion-item class="ion-text-wrap ion-no-margin ion-hide-md-up"> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ notification.displayname }}</p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <!-- If notifications enabled, show toggles. If disabled, show "Disabled" instead of toggle. --> | ||||
|             <ion-item *ngFor="let state of ['loggedin', 'loggedoff']" class="ion-text-wrap ion-hide-md-up"> | ||||
| @ -135,12 +148,12 @@ | ||||
|                 <span class="text-gray" slot="end" *ngIf="!preferences!.enableall">{{ 'core.settings.disabled' | translate }}</span> | ||||
|             </ion-item> | ||||
|         </ng-container> | ||||
|     </ion-card> | ||||
|     </ng-container> | ||||
| </ng-template> | ||||
| 
 | ||||
| <!-- 4.0 or downwards version --> | ||||
| <!-- 4.0 onwards version --> | ||||
| <ng-template #settings let-preferences="preferences"> | ||||
|     <ion-card *ngFor="let component of components" class="ion-margin-top"> | ||||
|     <ng-container *ngFor="let component of components" class="ion-margin-top"> | ||||
|         <ion-item-divider class="ion-text-wrap"> | ||||
|             <ion-label> | ||||
|                 <p class="item-heading">{{ component.displayname }}</p> | ||||
| @ -173,6 +186,5 @@ | ||||
|                 <span class="text-gray" slot="end" *ngIf="!preferences!.enableall">{{ 'core.settings.disabled' | translate }}</span> | ||||
|             </ion-item> | ||||
|         </ng-container> | ||||
|     </ion-card> | ||||
| 
 | ||||
|     </ng-container> | ||||
| </ng-template> | ||||
|  | ||||
| @ -1,3 +1,7 @@ | ||||
| .addon-notifications-table-content ion-row { | ||||
|     min-height: 35px; | ||||
| } | ||||
| 
 | ||||
| ion-item-divider, ion-card-header { | ||||
|     border-top: 1px solid var(--stroke); | ||||
| } | ||||
|  | ||||
| @ -95,3 +95,11 @@ | ||||
|     } | ||||
|     min-height: 100%; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| :host-context(.ios) { | ||||
|     &.core-loading-loaded { | ||||
|         --contents-display: flex; | ||||
|         flex-direction: column; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -17,31 +17,70 @@ | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
|         <ion-list> | ||||
|             <ion-item *ngFor="let site of sites" [class.item-current]="site.id == currentSiteId"> | ||||
|                 <ion-label class="ion-text-wrap"> | ||||
|         <ion-list class="core-sitelist limited-width"> | ||||
|             <ion-card *ngIf="accountsList.currentSite"> | ||||
|                 <ion-item-divider sticky="true" class="core-sitelist-sitename"> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading"> | ||||
|                         <core-format-text [text]="site.siteName" clean="true" [siteId]="site.id"></core-format-text> | ||||
|                             <core-format-text [text]="accountsList.currentSite.siteName" clean="true" | ||||
|                                 [siteId]="accountsList.currentSite.id"></core-format-text> | ||||
|                         </p> | ||||
|                         <p><a [href]="accountsList.currentSite.siteUrl" core-link autoLogin="yes">{{ | ||||
|                                 accountsList.currentSite.siteUrlWithoutProtocol }}</a> | ||||
|                         </p> | ||||
|                     <p class="ion-text-wrap">{{ site.fullName }}</p> | ||||
|                     <p>{{ site.siteUrlWithoutProtocol }}</p> | ||||
|                     <ion-badge color="light" *ngIf="site.spaceUsage !== undefined">{{ site.spaceUsage | coreBytesToSize }}</ion-badge> | ||||
|                     </ion-label> | ||||
|                 <ion-button fill="clear" color="danger" slot="end" (click)="deleteSiteStorage(site)" | ||||
|                     [hidden]="site.spaceUsage! + site.cacheEntries! <= 0"> | ||||
|                     <ion-icon name="fas-trash" slot="icon-only" | ||||
|                         [attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: { name: site.siteName }"> | ||||
|                     </ion-icon> | ||||
|                 </ion-button> | ||||
|                 </ion-item-divider> | ||||
| 
 | ||||
|                 <ion-item class="item-current"> | ||||
|                     <ng-container *ngTemplateOutlet="siteUsage; context: {site: accountsList.currentSite}"></ng-container> | ||||
|                 </ion-item> | ||||
| 
 | ||||
|                 <ion-item *ngFor="let site of accountsList.sameSite"> | ||||
|                     <ng-container *ngTemplateOutlet="siteUsage; context: {site: site}"></ng-container> | ||||
|                 </ion-item> | ||||
|             </ion-card> | ||||
| 
 | ||||
|             <ion-card *ngFor="let sites of accountsList.otherSites"> | ||||
|                 <ion-item-divider sticky="true" *ngIf="sites[0]" class="core-sitelist-sitename"> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading"> | ||||
|                             <core-format-text [text]="sites[0].siteName" clean="true" [siteId]="sites[0].id"></core-format-text> | ||||
|                         </p> | ||||
|                         <p><a [href]="sites[0].siteUrl" core-link autoLogin="no">{{ sites[0].siteUrlWithoutProtocol }}</a></p> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
| 
 | ||||
|                 <ion-item *ngFor="let site of sites"> | ||||
|                     <ng-container *ngTemplateOutlet="siteUsage; context: {site: site}"></ng-container> | ||||
|                 </ion-item> | ||||
|             </ion-card> | ||||
| 
 | ||||
|             <ion-item-divider> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'core.settings.total' | translate }}</h2> | ||||
|                 </ion-label> | ||||
|                 <p slot="end" class="ion-margin-end"> | ||||
|                     {{ totals.spaceUsage | coreBytesToSize }} | ||||
|                     {{ totalSpaceUsage | coreBytesToSize }} | ||||
|                 </p> | ||||
|             </ion-item-divider> | ||||
|         </ion-list> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
| 
 | ||||
| <!-- Template to render a site space usage. --> | ||||
| <ng-template #siteUsage let-site="site"> | ||||
|     <ion-avatar slot="start"> | ||||
|         <img [src]="site.avatar" core-external-content [siteId]="site.id" alt="{{ 'core.pictureof' | translate:{$a: site.fullName} }}" | ||||
|             onError="this.src='assets/img/user-avatar.png'"> | ||||
|     </ion-avatar> | ||||
|     <ion-label class="ion-text-wrap"> | ||||
|         <p class="item-heading">{{site.fullName}}</p> | ||||
|         <ion-badge color="light" *ngIf="site.spaceUsage !== undefined">{{ site.spaceUsage | coreBytesToSize }}</ion-badge> | ||||
|     </ion-label> | ||||
|     <ion-button fill="clear" color="danger" slot="end" (click)="deleteSiteStorage(site)" | ||||
|         [hidden]="site.spaceUsage <= 0 && !site.hasCacheEntries"> | ||||
|         <ion-icon name="fas-trash" slot="icon-only" | ||||
|             [attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: { name: site.siteName }"> | ||||
|         </ion-icon> | ||||
|     </ion-button> | ||||
| </ng-template> | ||||
|  | ||||
| @ -16,9 +16,10 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; | ||||
| import { IonRefresher } from '@ionic/angular'; | ||||
| 
 | ||||
| import { CoreSiteBasicInfo, CoreSites } from '@services/sites'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { CoreEventObserver, CoreEvents } from '@singletons/events'; | ||||
| 
 | ||||
| import { CoreSettingsHelper, CoreSiteSpaceUsage } from '../../services/settings-helper'; | ||||
| import { CoreSettingsHelper } from '../../services/settings-helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Page that displays the space usage settings. | ||||
| @ -30,37 +31,52 @@ import { CoreSettingsHelper, CoreSiteSpaceUsage } from '../../services/settings- | ||||
| export class CoreSettingsSpaceUsagePage implements OnInit, OnDestroy { | ||||
| 
 | ||||
|     loaded = false; | ||||
|     sites: CoreSiteBasicInfoWithUsage[] = []; | ||||
|     currentSiteId = ''; | ||||
|     totals: CoreSiteSpaceUsage = { | ||||
|         cacheEntries: 0, | ||||
|         spaceUsage: 0, | ||||
|     totalSpaceUsage = 0; | ||||
| 
 | ||||
|     accountsList: CoreAccountsListWithUsage = { | ||||
|         sameSite: [], | ||||
|         otherSites: [], | ||||
|     }; | ||||
| 
 | ||||
|     protected sitesObserver: CoreEventObserver; | ||||
| 
 | ||||
|     constructor() { | ||||
|         this.currentSiteId = CoreSites.getCurrentSiteId(); | ||||
| 
 | ||||
|         this.sitesObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, async (data) => { | ||||
|             const site = await CoreSites.getSite(data.siteId); | ||||
|             const siteId = data.siteId; | ||||
| 
 | ||||
|             const siteEntry = this.sites.find((siteEntry) => siteEntry.id == site.id); | ||||
|             if (siteEntry) { | ||||
|             let siteEntry = siteId === this.accountsList.currentSite?.id | ||||
|                 ? this.accountsList.currentSite | ||||
|                 : undefined; | ||||
| 
 | ||||
|             if (!siteEntry) { | ||||
|                 siteEntry = this.accountsList.sameSite.find((siteEntry) => siteEntry.id === siteId); | ||||
|             } | ||||
| 
 | ||||
|             if (!siteEntry) { | ||||
|                 this.accountsList.otherSites.some((sites) => { | ||||
|                     siteEntry = sites.find((siteEntry) => siteEntry.id === siteId); | ||||
| 
 | ||||
|                     return siteEntry; | ||||
|                 }); | ||||
|             } | ||||
| 
 | ||||
|             if (!siteEntry) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             const site = await CoreSites.getSite(siteId); | ||||
|             const siteInfo = site.getInfo(); | ||||
| 
 | ||||
|             siteEntry.siteName = site.getSiteName(); | ||||
| 
 | ||||
|             if (siteInfo) { | ||||
|                 siteEntry.siteUrl = siteInfo.siteurl; | ||||
|                 siteEntry.fullName = siteInfo.fullname; | ||||
|             } | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * View loaded. | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     ngOnInit(): void { | ||||
|         this.loadSiteData().finally(() => { | ||||
| @ -76,31 +92,65 @@ export class CoreSettingsSpaceUsagePage implements OnInit, OnDestroy { | ||||
|     protected async loadSiteData(): Promise<void> { | ||||
|         // Calculate total usage.
 | ||||
|         let totalSize = 0; | ||||
|         let totalEntries = 0; | ||||
| 
 | ||||
|         this.sites = await CoreSites.getSortedSites(); | ||||
|         const sites = await CoreUtils.ignoreErrors(CoreSites.getSortedSites(), [] as CoreSiteBasicInfo[]); | ||||
|         const sitesWithUsage = await Promise.all(sites.map((site) => this.getSiteWithUsage(site))); | ||||
| 
 | ||||
|         const settingsHelper = CoreSettingsHelper.instance; | ||||
|         let siteUrl = ''; | ||||
| 
 | ||||
|         const currentSiteId = CoreSites.getCurrentSiteId(); | ||||
| 
 | ||||
|         if (currentSiteId) { | ||||
|             const index = sitesWithUsage.findIndex((site) => site.id === currentSiteId); | ||||
| 
 | ||||
|             const siteWithUsage = sitesWithUsage.splice(index, 1)[0]; | ||||
|             this.accountsList.currentSite = siteWithUsage; | ||||
|             totalSize += siteWithUsage.spaceUsage || 0; | ||||
| 
 | ||||
|             siteUrl = this.accountsList.currentSite.siteUrlWithoutProtocol; | ||||
|         } | ||||
| 
 | ||||
|         const otherSites: Record<string, CoreSiteBasicInfoWithUsage[]> = {}; | ||||
| 
 | ||||
|         // Get space usage.
 | ||||
|         await Promise.all(this.sites.map(async (site) => { | ||||
|             const siteInfo = await settingsHelper.getSiteSpaceUsage(site.id); | ||||
|         sitesWithUsage.forEach((siteWithUsage) => { | ||||
|             totalSize += siteWithUsage.spaceUsage || 0; | ||||
| 
 | ||||
|             site.cacheEntries = siteInfo.cacheEntries; | ||||
|             site.spaceUsage = siteInfo.spaceUsage; | ||||
|             if (siteWithUsage.siteUrlWithoutProtocol === siteUrl) { | ||||
|                 this.accountsList.sameSite.push(siteWithUsage); | ||||
|             } else { | ||||
|                 if (otherSites[siteWithUsage.siteUrlWithoutProtocol] === undefined) { | ||||
|                     otherSites[siteWithUsage.siteUrlWithoutProtocol] = []; | ||||
|                 } | ||||
| 
 | ||||
|             totalSize += site.spaceUsage || 0; | ||||
|             totalEntries += site.cacheEntries || 0; | ||||
|         })); | ||||
|                 otherSites[siteWithUsage.siteUrlWithoutProtocol].push(siteWithUsage); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         this.totals.spaceUsage = totalSize; | ||||
|         this.totals.cacheEntries = totalEntries; | ||||
|         this.accountsList.otherSites = CoreUtils.objectToArray(otherSites); | ||||
| 
 | ||||
|         this.totalSpaceUsage = totalSize; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get site with space usage. | ||||
|      * | ||||
|      * @param site Site to check. | ||||
|      * @return Site with usage. | ||||
|      */ | ||||
|     protected async getSiteWithUsage(site: CoreSiteBasicInfo): Promise<CoreSiteBasicInfoWithUsage> { | ||||
|         const siteInfo = await CoreSettingsHelper.getSiteSpaceUsage(site.id); | ||||
| 
 | ||||
|         return Object.assign(site, { | ||||
|             hasCacheEntries: siteInfo.cacheEntries > 0, | ||||
|             spaceUsage: siteInfo.spaceUsage, | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Refresh the data. | ||||
|      * | ||||
|      * @param event Refresher event. | ||||
|      * @param refresher Refresher event. | ||||
|      */ | ||||
|     refreshData(refresher?: IonRefresher): void { | ||||
|         this.loadSiteData().finally(() => { | ||||
| @ -117,21 +167,20 @@ export class CoreSettingsSpaceUsagePage implements OnInit, OnDestroy { | ||||
|         try { | ||||
|             const newInfo = await CoreSettingsHelper.deleteSiteStorage(siteData.siteName || '', siteData.id); | ||||
| 
 | ||||
|             this.totals.spaceUsage -= siteData.spaceUsage! - newInfo.spaceUsage; | ||||
|             this.totals.spaceUsage -= siteData.cacheEntries! - newInfo.cacheEntries; | ||||
|             this.totalSpaceUsage -= siteData.spaceUsage - newInfo.spaceUsage; | ||||
| 
 | ||||
|             siteData.spaceUsage = newInfo.spaceUsage; | ||||
|             siteData.cacheEntries = newInfo.cacheEntries; | ||||
|             siteData.hasCacheEntries = newInfo.cacheEntries > 0; | ||||
|         } catch { | ||||
|             // Ignore cancelled confirmation modal.
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Page destroyed. | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     ngOnDestroy(): void { | ||||
|         this.sitesObserver?.off(); | ||||
|         this.sitesObserver.off(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -139,7 +188,16 @@ export class CoreSettingsSpaceUsagePage implements OnInit, OnDestroy { | ||||
| /** | ||||
|  * Basic site info with space usage and cache entries that can be erased. | ||||
|  */ | ||||
| export interface CoreSiteBasicInfoWithUsage extends CoreSiteBasicInfo { | ||||
|     cacheEntries?: number; // Number of cached entries that can be cleared.
 | ||||
|     spaceUsage?: number; // Space used in this site.
 | ||||
| interface CoreSiteBasicInfoWithUsage extends CoreSiteBasicInfo { | ||||
|     hasCacheEntries: boolean; // If has cached entries that can be cleared.
 | ||||
|     spaceUsage: number; // Space used in this site.
 | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Accounts list for selecting sites interfaces. | ||||
|  */ | ||||
| type CoreAccountsListWithUsage = { | ||||
|     currentSite?: CoreSiteBasicInfoWithUsage; // If logged in, current site info.
 | ||||
|     sameSite: CoreSiteBasicInfoWithUsage[]; // If logged in, accounts info on the same site.
 | ||||
|     otherSites: CoreSiteBasicInfoWithUsage[][]; // Other accounts in other sites.
 | ||||
| }; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user