MOBILE-3631 core: Add missing split views
parent
2da305bee8
commit
ec97894f74
|
@ -13,7 +13,13 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
import { Route, RouterModule, Routes } from '@angular/router';
|
||||||
|
|
||||||
|
|
||||||
|
export const AddonBadgesIssueRoute: Route = {
|
||||||
|
path: 'issue',
|
||||||
|
loadChildren: () => import('./pages/issued-badge/issued-badge.module').then( m => m.AddonBadgesIssuedBadgePageModule),
|
||||||
|
};
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
|
@ -21,10 +27,7 @@ const routes: Routes = [
|
||||||
redirectTo: 'user',
|
redirectTo: 'user',
|
||||||
pathMatch: 'full',
|
pathMatch: 'full',
|
||||||
},
|
},
|
||||||
{
|
AddonBadgesIssueRoute,
|
||||||
path: 'issue',
|
|
||||||
loadChildren: () => import('./pages/issued-badge/issued-badge.module').then( m => m.AddonBadgesIssuedBadgePageModule),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'user',
|
path: 'user',
|
||||||
loadChildren: () => import('./pages/user-badges/user-badges.module').then( m => m.AddonBadgesUserBadgesPageModule),
|
loadChildren: () => import('./pages/user-badges/user-badges.module').then( m => m.AddonBadgesUserBadgesPageModule),
|
||||||
|
|
|
@ -22,6 +22,7 @@ import { AddonBadges, AddonBadgesUserBadge } from '../../services/badges';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreCourses, CoreEnrolledCourseData } from '@features/courses/services/courses';
|
import { CoreCourses, CoreEnrolledCourseData } from '@features/courses/services/courses';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays the list of calendar events.
|
* Page that displays the list of calendar events.
|
||||||
|
@ -42,10 +43,17 @@ export class AddonBadgesIssuedBadgePage implements OnInit {
|
||||||
badgeLoaded = false;
|
badgeLoaded = false;
|
||||||
currentTime = 0;
|
currentTime = 0;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected route: ActivatedRoute,
|
||||||
|
) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View loaded.
|
* View loaded.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.route.queryParams.subscribe(() => {
|
||||||
|
this.badgeLoaded = false;
|
||||||
|
|
||||||
this.courseId = CoreNavigator.instance.getRouteNumberParam('courseId') || this.courseId; // Use 0 for site badges.
|
this.courseId = CoreNavigator.instance.getRouteNumberParam('courseId') || this.courseId; // Use 0 for site badges.
|
||||||
this.userId = CoreNavigator.instance.getRouteNumberParam('userId') || CoreSites.instance.getCurrentSite()!.getUserId();
|
this.userId = CoreNavigator.instance.getRouteNumberParam('userId') || CoreSites.instance.getCurrentSite()!.getUserId();
|
||||||
this.badgeHash = CoreNavigator.instance.getRouteParam('badgeHash') || '';
|
this.badgeHash = CoreNavigator.instance.getRouteParam('badgeHash') || '';
|
||||||
|
@ -53,6 +61,7 @@ export class AddonBadgesIssuedBadgePage implements OnInit {
|
||||||
this.fetchIssuedBadge().finally(() => {
|
this.fetchIssuedBadge().finally(() => {
|
||||||
this.badgeLoaded = true;
|
this.badgeLoaded = true;
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6,13 +6,14 @@
|
||||||
<ion-title>{{ 'addon.badges.badges' | translate }}</ion-title>
|
<ion-title>{{ 'addon.badges.badges' | translate }}</ion-title>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<!-- @todo <core-split-view>-->
|
|
||||||
<ion-content>
|
<ion-content>
|
||||||
|
<core-split-view>
|
||||||
<ion-refresher slot="fixed" [disabled]="!badgesLoaded" (ionRefresh)="refreshBadges($event)">
|
<ion-refresher slot="fixed" [disabled]="!badgesLoaded" (ionRefresh)="refreshBadges($event)">
|
||||||
<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]="badgesLoaded">
|
<core-loading [hideUntil]="badgesLoaded">
|
||||||
<core-empty-box *ngIf="!badges || badges.length == 0" icon="fas-trophy" [message]="'addon.badges.nobadges' | translate">
|
<core-empty-box *ngIf="!badges || badges.length == 0" icon="fas-trophy"
|
||||||
|
[message]="'addon.badges.nobadges' | translate">
|
||||||
</core-empty-box>
|
</core-empty-box>
|
||||||
|
|
||||||
<ion-list *ngIf="badges && badges.length" class="ion-no-margin">
|
<ion-list *ngIf="badges && badges.length" class="ion-no-margin">
|
||||||
|
@ -31,4 +32,5 @@
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
</core-loading>
|
</core-loading>
|
||||||
|
</core-split-view>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
|
@ -17,15 +17,34 @@ import { IonicModule } from '@ionic/angular';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { conditionalRoutes } from '@/app/app-routing.module';
|
||||||
|
import { CoreScreen } from '@services/screen';
|
||||||
|
|
||||||
import { CoreSharedModule } from '@/core/shared.module';
|
import { CoreSharedModule } from '@/core/shared.module';
|
||||||
import { AddonBadgesUserBadgesPage } from './user-badges.page';
|
import { AddonBadgesUserBadgesPage } from './user-badges.page';
|
||||||
|
import { AddonBadgesIssueRoute } from '@addons/badges/badges-lazy.module';
|
||||||
|
|
||||||
const routes: Routes = [
|
const mobileRoutes: Routes = [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: AddonBadgesUserBadgesPage,
|
component: AddonBadgesUserBadgesPage,
|
||||||
},
|
},
|
||||||
|
AddonBadgesIssueRoute,
|
||||||
|
];
|
||||||
|
|
||||||
|
const tabletRoutes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: AddonBadgesUserBadgesPage,
|
||||||
|
children: [
|
||||||
|
AddonBadgesIssueRoute,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
...conditionalRoutes(mobileRoutes, () => CoreScreen.instance.isMobile),
|
||||||
|
...conditionalRoutes(tabletRoutes, () => CoreScreen.instance.isTablet),
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
// @todo import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
import { CoreScreen } from '@services/screen';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays the list of calendar events.
|
* Page that displays the list of calendar events.
|
||||||
|
@ -31,8 +31,6 @@ import { CoreNavigator } from '@services/navigator';
|
||||||
})
|
})
|
||||||
export class AddonBadgesUserBadgesPage implements OnInit {
|
export class AddonBadgesUserBadgesPage implements OnInit {
|
||||||
|
|
||||||
// @ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent;
|
|
||||||
|
|
||||||
courseId = 0;
|
courseId = 0;
|
||||||
userId!: number;
|
userId!: number;
|
||||||
|
|
||||||
|
@ -50,11 +48,10 @@ export class AddonBadgesUserBadgesPage implements OnInit {
|
||||||
this.userId = CoreNavigator.instance.getRouteNumberParam('userId') || CoreSites.instance.getCurrentSite()!.getUserId();
|
this.userId = CoreNavigator.instance.getRouteNumberParam('userId') || CoreSites.instance.getCurrentSite()!.getUserId();
|
||||||
|
|
||||||
this.fetchBadges().finally(() => {
|
this.fetchBadges().finally(() => {
|
||||||
// @todo splitview
|
if (!this.badgeHash && CoreScreen.instance.isTablet && this.badges.length > 0) {
|
||||||
/* if (!this.badgeHash && this.splitviewCtrl.isOn() && this.badges.length > 0) {
|
|
||||||
// Take first and load it.
|
// Take first and load it.
|
||||||
this.loadIssuedBadge(this.badges[0].uniquehash);
|
this.loadIssuedBadge(this.badges[0].uniquehash);
|
||||||
}*/
|
}
|
||||||
this.badgesLoaded = true;
|
this.badgesLoaded = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -99,9 +96,11 @@ export class AddonBadgesUserBadgesPage implements OnInit {
|
||||||
loadIssuedBadge(badgeHash: string): void {
|
loadIssuedBadge(badgeHash: string): void {
|
||||||
this.badgeHash = badgeHash;
|
this.badgeHash = badgeHash;
|
||||||
const params = { courseId: this.courseId, userId: this.userId, badgeHash: badgeHash };
|
const params = { courseId: this.courseId, userId: this.userId, badgeHash: badgeHash };
|
||||||
// @todo use splitview.
|
|
||||||
// this.splitviewCtrl.push('AddonBadgesIssuedBadgePage', params);
|
const splitViewLoaded = CoreNavigator.instance.isCurrentPathInTablet('**/badges/user/issue');
|
||||||
CoreNavigator.instance.navigateToSitePath('/badges/issue', { params });
|
const path = (splitViewLoaded ? '../' : '') + 'issue';
|
||||||
|
|
||||||
|
CoreNavigator.instance.navigate(path, { params });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,21 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Injector, NgModule } from '@angular/core';
|
import { Injector, NgModule } from '@angular/core';
|
||||||
import { RouterModule, ROUTES, Routes } from '@angular/router';
|
import { Route, RouterModule, ROUTES, Routes } from '@angular/router';
|
||||||
|
|
||||||
import { buildTabMainRoutes } from '@features/mainmenu/mainmenu-tab-routing.module';
|
import { buildTabMainRoutes } from '@features/mainmenu/mainmenu-tab-routing.module';
|
||||||
|
|
||||||
|
export const AddonCalendarEditRoute: Route = {
|
||||||
|
path: 'edit',
|
||||||
|
loadChildren: () =>
|
||||||
|
import('@/addons/calendar/pages/edit-event/edit-event.module').then(m => m.AddonCalendarEditEventPageModule),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AddonCalendarEventRoute: Route ={
|
||||||
|
path: 'event',
|
||||||
|
loadChildren: () => import('@/addons/calendar/pages/event/event.module').then(m => m.AddonCalendarEventPageModule),
|
||||||
|
};
|
||||||
|
|
||||||
function buildRoutes(injector: Injector): Routes {
|
function buildRoutes(injector: Injector): Routes {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
@ -37,16 +48,8 @@ function buildRoutes(injector: Injector): Routes {
|
||||||
loadChildren: () =>
|
loadChildren: () =>
|
||||||
import('@/addons/calendar/pages/day/day.module').then(m => m.AddonCalendarDayPageModule),
|
import('@/addons/calendar/pages/day/day.module').then(m => m.AddonCalendarDayPageModule),
|
||||||
},
|
},
|
||||||
{
|
AddonCalendarEventRoute,
|
||||||
path: 'event',
|
AddonCalendarEditRoute,
|
||||||
loadChildren: () =>
|
|
||||||
import('@/addons/calendar/pages/event/event.module').then(m => m.AddonCalendarEventPageModule),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'edit',
|
|
||||||
loadChildren: () =>
|
|
||||||
import('@/addons/calendar/pages/edit-event/edit-event.module').then(m => m.AddonCalendarEditEventPageModule),
|
|
||||||
},
|
|
||||||
...buildTabMainRoutes(injector, {
|
...buildTabMainRoutes(injector, {
|
||||||
redirectTo: 'index',
|
redirectTo: 'index',
|
||||||
pathMatch: 'full',
|
pathMatch: 'full',
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// 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 { Component, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core';
|
import { Component, OnInit, OnDestroy, ViewChild, ElementRef, Optional } from '@angular/core';
|
||||||
import { FormControl, FormGroup, FormBuilder, Validators } from '@angular/forms';
|
import { FormControl, FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
import { IonRefresher } from '@ionic/angular';
|
import { IonRefresher } from '@ionic/angular';
|
||||||
import { CoreEvents } from '@singletons/events';
|
import { CoreEvents } from '@singletons/events';
|
||||||
|
@ -23,7 +23,7 @@ import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreTimeUtils } from '@services/utils/time';
|
import { CoreTimeUtils } from '@services/utils/time';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreCategoryData, CoreCourses, CoreCourseSearchedData, CoreEnrolledCourseData } from '@features/courses/services/courses';
|
import { CoreCategoryData, CoreCourses, CoreCourseSearchedData, CoreEnrolledCourseData } from '@features/courses/services/courses';
|
||||||
// @todo import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||||
import { CoreEditorRichTextEditorComponent } from '@features/editor/components/rich-text-editor/rich-text-editor.ts';
|
import { CoreEditorRichTextEditorComponent } from '@features/editor/components/rich-text-editor/rich-text-editor.ts';
|
||||||
import {
|
import {
|
||||||
AddonCalendarProvider,
|
AddonCalendarProvider,
|
||||||
|
@ -91,6 +91,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected fb: FormBuilder,
|
protected fb: FormBuilder,
|
||||||
|
@Optional() protected svComponent: CoreSplitViewComponent,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
this.currentSite = CoreSites.instance.getCurrentSite()!;
|
this.currentSite = CoreSites.instance.getCurrentSite()!;
|
||||||
|
@ -569,15 +570,16 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if (this.svComponent && this.svComponent.isOn()) {
|
if (this.svComponent?.isOn()) {
|
||||||
// Empty form.
|
// Empty form.
|
||||||
this.hasOffline = false;
|
this.hasOffline = false;
|
||||||
this.form.reset(this.originalData);
|
this.form.reset(this.originalData);
|
||||||
this.originalData = CoreUtils.instance.clone(this.form.value);
|
this.originalData = CoreUtils.instance.clone(this.form.value);
|
||||||
} else {*/
|
} else {
|
||||||
this.originalData = undefined; // Avoid asking for confirmation.
|
this.originalData = undefined; // Avoid asking for confirmation.
|
||||||
CoreNavigator.instance.back();
|
CoreNavigator.instance.back();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Discard an offline saved discussion.
|
* Discard an offline saved discussion.
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// 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 { Component, OnDestroy, OnInit } from '@angular/core';
|
import { Component, OnDestroy, OnInit, Optional } from '@angular/core';
|
||||||
import { IonRefresher } from '@ionic/angular';
|
import { IonRefresher } from '@ionic/angular';
|
||||||
import { AlertOptions } from '@ionic/core';
|
import { AlertOptions } from '@ionic/core';
|
||||||
import {
|
import {
|
||||||
|
@ -37,12 +37,14 @@ import { CoreLocalNotifications } from '@services/local-notifications';
|
||||||
import { CoreCourse } from '@features/course/services/course';
|
import { CoreCourse } from '@features/course/services/course';
|
||||||
import { CoreTimeUtils } from '@services/utils/time';
|
import { CoreTimeUtils } from '@services/utils/time';
|
||||||
import { CoreGroups } from '@services/groups';
|
import { CoreGroups } from '@services/groups';
|
||||||
// @todo import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||||
import { Network, NgZone, Translate } from '@singletons';
|
import { Network, NgZone, Translate } from '@singletons';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { AddonCalendarReminderDBRecord } from '../../services/database/calendar';
|
import { AddonCalendarReminderDBRecord } from '../../services/database/calendar';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { CoreScreen } from '@services/screen';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays a single calendar event.
|
* Page that displays a single calendar event.
|
||||||
|
@ -85,11 +87,15 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
||||||
syncIcon = 'spinner'; // Sync icon.
|
syncIcon = 'spinner'; // Sync icon.
|
||||||
isSplitViewOn = false;
|
isSplitViewOn = false;
|
||||||
|
|
||||||
constructor() {
|
constructor(
|
||||||
|
@Optional() protected svComponent: CoreSplitViewComponent,
|
||||||
|
protected route: ActivatedRoute,
|
||||||
|
) {
|
||||||
|
|
||||||
this.notificationsEnabled = CoreLocalNotifications.instance.isAvailable();
|
this.notificationsEnabled = CoreLocalNotifications.instance.isAvailable();
|
||||||
this.siteHomeId = CoreSites.instance.getCurrentSiteHomeId();
|
this.siteHomeId = CoreSites.instance.getCurrentSiteHomeId();
|
||||||
this.currentSiteId = CoreSites.instance.getCurrentSiteId();
|
this.currentSiteId = CoreSites.instance.getCurrentSiteId();
|
||||||
// this.isSplitViewOn = this.svComponent && this.svComponent.isOn();
|
this.isSplitViewOn = this.svComponent?.isOn();
|
||||||
|
|
||||||
// Check if site supports editing and deleting. No need to check allowed types, event.canedit already does it.
|
// Check if site supports editing and deleting. No need to check allowed types, event.canedit already does it.
|
||||||
this.canEdit = AddonCalendar.instance.canEditEventsInSite();
|
this.canEdit = AddonCalendar.instance.canEditEventsInSite();
|
||||||
|
@ -145,6 +151,9 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
||||||
* View loaded.
|
* View loaded.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.route.queryParams.subscribe(() => {
|
||||||
|
this.eventLoaded = false;
|
||||||
|
|
||||||
const eventId = CoreNavigator.instance.getRouteNumberParam('id');
|
const eventId = CoreNavigator.instance.getRouteNumberParam('id');
|
||||||
if (!eventId) {
|
if (!eventId) {
|
||||||
CoreDomUtils.instance.showErrorModal('Event ID not supplied.');
|
CoreDomUtils.instance.showErrorModal('Event ID not supplied.');
|
||||||
|
@ -157,6 +166,7 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
||||||
this.syncIcon = 'spinner';
|
this.syncIcon = 'spinner';
|
||||||
|
|
||||||
this.fetchEvent();
|
this.fetchEvent();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -501,9 +511,9 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
||||||
CoreDomUtils.instance.showToast('addon.calendar.eventcalendareventdeleted', true, 3000);
|
CoreDomUtils.instance.showToast('addon.calendar.eventcalendareventdeleted', true, 3000);
|
||||||
|
|
||||||
// Event deleted, close the view.
|
// Event deleted, close the view.
|
||||||
/* if (!this.svComponent || !this.svComponent.isOn()) {
|
if (CoreScreen.instance.isMobile) {
|
||||||
this.navCtrl.pop();
|
CoreNavigator.instance.back();
|
||||||
}*/
|
}
|
||||||
} else {
|
} else {
|
||||||
// Event deleted in offline, just mark it as deleted.
|
// Event deleted in offline, just mark it as deleted.
|
||||||
this.event.deleted = true;
|
this.event.deleted = true;
|
||||||
|
@ -558,9 +568,9 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
||||||
CoreDomUtils.instance.showToast('addon.calendar.eventcalendareventdeleted', true, 3000);
|
CoreDomUtils.instance.showToast('addon.calendar.eventcalendareventdeleted', true, 3000);
|
||||||
|
|
||||||
// Event was deleted, close the view.
|
// Event was deleted, close the view.
|
||||||
/* if (!this.svComponent || !this.svComponent.isOn()) {
|
if (CoreScreen.instance.isMobile) {
|
||||||
this.navCtrl.pop();
|
CoreNavigator.instance.back();
|
||||||
}*/
|
}
|
||||||
} else if (data.events && (!isManual || data.source != 'event')) {
|
} else if (data.events && (!isManual || data.source != 'event')) {
|
||||||
const event = data.events.find((ev) => ev.id == this.eventId);
|
const event = data.events.find((ev) => ev.id == this.eventId);
|
||||||
|
|
||||||
|
|
|
@ -89,9 +89,9 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
|
||||||
this.currentSiteId = CoreSites.instance.getCurrentSiteId();
|
this.currentSiteId = CoreSites.instance.getCurrentSiteId();
|
||||||
|
|
||||||
// Listen for events added. When an event is added, reload the data.
|
// Listen for events added. When an event is added, reload the data.
|
||||||
this.newEventObserver = CoreEvents.on(
|
this.newEventObserver = CoreEvents.on<AddonCalendarUpdatedEventEvent>(
|
||||||
AddonCalendarProvider.NEW_EVENT_EVENT,
|
AddonCalendarProvider.NEW_EVENT_EVENT,
|
||||||
(data: AddonCalendarUpdatedEventEvent) => {
|
(data) => {
|
||||||
if (data && data.eventId) {
|
if (data && data.eventId) {
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
this.refreshData(true, false);
|
this.refreshData(true, false);
|
||||||
|
@ -107,9 +107,9 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
|
||||||
}, this.currentSiteId);
|
}, this.currentSiteId);
|
||||||
|
|
||||||
// Listen for events edited. When an event is edited, reload the data.
|
// Listen for events edited. When an event is edited, reload the data.
|
||||||
this.editEventObserver = CoreEvents.on(
|
this.editEventObserver = CoreEvents.on<AddonCalendarUpdatedEventEvent>(
|
||||||
AddonCalendarProvider.EDIT_EVENT_EVENT,
|
AddonCalendarProvider.EDIT_EVENT_EVENT,
|
||||||
(data: AddonCalendarUpdatedEventEvent) => {
|
(data) => {
|
||||||
if (data && data.eventId) {
|
if (data && data.eventId) {
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
this.refreshData(true, false);
|
this.refreshData(true, false);
|
||||||
|
@ -125,7 +125,7 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
|
||||||
}, this.currentSiteId);
|
}, this.currentSiteId);
|
||||||
|
|
||||||
// Refresh data if calendar events are synchronized manually but not by this page.
|
// Refresh data if calendar events are synchronized manually but not by this page.
|
||||||
this.manualSyncObserver = CoreEvents.on(AddonCalendarSyncProvider.MANUAL_SYNCED, (data: AddonCalendarSyncEvents) => {
|
this.manualSyncObserver = CoreEvents.on<AddonCalendarSyncEvents>(AddonCalendarSyncProvider.MANUAL_SYNCED, (data) => {
|
||||||
if (data && data.source != 'index') {
|
if (data && data.source != 'index') {
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
this.refreshData(false, false);
|
this.refreshData(false, false);
|
||||||
|
@ -143,9 +143,9 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
|
||||||
this.hasOffline = await AddonCalendarOffline.instance.hasOfflineData();
|
this.hasOffline = await AddonCalendarOffline.instance.hasOfflineData();
|
||||||
}, this.currentSiteId);
|
}, this.currentSiteId);
|
||||||
|
|
||||||
this.filterChangedObserver = CoreEvents.on(
|
this.filterChangedObserver = CoreEvents.on<AddonCalendarFilter>(
|
||||||
AddonCalendarProvider.FILTER_CHANGED_EVENT,
|
AddonCalendarProvider.FILTER_CHANGED_EVENT,
|
||||||
async (filterData: AddonCalendarFilter) => {
|
async (filterData) => {
|
||||||
this.filter = filterData;
|
this.filter = filterData;
|
||||||
|
|
||||||
// Course viewed has changed, check if the user can create events for this course calendar.
|
// Course viewed has changed, check if the user can create events for this course calendar.
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<!--<core-split-view>-->
|
<ion-content>
|
||||||
<ion-content>
|
<core-split-view>
|
||||||
<ion-refresher slot="fixed" [disabled]="!eventsLoaded" (ionRefresh)="doRefresh($event)">
|
<ion-refresher slot="fixed" [disabled]="!eventsLoaded" (ionRefresh)="doRefresh($event)">
|
||||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
|
@ -86,5 +86,5 @@
|
||||||
<ion-icon name="fas-plus"></ion-icon>
|
<ion-icon name="fas-plus"></ion-icon>
|
||||||
</ion-fab-button>
|
</ion-fab-button>
|
||||||
</ion-fab>
|
</ion-fab>
|
||||||
</ion-content>
|
</core-split-view>
|
||||||
<!--</core-split-view>-->
|
</ion-content>
|
||||||
|
|
|
@ -17,18 +17,40 @@ import { IonicModule } from '@ionic/angular';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { AddonCalendarEventRoute, AddonCalendarEditRoute } from '@addons/calendar/calendar-lazy.module';
|
||||||
|
import { conditionalRoutes } from '@/app/app-routing.module';
|
||||||
|
import { CoreScreen } from '@services/screen';
|
||||||
|
|
||||||
import { CoreSharedModule } from '@/core/shared.module';
|
import { CoreSharedModule } from '@/core/shared.module';
|
||||||
|
|
||||||
import { AddonCalendarListPage } from './list.page';
|
import { AddonCalendarListPage } from './list.page';
|
||||||
|
|
||||||
const routes: Routes = [
|
const splitviewRoutes = [AddonCalendarEditRoute, AddonCalendarEventRoute];
|
||||||
|
|
||||||
|
const mobileRoutes: Routes = [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: AddonCalendarListPage,
|
component: AddonCalendarListPage,
|
||||||
},
|
},
|
||||||
|
...splitviewRoutes,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const tabletRoutes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: AddonCalendarListPage,
|
||||||
|
children: [
|
||||||
|
...splitviewRoutes,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
...conditionalRoutes(mobileRoutes, () => CoreScreen.instance.isMobile),
|
||||||
|
...conditionalRoutes(tabletRoutes, () => CoreScreen.instance.isTablet),
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule.forChild(routes),
|
RouterModule.forChild(routes),
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { CoreSites } from '@services/sites';
|
||||||
import { CoreLocalNotifications } from '@services/local-notifications';
|
import { CoreLocalNotifications } from '@services/local-notifications';
|
||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
import { CoreApp } from '@services/app';
|
import { CoreApp } from '@services/app';
|
||||||
// @todo import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { CoreConstants } from '@/core/constants';
|
import { CoreConstants } from '@/core/constants';
|
||||||
import { AddonCalendarFilterPopoverComponent } from '../../components/filter/filter';
|
import { AddonCalendarFilterPopoverComponent } from '../../components/filter/filter';
|
||||||
|
@ -52,7 +52,7 @@ import { CoreNavigator } from '@services/navigator';
|
||||||
export class AddonCalendarListPage implements OnInit, OnDestroy {
|
export class AddonCalendarListPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
@ViewChild(IonContent) content?: IonContent;
|
@ViewChild(IonContent) content?: IonContent;
|
||||||
// @ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent;
|
@ViewChild(CoreSplitViewComponent) splitviewCtrl?: CoreSplitViewComponent;
|
||||||
|
|
||||||
protected initialTime = 0;
|
protected initialTime = 0;
|
||||||
protected daysLoaded = 0;
|
protected daysLoaded = 0;
|
||||||
|
@ -117,30 +117,28 @@ export class AddonCalendarListPage implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for events added. When an event is added, reload the data.
|
// Listen for events added. When an event is added, reload the data.
|
||||||
this.newEventObserver = CoreEvents.on(AddonCalendarProvider.NEW_EVENT_EVENT, (data: AddonCalendarUpdatedEventEvent) => {
|
this.newEventObserver = CoreEvents.on<AddonCalendarUpdatedEventEvent>(AddonCalendarProvider.NEW_EVENT_EVENT, (data) => {
|
||||||
if (data && data.eventId) {
|
if (data && data.eventId) {
|
||||||
/* if (this.splitviewCtrl.isOn()) {
|
|
||||||
// Discussion added, clear details page.
|
|
||||||
this.splitviewCtrl.emptyDetails();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
this.eventsLoaded = false;
|
this.eventsLoaded = false;
|
||||||
this.refreshEvents(true, false).finally(() => {
|
this.refreshEvents(true, false).finally(() => {
|
||||||
|
|
||||||
// In tablet mode try to open the event (only if it's an online event).
|
// In tablet mode try to open the event (only if it's an online event).
|
||||||
/* if (this.splitviewCtrl.isOn() && data.event.id > 0) {
|
if (this.splitviewCtrl?.isOn() && data.eventId > 0) {
|
||||||
this.gotoEvent(data.event.id);
|
this.gotoEvent(data.eventId);
|
||||||
}*/
|
} else if (this.splitviewCtrl?.isOn()) {
|
||||||
|
// Discussion added, clear details page.
|
||||||
|
this.emptySplitView();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, this.currentSiteId);
|
}, this.currentSiteId);
|
||||||
|
|
||||||
// Listen for new event discarded event. When it does, reload the data.
|
// Listen for new event discarded event. When it does, reload the data.
|
||||||
this.discardedObserver = CoreEvents.on(AddonCalendarProvider.NEW_EVENT_DISCARDED_EVENT, () => {
|
this.discardedObserver = CoreEvents.on(AddonCalendarProvider.NEW_EVENT_DISCARDED_EVENT, () => {
|
||||||
/* if (this.splitviewCtrl.isOn()) {
|
if (this.splitviewCtrl?.isOn()) {
|
||||||
// Discussion added, clear details page.
|
// Discussion added, clear details page.
|
||||||
this.splitviewCtrl.emptyDetails();
|
this.emptySplitView();
|
||||||
}*/
|
}
|
||||||
|
|
||||||
this.eventsLoaded = false;
|
this.eventsLoaded = false;
|
||||||
this.refreshEvents(true, false);
|
this.refreshEvents(true, false);
|
||||||
|
@ -155,14 +153,14 @@ export class AddonCalendarListPage implements OnInit, OnDestroy {
|
||||||
}, this.currentSiteId);
|
}, this.currentSiteId);
|
||||||
|
|
||||||
// Refresh data if calendar events are synchronized automatically.
|
// Refresh data if calendar events are synchronized automatically.
|
||||||
this.syncObserver = CoreEvents.on(AddonCalendarSyncProvider.AUTO_SYNCED, () => {
|
this.syncObserver = CoreEvents.on<AddonCalendarSyncEvents>(AddonCalendarSyncProvider.AUTO_SYNCED, (data) => {
|
||||||
this.eventsLoaded = false;
|
this.eventsLoaded = false;
|
||||||
this.refreshEvents();
|
this.refreshEvents();
|
||||||
|
|
||||||
/* if (this.splitviewCtrl.isOn() && this.eventId && data && data.deleted && data.deleted.indexOf(this.eventId) != -1) {
|
if (this.splitviewCtrl?.isOn() && this.eventId && data && data.deleted && data.deleted.indexOf(this.eventId) != -1) {
|
||||||
// Current selected event was deleted. Clear details.
|
// Current selected event was deleted. Clear details.
|
||||||
this.splitviewCtrl.emptyDetails();
|
this.emptySplitView();
|
||||||
} */
|
}
|
||||||
}, this.currentSiteId);
|
}, this.currentSiteId);
|
||||||
|
|
||||||
// Refresh data if calendar events are synchronized manually but not by this page.
|
// Refresh data if calendar events are synchronized manually but not by this page.
|
||||||
|
@ -172,10 +170,10 @@ export class AddonCalendarListPage implements OnInit, OnDestroy {
|
||||||
this.refreshEvents();
|
this.refreshEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if (this.splitviewCtrl.isOn() && this.eventId && data && data.deleted && data.deleted.indexOf(this.eventId) != -1) {
|
if (this.splitviewCtrl?.isOn() && this.eventId && data && data.deleted && data.deleted.indexOf(this.eventId) != -1) {
|
||||||
// Current selected event was deleted. Clear details.
|
// Current selected event was deleted. Clear details.
|
||||||
this.splitviewCtrl.emptyDetails();
|
this.emptySplitView();
|
||||||
}*/
|
}
|
||||||
}, this.currentSiteId);
|
}, this.currentSiteId);
|
||||||
|
|
||||||
// Update the list when an event is deleted.
|
// Update the list when an event is deleted.
|
||||||
|
@ -189,9 +187,9 @@ export class AddonCalendarListPage implements OnInit, OnDestroy {
|
||||||
this.hasOffline = true;
|
this.hasOffline = true;
|
||||||
} else {
|
} else {
|
||||||
// Event deleted, clear the details if needed and refresh the view.
|
// Event deleted, clear the details if needed and refresh the view.
|
||||||
/* if (this.splitviewCtrl.isOn()) {
|
if (this.splitviewCtrl?.isOn()) {
|
||||||
this.splitviewCtrl.emptyDetails();
|
this.emptySplitView();
|
||||||
} */
|
}
|
||||||
|
|
||||||
this.eventsLoaded = false;
|
this.eventsLoaded = false;
|
||||||
this.refreshEvents();
|
this.refreshEvents();
|
||||||
|
@ -259,14 +257,26 @@ export class AddonCalendarListPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
await this.fetchData(false, true, false);
|
await this.fetchData(false, true, false);
|
||||||
|
|
||||||
/* if (!this.eventId && this.splitviewCtrl.isOn() && this.events.length > 0) {
|
if (!this.eventId && this.splitviewCtrl?.isOn() && this.events.length > 0) {
|
||||||
// Take first online event and load it. If no online event, load the first offline.
|
// Take first online event and load it. If no online event, load the first offline.
|
||||||
if (this.onlineEvents[0]) {
|
if (this.onlineEvents[0]) {
|
||||||
this.gotoEvent(this.onlineEvents[0].id);
|
this.gotoEvent(this.onlineEvents[0].id);
|
||||||
} else {
|
} else {
|
||||||
this.gotoEvent(this.offlineEvents[0].id);
|
this.gotoEvent(this.offlineEvents[0].id);
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function to clear detail view of the split view.
|
||||||
|
*/
|
||||||
|
protected emptySplitView(): void {
|
||||||
|
// Empty details.
|
||||||
|
const splitViewLoaded = CoreNavigator.instance.isCurrentPathInTablet('**/calendar/list/event') ||
|
||||||
|
CoreNavigator.instance.isCurrentPathInTablet('**/calendar/list/edit');
|
||||||
|
if (splitViewLoaded) {
|
||||||
|
CoreNavigator.instance.navigate('../');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -642,7 +652,10 @@ export class AddonCalendarListPage implements OnInit, OnDestroy {
|
||||||
params.courseId = this.filter.courseId;
|
params.courseId = this.filter.courseId;
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreNavigator.instance.navigateToSitePath('/calendar/edit', { params }); // @todo , this.splitviewCtrl);
|
const splitViewLoaded = CoreNavigator.instance.isCurrentPathInTablet('**/calendar/list/event') ||
|
||||||
|
CoreNavigator.instance.isCurrentPathInTablet('**/calendar/list/edit');
|
||||||
|
const path = (splitViewLoaded ? '../' : '') + 'edit';
|
||||||
|
CoreNavigator.instance.navigate(path, { params });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -664,9 +677,12 @@ export class AddonCalendarListPage implements OnInit, OnDestroy {
|
||||||
// It's an offline event, go to the edit page.
|
// It's an offline event, go to the edit page.
|
||||||
this.openEdit(eventId);
|
this.openEdit(eventId);
|
||||||
} else {
|
} else {
|
||||||
/* this.splitviewCtrl.push('/calendar/event', {
|
const splitViewLoaded = CoreNavigator.instance.isCurrentPathInTablet('**/calendar/list/event') ||
|
||||||
|
CoreNavigator.instance.isCurrentPathInTablet('**/calendar/list/edit');
|
||||||
|
const path = (splitViewLoaded ? '../' : '') + 'event';
|
||||||
|
CoreNavigator.instance.navigate(path, { params: {
|
||||||
id: eventId,
|
id: eventId,
|
||||||
});*/
|
} });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import {
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { ModalController } from '@singletons';
|
import { ModalController } from '@singletons';
|
||||||
|
import { CoreNavigator } from '@services/navigator';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that displays the list of conversations, including group conversations.
|
* Component that displays the list of conversations, including group conversations.
|
||||||
|
@ -49,8 +50,8 @@ export class AddonMessagesConversationInfoComponent implements OnInit {
|
||||||
* Component loaded.
|
* Component loaded.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.route.queryParams.subscribe(async params => {
|
this.route.queryParams.subscribe(async () => {
|
||||||
this.conversationId = parseInt(params['conversationId'], 10);
|
this.conversationId = CoreNavigator.instance.getRouteNumberParam('conversationId') || 0;
|
||||||
|
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
this.fetchData().finally(() => {
|
this.fetchData().finally(() => {
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { Route, RouterModule, ROUTES, Routes } from '@angular/router';
|
||||||
import { buildTabMainRoutes } from '@features/mainmenu/mainmenu-tab-routing.module';
|
import { buildTabMainRoutes } from '@features/mainmenu/mainmenu-tab-routing.module';
|
||||||
import { AddonMessagesSettingsHandlerService } from './services/handlers/settings';
|
import { AddonMessagesSettingsHandlerService } from './services/handlers/settings';
|
||||||
|
|
||||||
export const discussionRoute: Route = {
|
export const AddonMessagesDiscussionRoute: Route = {
|
||||||
path: 'discussion',
|
path: 'discussion',
|
||||||
loadChildren: () => import('./pages/discussion/discussion.module')
|
loadChildren: () => import('./pages/discussion/discussion.module')
|
||||||
.then(m => m.AddonMessagesDiscussionPageModule),
|
.then(m => m.AddonMessagesDiscussionPageModule),
|
||||||
|
@ -40,7 +40,7 @@ function buildRoutes(injector: Injector): Routes {
|
||||||
loadChildren: () => import('./pages/group-conversations/group-conversations.module')
|
loadChildren: () => import('./pages/group-conversations/group-conversations.module')
|
||||||
.then(m => m.AddonMessagesGroupConversationsPageModule),
|
.then(m => m.AddonMessagesGroupConversationsPageModule),
|
||||||
},
|
},
|
||||||
discussionRoute,
|
AddonMessagesDiscussionRoute,
|
||||||
{
|
{
|
||||||
path: 'search',
|
path: 'search',
|
||||||
loadChildren: () => import('./pages/search/search.module')
|
loadChildren: () => import('./pages/search/search.module')
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
<ion-title>{{ 'addon.messages.contacts' | translate }}</ion-title>
|
<ion-title>{{ 'addon.messages.contacts' | translate }}</ion-title>
|
||||||
<ion-buttons slot="end">
|
<ion-buttons slot="end">
|
||||||
<!-- Add an empty context menu so discussion page can add items in split view, otherwise the menu disappears in some cases. -->
|
<!-- Add an empty context menu so discussion page can add items in split view,
|
||||||
|
otherwise the menu disappears in some cases. -->
|
||||||
<core-context-menu></core-context-menu>
|
<core-context-menu></core-context-menu>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
|
@ -16,7 +17,7 @@
|
||||||
<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-search-box (onSubmit)="search($event)" (onClear)="clearSearch($event)"
|
<core-search-box (onSubmit)="search($event)" (onClear)="clearSearch()"
|
||||||
[placeholder]="'addon.messages.contactname' | translate" autocorrect="off" spellcheck="false" lengthCheck="2"
|
[placeholder]="'addon.messages.contactname' | translate" autocorrect="off" spellcheck="false" lengthCheck="2"
|
||||||
[disabled]="!loaded" searchArea="AddonMessagesContacts"></core-search-box>
|
[disabled]="!loaded" searchArea="AddonMessagesContacts"></core-search-box>
|
||||||
|
|
||||||
|
@ -35,7 +36,8 @@
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
<ng-container *ngFor="let contact of contacts[contactType]">
|
<ng-container *ngFor="let contact of contacts[contactType]">
|
||||||
<!-- Don't show deleted users -->
|
<!-- Don't show deleted users -->
|
||||||
<ion-item class="ion-text-wrap addon-messages-conversation-item" *ngIf="contact.profileimageurl || contact.profileimageurlsmall"
|
<ion-item class="ion-text-wrap addon-messages-conversation-item"
|
||||||
|
*ngIf="contact.profileimageurl || contact.profileimageurlsmall"
|
||||||
[title]="contact.fullname" (click)="gotoDiscussion(contact.id)" detail
|
[title]="contact.fullname" (click)="gotoDiscussion(contact.id)" detail
|
||||||
[class.core-selected-item]="contact.id == discussionUserId">
|
[class.core-selected-item]="contact.id == discussionUserId">
|
||||||
<core-user-avatar [user]="contact" slot="start" [checkOnline]="contact.showonlinestatus"></core-user-avatar>
|
<core-user-avatar [user]="contact" slot="start" [checkOnline]="contact.showonlinestatus"></core-user-avatar>
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { conditionalRoutes } from '@/app/app-routing.module';
|
import { conditionalRoutes } from '@/app/app-routing.module';
|
||||||
import { discussionRoute } from '@addons/messages/messages-lazy.module';
|
import { AddonMessagesDiscussionRoute } from '@addons/messages/messages-lazy.module';
|
||||||
import { CoreScreen } from '@services/screen';
|
import { CoreScreen } from '@services/screen';
|
||||||
|
|
||||||
import { CoreSharedModule } from '@/core/shared.module';
|
import { CoreSharedModule } from '@/core/shared.module';
|
||||||
|
@ -26,23 +26,27 @@ import { CoreSearchComponentsModule } from '@features/search/components/componen
|
||||||
|
|
||||||
import { AddonMessagesContacts35Page } from './contacts.page';
|
import { AddonMessagesContacts35Page } from './contacts.page';
|
||||||
|
|
||||||
const routes: Routes = [
|
const mobileRoutes: Routes = [
|
||||||
{
|
|
||||||
matcher: segments => {
|
|
||||||
const matches = CoreScreen.instance.isMobile ? segments.length === 0 : true;
|
|
||||||
|
|
||||||
return matches ? { consumed: [] } : null;
|
|
||||||
},
|
|
||||||
component: AddonMessagesContacts35Page,
|
|
||||||
children: conditionalRoutes([
|
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
pathMatch: 'full',
|
component: AddonMessagesContacts35Page,
|
||||||
},
|
},
|
||||||
discussionRoute,
|
AddonMessagesDiscussionRoute,
|
||||||
], () => CoreScreen.instance.isTablet),
|
];
|
||||||
|
|
||||||
|
const tabletRoutes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: AddonMessagesContacts35Page,
|
||||||
|
children: [
|
||||||
|
AddonMessagesDiscussionRoute,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
...conditionalRoutes([discussionRoute], () => CoreScreen.instance.isMobile),
|
];
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
...conditionalRoutes(mobileRoutes, () => CoreScreen.instance.isMobile),
|
||||||
|
...conditionalRoutes(tabletRoutes, () => CoreScreen.instance.isTablet),
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -87,10 +87,9 @@ export class AddonMessagesContacts35Page implements OnInit, OnDestroy {
|
||||||
* Component loaded.
|
* Component loaded.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.route.queryParams.subscribe(async params => {
|
this.route.queryParams.subscribe(async () => {
|
||||||
const discussionUserId = params['discussionUserId']
|
const discussionUserId = CoreNavigator.instance.getRouteNumberParam('discussionUserId') ||
|
||||||
? parseInt(params['discussionUserId'], 10)
|
CoreNavigator.instance.getRouteNumberParam('userId') || undefined;
|
||||||
: (params['userId'] ? parseInt(params['userId'], 10) : undefined);
|
|
||||||
|
|
||||||
if (this.loaded && this.discussionUserId == discussionUserId) {
|
if (this.loaded && this.discussionUserId == discussionUserId) {
|
||||||
return;
|
return;
|
||||||
|
@ -250,7 +249,7 @@ export class AddonMessagesContacts35Page implements OnInit, OnDestroy {
|
||||||
userId: discussionUserId,
|
userId: discussionUserId,
|
||||||
};
|
};
|
||||||
|
|
||||||
const splitViewLoaded = CoreNavigator.instance.isSplitViewOutletLoaded('**/messages/contacts-35/discussion');
|
const splitViewLoaded = CoreNavigator.instance.isCurrentPathInTablet('**/messages/contacts-35/discussion');
|
||||||
const path = (splitViewLoaded ? '../' : '') + 'discussion';
|
const path = (splitViewLoaded ? '../' : '') + 'discussion';
|
||||||
|
|
||||||
// @todo Check why this is failing on ngInit.
|
// @todo Check why this is failing on ngInit.
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
<ion-button (click)="gotoSearch()" [attr.aria-label]="'addon.messages.search' | translate">
|
<ion-button (click)="gotoSearch()" [attr.aria-label]="'addon.messages.search' | translate">
|
||||||
<ion-icon name="fas-search" slot="icon-only"></ion-icon>
|
<ion-icon name="fas-search" slot="icon-only"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<!-- Add an empty context menu so discussion page can add items in split view, otherwise the menu disappears in some cases. -->
|
<!-- Add an empty context menu so discussion page can add items in split view, otherwise the menu
|
||||||
|
disappears in some cases. -->
|
||||||
<core-context-menu></core-context-menu>
|
<core-context-menu></core-context-menu>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
|
@ -17,10 +18,10 @@
|
||||||
<core-split-view>
|
<core-split-view>
|
||||||
<ion-tab-bar class="core-tabs-bar">
|
<ion-tab-bar class="core-tabs-bar">
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col class="tab-slide" [attr.aria-selected]="selected == 'confirmed'" (click)="selectTab('confirmed', $event)">
|
<ion-col class="tab-slide" [attr.aria-selected]="selected == 'confirmed'" (click)="selectTab('confirmed')">
|
||||||
<ion-label>{{ 'addon.messages.contacts' | translate}}</ion-label>
|
<ion-label>{{ 'addon.messages.contacts' | translate}}</ion-label>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
<ion-col class="tab-slide" [attr.aria-selected]="selected != 'confirmed'" (click)="selectTab('requests', $event)">
|
<ion-col class="tab-slide" [attr.aria-selected]="selected != 'confirmed'" (click)="selectTab('requests')">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
{{ 'addon.messages.requests' | translate}}
|
{{ 'addon.messages.requests' | translate}}
|
||||||
<ion-badge *ngIf="requestsBadge">{{ requestsBadge }}</ion-badge>
|
<ion-badge *ngIf="requestsBadge">{{ requestsBadge }}</ion-badge>
|
||||||
|
|
|
@ -18,32 +18,37 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { conditionalRoutes } from '@/app/app-routing.module';
|
import { conditionalRoutes } from '@/app/app-routing.module';
|
||||||
import { discussionRoute } from '@addons/messages/messages-lazy.module';
|
import { AddonMessagesDiscussionRoute } from '@addons/messages/messages-lazy.module';
|
||||||
import { CoreScreen } from '@services/screen';
|
import { CoreScreen } from '@services/screen';
|
||||||
|
|
||||||
import { CoreSharedModule } from '@/core/shared.module';
|
import { CoreSharedModule } from '@/core/shared.module';
|
||||||
|
|
||||||
import { AddonMessagesContactsPage } from './contacts.page';
|
import { AddonMessagesContactsPage } from './contacts.page';
|
||||||
|
|
||||||
const routes: Routes = [
|
const mobileRoutes: Routes = [
|
||||||
{
|
|
||||||
matcher: segments => {
|
|
||||||
const matches = CoreScreen.instance.isMobile ? segments.length === 0 : true;
|
|
||||||
|
|
||||||
return matches ? { consumed: [] } : null;
|
|
||||||
},
|
|
||||||
component: AddonMessagesContactsPage,
|
|
||||||
children: conditionalRoutes([
|
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
pathMatch: 'full',
|
component: AddonMessagesContactsPage,
|
||||||
},
|
},
|
||||||
discussionRoute,
|
AddonMessagesDiscussionRoute,
|
||||||
], () => CoreScreen.instance.isTablet),
|
|
||||||
},
|
|
||||||
...conditionalRoutes([discussionRoute], () => CoreScreen.instance.isMobile),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const tabletRoutes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: AddonMessagesContactsPage,
|
||||||
|
children: [
|
||||||
|
AddonMessagesDiscussionRoute,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
...conditionalRoutes(mobileRoutes, () => CoreScreen.instance.isMobile),
|
||||||
|
...conditionalRoutes(tabletRoutes, () => CoreScreen.instance.isTablet),
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule.forChild(routes),
|
RouterModule.forChild(routes),
|
||||||
|
|
|
@ -258,7 +258,7 @@ export class AddonMessagesContactsPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
this.selectedUserId = userId;
|
this.selectedUserId = userId;
|
||||||
|
|
||||||
const splitViewLoaded = CoreNavigator.instance.isSplitViewOutletLoaded('**/messages/contacts/discussion');
|
const splitViewLoaded = CoreNavigator.instance.isCurrentPathInTablet('**/messages/contacts/discussion');
|
||||||
const path = (splitViewLoaded ? '../' : '') + 'discussion';
|
const path = (splitViewLoaded ? '../' : '') + 'discussion';
|
||||||
|
|
||||||
CoreNavigator.instance.navigate(path, { params : { userId } });
|
CoreNavigator.instance.navigate(path, { params : { userId } });
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
</core-context-menu>
|
</core-context-menu>
|
||||||
</core-navbar-buttons>
|
</core-navbar-buttons>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content class="has-footer" (ionScroll)="scrollFunction($event)">
|
<ion-content class="has-footer" (ionScroll)="scrollFunction()">
|
||||||
<core-loading [hideUntil]="loaded" class="safe-area-page">
|
<core-loading [hideUntil]="loaded" class="safe-area-page">
|
||||||
<!-- Load previous messages. -->
|
<!-- Load previous messages. -->
|
||||||
<core-infinite-loading [enabled]="canLoadMore" (action)="loadPrevious($event)" position="top" [error]="loadMoreError">
|
<core-infinite-loading [enabled]="canLoadMore" (action)="loadPrevious($event)" position="top" [error]="loadMoreError">
|
||||||
|
@ -72,18 +72,24 @@
|
||||||
<p class="ion-text-center"><i>{{ 'addon.messages.selfconversationdefaultmessage' | translate }}</i></p>
|
<p class="ion-text-center"><i>{{ 'addon.messages.selfconversationdefaultmessage' | translate }}</i></p>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ion-list class="addon-messages-discussion-container" [class.addon-messages-discussion-group]="isGroup" [attr.aria-live]="'polite'">
|
<ion-list class="addon-messages-discussion-container" [class.addon-messages-discussion-group]="isGroup"
|
||||||
|
[attr.aria-live]="'polite'">
|
||||||
<ng-container *ngFor="let message of messages; index as index; last as last">
|
<ng-container *ngFor="let message of messages; index as index; last as last">
|
||||||
<h6 class="ion-text-center addon-messages-date" *ngIf="message.showDate">
|
<h6 class="ion-text-center addon-messages-date" *ngIf="message.showDate">
|
||||||
{{ message.timecreated | coreFormatDate: "strftimedayshort" }}
|
{{ message.timecreated | coreFormatDate: "strftimedayshort" }}
|
||||||
</h6>
|
</h6>
|
||||||
|
|
||||||
<ion-chip class="addon-messages-unreadfrom" *ngIf="unreadMessageFrom && message.id == unreadMessageFrom" color="light">
|
<ion-chip class="addon-messages-unreadfrom" *ngIf="unreadMessageFrom && message.id == unreadMessageFrom"
|
||||||
|
color="light">
|
||||||
<ion-label>{{ 'addon.messages.newmessages' | translate }}</ion-label>
|
<ion-label>{{ 'addon.messages.newmessages' | translate }}</ion-label>
|
||||||
<ion-icon name="arrow-round-down"></ion-icon>
|
<ion-icon name="arrow-round-down"></ion-icon>
|
||||||
</ion-chip>
|
</ion-chip>
|
||||||
|
|
||||||
<ion-item class="ion-text-wrap addon-message" (longPress)="copyMessage(message)" [class.addon-message-mine]="message.useridfrom == currentUserId" [class.addon-message-not-mine]="message.useridfrom != currentUserId" [class.addon-message-no-user]="!message.showUserData" [@coreSlideInOut]="message.useridfrom == currentUserId ? '' : 'fromLeft'">
|
<ion-item class="ion-text-wrap addon-message" (longPress)="copyMessage(message)"
|
||||||
|
[class.addon-message-mine]="message.useridfrom == currentUserId"
|
||||||
|
[class.addon-message-not-mine]="message.useridfrom != currentUserId"
|
||||||
|
[class.addon-message-no-user]="!message.showUserData"
|
||||||
|
[@coreSlideInOut]="message.useridfrom == currentUserId ? '' : 'fromLeft'">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<!-- User data. -->
|
<!-- User data. -->
|
||||||
<h2 class="addon-message-user">
|
<h2 class="addon-message-user">
|
||||||
|
@ -98,7 +104,8 @@
|
||||||
|
|
||||||
<!-- Some messages have <p> and some others don't. Add a <p> so they all have same styles. -->
|
<!-- Some messages have <p> and some others don't. Add a <p> so they all have same styles. -->
|
||||||
<p class="addon-message-text">
|
<p class="addon-message-text">
|
||||||
<core-format-text (afterRender)="last && scrollToBottom()" [text]="message.text" contextLevel="system" [contextInstanceId]="0"></core-format-text>
|
<core-format-text (afterRender)="last && scrollToBottom()" [text]="message.text" contextLevel="system"
|
||||||
|
[contextInstanceId]="0"></core-format-text>
|
||||||
</p>
|
</p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<ion-button fill="clear" *ngIf="!message.sending && showDelete" (click)="deleteMessage(message, index)"
|
<ion-button fill="clear" *ngIf="!message.sending && showDelete" (click)="deleteMessage(message, index)"
|
||||||
|
@ -112,11 +119,12 @@
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
|
|
||||||
<core-empty-box *ngIf="!messages || messages.length <= 0" icon="far-comments" [message]="'addon.messages.nomessagesfound' | translate"></core-empty-box>
|
<core-empty-box *ngIf="!messages || messages.length <= 0" icon="far-comments"
|
||||||
|
[message]="'addon.messages.nomessagesfound' | translate"></core-empty-box>
|
||||||
</core-loading>
|
</core-loading>
|
||||||
<!-- Scroll bottom. -->
|
<!-- Scroll bottom. -->
|
||||||
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="loaded && newMessages > 0">
|
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="loaded && newMessages > 0">
|
||||||
<ion-fab-button size="small" (click)="scrollToFirstUnreadMessage(true)" color="light"
|
<ion-fab-button size="small" (click)="scrollToFirstUnreadMessage()" color="light"
|
||||||
[attr.aria-label]="'addon.messages.newmessages' | translate">
|
[attr.aria-label]="'addon.messages.newmessages' | translate">
|
||||||
<ion-icon name="fas-arrow-down"></ion-icon>
|
<ion-icon name="fas-arrow-down"></ion-icon>
|
||||||
<span class="core-discussion-messages-badge">{{ newMessages }}</span>
|
<span class="core-discussion-messages-badge">{{ newMessages }}</span>
|
||||||
|
@ -125,24 +133,38 @@
|
||||||
</ion-content>
|
</ion-content>
|
||||||
<ion-footer color="light" class="footer-adjustable" *ngIf="loaded && (!conversationId || conversation)">
|
<ion-footer color="light" class="footer-adjustable" *ngIf="loaded && (!conversationId || conversation)">
|
||||||
<ion-toolbar color="light">
|
<ion-toolbar color="light">
|
||||||
<p *ngIf="footerType == 'unable'" class="ion-text-center ion-margin-horizontal">{{ 'addon.messages.unabletomessage' | translate }}</p>
|
<p *ngIf="footerType == 'unable'" class="ion-text-center ion-margin-horizontal">
|
||||||
|
{{ 'addon.messages.unabletomessage' | translate }}
|
||||||
|
</p>
|
||||||
<div *ngIf="footerType == 'blocked'" class="ion-padding-horizontal">
|
<div *ngIf="footerType == 'blocked'" class="ion-padding-horizontal">
|
||||||
<p class="ion-text-center">{{ 'addon.messages.youhaveblockeduser' | translate }}</p>
|
<p class="ion-text-center">{{ 'addon.messages.youhaveblockeduser' | translate }}</p>
|
||||||
<ion-button expand="block" class="ion-text-wrap ion-margin-bottom" (click)="unblockUser()">{{ 'addon.messages.unblockuser' | translate }}</ion-button>
|
<ion-button expand="block" class="ion-text-wrap ion-margin-bottom" (click)="unblockUser()">
|
||||||
|
{{ 'addon.messages.unblockuser' | translate }}
|
||||||
|
</ion-button>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="footerType == 'requiresContact'" class="ion-padding-horizontal">
|
<div *ngIf="footerType == 'requiresContact' && otherMember" class="ion-padding-horizontal">
|
||||||
<p class="ion-text-center"><strong>{{ 'addon.messages.isnotinyourcontacts' | translate: {$a: otherMember.fullname} }}</strong></p>
|
<p class="ion-text-center">
|
||||||
|
<strong>{{ 'addon.messages.isnotinyourcontacts' | translate: {$a: otherMember.fullname} }}</strong>
|
||||||
|
</p>
|
||||||
<p class="ion-text-center">{{ 'addon.messages.requirecontacttomessage' | translate: {$a: otherMember.fullname} }}</p>
|
<p class="ion-text-center">{{ 'addon.messages.requirecontacttomessage' | translate: {$a: otherMember.fullname} }}</p>
|
||||||
<ion-button expand="block" class="ion-text-wrap ion-margin-bottom" (click)="createContactRequest()">{{ 'addon.messages.sendcontactrequest' | translate }}</ion-button>
|
<ion-button expand="block" class="ion-text-wrap ion-margin-bottom" (click)="createContactRequest()">
|
||||||
|
{{ 'addon.messages.sendcontactrequest' | translate }}
|
||||||
|
</ion-button>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="footerType == 'requestReceived'" class="ion-padding-horizontal">
|
<div *ngIf="footerType == 'requestReceived' && otherMember" class="ion-padding-horizontal">
|
||||||
<p class="ion-text-center">{{ 'addon.messages.userwouldliketocontactyou' | translate: {$a: otherMember.fullname} }}</p>
|
<p class="ion-text-center">{{ 'addon.messages.userwouldliketocontactyou' | translate: {$a: otherMember.fullname} }}</p>
|
||||||
<ion-button expand="block" class="ion-text-wrap ion-margin-bottom" (click)="confirmContactRequest()">{{ 'addon.messages.acceptandaddcontact' | translate }}</ion-button>
|
<ion-button expand="block" class="ion-text-wrap ion-margin-bottom" (click)="confirmContactRequest()">
|
||||||
<ion-button expand="block" class="ion-text-wrap ion-margin-bottom" color="light" (click)="declineContactRequest()">{{ 'addon.messages.decline' | translate }}</ion-button>
|
{{ 'addon.messages.acceptandaddcontact' | translate }}
|
||||||
|
</ion-button>
|
||||||
|
<ion-button expand="block" class="ion-text-wrap ion-margin-bottom" color="light" (click)="declineContactRequest()">
|
||||||
|
{{ 'addon.messages.decline' | translate }}
|
||||||
|
</ion-button>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="footerType == 'requestSent' || (footerType == 'message' && requestContactSent)" class="ion-padding-horizontal">
|
<div *ngIf="footerType == 'requestSent' || (footerType == 'message' && requestContactSent)" class="ion-padding-horizontal">
|
||||||
<p class="ion-text-center"><strong>{{ 'addon.messages.contactrequestsent' | translate }}</strong></p>
|
<p class="ion-text-center"><strong>{{ 'addon.messages.contactrequestsent' | translate }}</strong></p>
|
||||||
<p class="ion-text-center">{{ 'addon.messages.yourcontactrequestpending' | translate: {$a: otherMember.fullname} }}</p>
|
<p class="ion-text-center" *ngIf="otherMember">
|
||||||
|
{{ 'addon.messages.yourcontactrequestpending' | translate: {$a: otherMember.fullname} }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<core-send-message-form *ngIf="footerType == 'message'" (onSubmit)="sendMessage($event)" [showKeyboard]="showKeyboard"
|
<core-send-message-form *ngIf="footerType == 'message'" (onSubmit)="sendMessage($event)" [showKeyboard]="showKeyboard"
|
||||||
[placeholder]="'addon.messages.newmessage' | translate" (onResize)="resizeContent()"></core-send-message-form>
|
[placeholder]="'addon.messages.newmessage' | translate" (onResize)="resizeContent()"></core-send-message-form>
|
||||||
|
|
|
@ -61,7 +61,7 @@ import { AddonMessagesConversationInfoComponent } from '../../components/convers
|
||||||
selector: 'page-addon-messages-discussion',
|
selector: 'page-addon-messages-discussion',
|
||||||
templateUrl: 'discussion.html',
|
templateUrl: 'discussion.html',
|
||||||
animations: [CoreAnimations.SLIDE_IN_OUT],
|
animations: [CoreAnimations.SLIDE_IN_OUT],
|
||||||
styleUrls: ['discussion.scss', '../../../../theme/messages.scss'],
|
styleUrls: ['discussion.scss'],
|
||||||
})
|
})
|
||||||
export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterViewInit {
|
export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterViewInit {
|
||||||
|
|
||||||
|
@ -167,15 +167,15 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
||||||
*/
|
*/
|
||||||
async ngOnInit(): Promise<void> {
|
async ngOnInit(): Promise<void> {
|
||||||
|
|
||||||
this.route.queryParams.subscribe(async params => {
|
this.route.queryParams.subscribe(async () => {
|
||||||
// Disable the profile button if we're already coming from a profile.
|
// Disable the profile button if we're already coming from a profile.
|
||||||
const backViewPage = CoreNavigator.instance.getPreviousPath();
|
const backViewPage = CoreNavigator.instance.getPreviousPath();
|
||||||
this.showInfo = !backViewPage || !CoreTextUtils.instance.matchesGlob(backViewPage, '**/user/profile');
|
this.showInfo = !backViewPage || !CoreTextUtils.instance.matchesGlob(backViewPage, '**/user/profile');
|
||||||
|
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
this.conversationId = params['conversationId'] ? parseInt(params['conversationId'], 10) : undefined;
|
this.conversationId = CoreNavigator.instance.getRouteNumberParam('conversationId') || undefined;
|
||||||
this.userId = params['userId'] ? parseInt(params['userId'], 10) : undefined;
|
this.userId = CoreNavigator.instance.getRouteNumberParam('userId') || undefined;
|
||||||
this.showKeyboard = !!params['showKeyboard'];
|
this.showKeyboard = CoreNavigator.instance.getRouteBooleanParam('showKeyboard') || false;
|
||||||
|
|
||||||
await this.fetchData();
|
await this.fetchData();
|
||||||
|
|
||||||
|
@ -1329,7 +1329,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
||||||
const result = await modal.onDidDismiss();
|
const result = await modal.onDidDismiss();
|
||||||
|
|
||||||
if (typeof result.data != 'undefined') {
|
if (typeof result.data != 'undefined') {
|
||||||
const splitViewLoaded = CoreNavigator.instance.isSplitViewOutletLoaded('**/messages/**/discussion');
|
const splitViewLoaded = CoreNavigator.instance.isCurrentPathInTablet('**/messages/**/discussion');
|
||||||
|
|
||||||
// Open user conversation.
|
// Open user conversation.
|
||||||
if (splitViewLoaded) {
|
if (splitViewLoaded) {
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
<ion-title>{{ 'addon.messages.messages' | translate }}</ion-title>
|
<ion-title>{{ 'addon.messages.messages' | translate }}</ion-title>
|
||||||
<ion-buttons slot="end">
|
<ion-buttons slot="end">
|
||||||
<!-- Add an empty context menu so discussion page can add items in split view, otherwise the menu disappears in some cases. -->
|
<!-- Add an empty context menu so discussion page can add items in split view,
|
||||||
|
otherwise the menu disappears in some cases. -->
|
||||||
<core-context-menu></core-context-menu>
|
<core-context-menu></core-context-menu>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
|
@ -16,7 +17,7 @@
|
||||||
<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-search-box *ngIf="search.enabled" (onSubmit)="searchMessage($event)" (onClear)="clearSearch($event)"
|
<core-search-box *ngIf="search.enabled" (onSubmit)="searchMessage($event)" (onClear)="clearSearch()"
|
||||||
[placeholder]=" 'addon.messages.message' | translate" autocorrect="off" spellcheck="false" lengthCheck="2"
|
[placeholder]=" 'addon.messages.message' | translate" autocorrect="off" spellcheck="false" lengthCheck="2"
|
||||||
[disabled]="!loaded" searchArea="AddonMessagesDiscussions"></core-search-box>
|
[disabled]="!loaded" searchArea="AddonMessagesDiscussions"></core-search-box>
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@
|
||||||
|
|
||||||
<ion-list class="ion-no-margin">
|
<ion-list class="ion-no-margin">
|
||||||
|
|
||||||
<ion-item class="ion-text-wrap addon-message-discussion" (click)="gotoContacts($event)"
|
<ion-item class="ion-text-wrap addon-message-discussion" (click)="gotoContacts()"
|
||||||
[attr.aria-label]="'addon.messages.contacts' | translate" detail>
|
[attr.aria-label]="'addon.messages.contacts' | translate" detail>
|
||||||
<ion-icon name="fas-address-book" slot="start"></ion-icon>
|
<ion-icon name="fas-address-book" slot="start"></ion-icon>
|
||||||
<ion-label><h2>{{ 'addon.messages.contacts' | translate }}</h2></ion-label>
|
<ion-label><h2>{{ 'addon.messages.contacts' | translate }}</h2></ion-label>
|
||||||
|
@ -37,9 +38,9 @@
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<ion-note slot="end" class="ion-padding-end"><ion-badge>{{ search.results.length }}</ion-badge></ion-note>
|
<ion-note slot="end" class="ion-padding-end"><ion-badge>{{ search.results.length }}</ion-badge></ion-note>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
<ion-item class="ion-text-wrap" *ngFor="let result of search.results" [title]="result.fullname"
|
<ion-item class="ion-text-wrap addon-message-discussion" *ngFor="let result of search.results" [title]="result.fullname"
|
||||||
(click)="gotoDiscussion(result.userid, result.messageid)"
|
(click)="gotoDiscussion(result.userid, result.messageid)"
|
||||||
[class.core-selected-item]="result.userid == discussionUserId" class="addon-message-discussion">
|
[class.core-selected-item]="result.userid == discussionUserId">
|
||||||
<core-user-avatar [user]="result" slot="start" [checkOnline]="result.showonlinestatus"></core-user-avatar>
|
<core-user-avatar [user]="result" slot="start" [checkOnline]="result.showonlinestatus"></core-user-avatar>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>{{ result.fullname }}</h2>
|
<h2>{{ result.fullname }}</h2>
|
||||||
|
@ -49,18 +50,21 @@
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngIf="!search.showResults">
|
<ng-container *ngIf="!search.showResults">
|
||||||
<ion-item class="ion-text-wrap" *ngFor="let discussion of discussions" [title]="discussion.fullname"
|
<ion-item class="ion-text-wrap addon-message-discussion" *ngFor="let discussion of discussions"
|
||||||
(click)="gotoDiscussion(discussion.message!.user)"
|
[title]="discussion.fullname" (click)="gotoDiscussion(discussion.message!.user)"
|
||||||
[class.core-selected-item]="discussion.message!.user == discussionUserId" class="addon-message-discussion">
|
[class.core-selected-item]="discussion.message!.user == discussionUserId">
|
||||||
<core-user-avatar [user]="discussion" slot="start" checkOnline="false"></core-user-avatar>
|
<core-user-avatar [user]="discussion" slot="start" checkOnline="false"></core-user-avatar>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>{{ discussion.fullname }}</h2>
|
<h2>{{ discussion.fullname }}</h2>
|
||||||
<ion-note *ngIf="discussion.message!.timecreated > 0 || discussion.unread">
|
<ion-note *ngIf="discussion.message!.timecreated > 0 || discussion.unread">
|
||||||
<span *ngIf="discussion.unread" class="core-primary-circle"></span>
|
<span *ngIf="discussion.unread" class="core-primary-circle"></span>
|
||||||
<span *ngIf="discussion.message!.timecreated > 0">{{discussion.message!.timecreated / 1000 | coreDateDayOrTime}}</span>
|
<span *ngIf="discussion.message!.timecreated > 0">
|
||||||
|
{{discussion.message!.timecreated / 1000 | coreDateDayOrTime}}
|
||||||
|
</span>
|
||||||
</ion-note>
|
</ion-note>
|
||||||
<p>
|
<p>
|
||||||
<core-format-text clean="true" singleLine="true" [text]="discussion.message!.message" contextLevel="system" [contextInstanceId]="0">
|
<core-format-text clean="true" singleLine="true" [text]="discussion.message!.message"
|
||||||
|
contextLevel="system" [contextInstanceId]="0">
|
||||||
</core-format-text>
|
</core-format-text>
|
||||||
</p>
|
</p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
|
|
|
@ -19,30 +19,34 @@ import { RouterModule, Routes } from '@angular/router';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { CoreScreen } from '@services/screen';
|
import { CoreScreen } from '@services/screen';
|
||||||
import { conditionalRoutes } from '@/app/app-routing.module';
|
import { conditionalRoutes } from '@/app/app-routing.module';
|
||||||
import { discussionRoute } from '@addons/messages/messages-lazy.module';
|
import { AddonMessagesDiscussionRoute } from '@addons/messages/messages-lazy.module';
|
||||||
|
|
||||||
import { CoreSharedModule } from '@/core/shared.module';
|
import { CoreSharedModule } from '@/core/shared.module';
|
||||||
import { CoreSearchComponentsModule } from '@features/search/components/components.module';
|
import { CoreSearchComponentsModule } from '@features/search/components/components.module';
|
||||||
|
|
||||||
import { AddonMessagesDiscussions35Page } from './discussions.page';
|
import { AddonMessagesDiscussions35Page } from './discussions.page';
|
||||||
|
|
||||||
const routes: Routes = [
|
const mobileRoutes: Routes = [
|
||||||
{
|
|
||||||
matcher: segments => {
|
|
||||||
const matches = CoreScreen.instance.isMobile ? segments.length === 0 : true;
|
|
||||||
|
|
||||||
return matches ? { consumed: [] } : null;
|
|
||||||
},
|
|
||||||
component: AddonMessagesDiscussions35Page,
|
|
||||||
children: conditionalRoutes([
|
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
pathMatch: 'full',
|
component: AddonMessagesDiscussions35Page,
|
||||||
},
|
},
|
||||||
discussionRoute,
|
AddonMessagesDiscussionRoute,
|
||||||
], () => CoreScreen.instance.isTablet),
|
];
|
||||||
|
|
||||||
|
const tabletRoutes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: AddonMessagesDiscussions35Page,
|
||||||
|
children: [
|
||||||
|
AddonMessagesDiscussionRoute,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
...conditionalRoutes([discussionRoute], () => CoreScreen.instance.isMobile),
|
];
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
...conditionalRoutes(mobileRoutes, () => CoreScreen.instance.isMobile),
|
||||||
|
...conditionalRoutes(tabletRoutes, () => CoreScreen.instance.isTablet),
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -146,10 +146,9 @@ export class AddonMessagesDiscussions35Page implements OnInit, OnDestroy {
|
||||||
* Component loaded.
|
* Component loaded.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.route.queryParams.subscribe(async params => {
|
this.route.queryParams.subscribe(async () => {
|
||||||
const discussionUserId = params['discussionUserId']
|
const discussionUserId = CoreNavigator.instance.getRouteNumberParam('discussionUserId') ||
|
||||||
? parseInt(params['discussionUserId'], 10)
|
CoreNavigator.instance.getRouteNumberParam('userId') || undefined;
|
||||||
: (params['userId'] ? parseInt(params['userId'], 10) : undefined);
|
|
||||||
|
|
||||||
if (this.loaded && this.discussionUserId == discussionUserId) {
|
if (this.loaded && this.discussionUserId == discussionUserId) {
|
||||||
return;
|
return;
|
||||||
|
@ -281,7 +280,7 @@ export class AddonMessagesDiscussions35Page implements OnInit, OnDestroy {
|
||||||
params.message = messageId;
|
params.message = messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
const splitViewLoaded = CoreNavigator.instance.isSplitViewOutletLoaded('**/messages/index/discussion');
|
const splitViewLoaded = CoreNavigator.instance.isCurrentPathInTablet('**/messages/index/discussion');
|
||||||
const path = (splitViewLoaded ? '../' : '') + 'discussion';
|
const path = (splitViewLoaded ? '../' : '') + 'discussion';
|
||||||
|
|
||||||
CoreNavigator.instance.navigate(path, { params });
|
CoreNavigator.instance.navigate(path, { params });
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<ion-button (click)="gotoSearch()" [attr.aria-label]="'addon.messages.search' | translate">
|
<ion-button (click)="gotoSearch()" [attr.aria-label]="'addon.messages.search' | translate">
|
||||||
<ion-icon name="fas-search" slot="icon-only"></ion-icon>
|
<ion-icon name="fas-search" slot="icon-only"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<ion-button (click)="gotoSettings($event)" [attr.aria-label]="'addon.messages.messagepreferences' | translate">
|
<ion-button (click)="gotoSettings()" [attr.aria-label]="'addon.messages.messagepreferences' | translate">
|
||||||
<ion-icon name="fas-cog" slot="icon-only"></ion-icon>
|
<ion-icon name="fas-cog" slot="icon-only"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<!-- Add an empty context menu so discussion page can add items in split view,
|
<!-- Add an empty context menu so discussion page can add items in split view,
|
||||||
|
@ -25,14 +25,14 @@
|
||||||
|
|
||||||
<core-loading [hideUntil]="loaded" [message]="loadingMessage">
|
<core-loading [hideUntil]="loaded" [message]="loadingMessage">
|
||||||
<ion-list>
|
<ion-list>
|
||||||
<ion-item class="ion-text-wrap addon-message-discussion" (click)="gotoContacts($event)"
|
<ion-item class="ion-text-wrap addon-message-discussion" (click)="gotoContacts()"
|
||||||
[attr.aria-label]="'addon.messages.contacts' | translate" detail>
|
[attr.aria-label]="'addon.messages.contacts' | translate" detail>
|
||||||
<ion-icon name="fas-address-book" slot="start"></ion-icon>
|
<ion-icon name="fas-address-book" slot="start"></ion-icon>
|
||||||
<ion-label><h2>{{ 'addon.messages.contacts' | translate }}</h2></ion-label>
|
<ion-label><h2>{{ 'addon.messages.contacts' | translate }}</h2></ion-label>
|
||||||
<ion-badge *ngIf="contactRequestsCount > 0" slot="end">{{contactRequestsCount}}</ion-badge>
|
<ion-badge *ngIf="contactRequestsCount > 0" slot="end">{{contactRequestsCount}}</ion-badge>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<!-- Favourite conversations. -->
|
<!-- Favourite conversations. -->
|
||||||
<ion-item-divider class="ion-text-wrap" (click)="toggle(favourites)" class="core-expandable" sticky="true">
|
<ion-item-divider class="ion-text-wrap core-expandable" (click)="toggle(favourites)" sticky="true">
|
||||||
<ion-icon *ngIf="!favourites.expanded" name="fas-caret-right" slot="start"></ion-icon>
|
<ion-icon *ngIf="!favourites.expanded" name="fas-caret-right" slot="start"></ion-icon>
|
||||||
<ion-icon *ngIf="favourites.expanded" name="fas-caret-down" slot="start"></ion-icon>
|
<ion-icon *ngIf="favourites.expanded" name="fas-caret-down" slot="start"></ion-icon>
|
||||||
<ion-label>{{ 'core.favourites' | translate }} ({{ favourites.count }})</ion-label>
|
<ion-label>{{ 'core.favourites' | translate }} ({{ favourites.count }})</ion-label>
|
||||||
|
@ -42,7 +42,8 @@
|
||||||
<ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: favourites.conversations}">
|
<ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: favourites.conversations}">
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. -->
|
<!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. -->
|
||||||
<core-infinite-loading [enabled]="favourites.canLoadMore" (action)="loadMoreConversations(favourites, $event)" [error]="favourites.loadMoreError"></core-infinite-loading>
|
<core-infinite-loading [enabled]="favourites.canLoadMore" (action)="loadMoreConversations(favourites, $event)"
|
||||||
|
[error]="favourites.loadMoreError"></core-infinite-loading>
|
||||||
<ion-item class="ion-text-wrap" *ngIf="favourites.conversations && favourites.conversations.length == 0">
|
<ion-item class="ion-text-wrap" *ngIf="favourites.conversations && favourites.conversations.length == 0">
|
||||||
<ion-label><p>{{ 'addon.messages.nofavourites' | translate }}</p></ion-label>
|
<ion-label><p>{{ 'addon.messages.nofavourites' | translate }}</p></ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
@ -52,16 +53,18 @@
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
<!-- Group conversations. -->
|
<!-- Group conversations. -->
|
||||||
<ion-item-divider class="ion-text-wrap" (click)="toggle(group)" class="core-expandable" sticky="true">
|
<ion-item-divider class="ion-text-wrap core-expandable" (click)="toggle(group)" sticky="true">
|
||||||
<ion-icon *ngIf="!group.expanded" name="fas-caret-right" slot="start"></ion-icon>
|
<ion-icon *ngIf="!group.expanded" name="fas-caret-right" slot="start"></ion-icon>
|
||||||
<ion-icon *ngIf="group.expanded" name="fas-caret-down" slot="start"></ion-icon>
|
<ion-icon *ngIf="group.expanded" name="fas-caret-down" slot="start"></ion-icon>
|
||||||
<ion-label>{{ 'addon.messages.groupconversations' | translate }} ({{ group.count }})</ion-label>
|
<ion-label>{{ 'addon.messages.groupconversations' | translate }} ({{ group.count }})</ion-label>
|
||||||
<ion-badge slot="end" *ngIf="group.unread">{{ group.unread }}</ion-badge>
|
<ion-badge slot="end" *ngIf="group.unread">{{ group.unread }}</ion-badge>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
<div [hidden]="!group.conversations || !group.expanded || group.loading" #grouplist>
|
<div [hidden]="!group.conversations || !group.expanded || group.loading" #grouplist>
|
||||||
<ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: group.conversations}"></ng-container>
|
<ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: group.conversations}">
|
||||||
|
</ng-container>
|
||||||
<!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. -->
|
<!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. -->
|
||||||
<core-infinite-loading [enabled]="group.canLoadMore" (action)="loadMoreConversations(group, $event)" [error]="group.loadMoreError"></core-infinite-loading>
|
<core-infinite-loading [enabled]="group.canLoadMore" (action)="loadMoreConversations(group, $event)"
|
||||||
|
[error]="group.loadMoreError"></core-infinite-loading>
|
||||||
<ion-item class="ion-text-wrap" *ngIf="group.conversations && group.conversations.length == 0">
|
<ion-item class="ion-text-wrap" *ngIf="group.conversations && group.conversations.length == 0">
|
||||||
<ion-label><p>{{ 'addon.messages.nogroupconversations' | translate }}</p></ion-label>
|
<ion-label><p>{{ 'addon.messages.nogroupconversations' | translate }}</p></ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
@ -70,16 +73,18 @@
|
||||||
<ion-label><ion-spinner></ion-spinner></ion-label>
|
<ion-label><ion-spinner></ion-spinner></ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
<ion-item-divider class="ion-text-wrap" (click)="toggle(individual)" class="core-expandable" sticky="true">
|
<ion-item-divider class="ion-text-wrap core-expandable" (click)="toggle(individual)" sticky="true">
|
||||||
<ion-icon *ngIf="!individual.expanded" name="fas-caret-right" slot="start"></ion-icon>
|
<ion-icon *ngIf="!individual.expanded" name="fas-caret-right" slot="start"></ion-icon>
|
||||||
<ion-icon *ngIf="individual.expanded" name="fas-caret-down" slot="start"></ion-icon>
|
<ion-icon *ngIf="individual.expanded" name="fas-caret-down" slot="start"></ion-icon>
|
||||||
<ion-label>{{ 'addon.messages.individualconversations' | translate }} ({{ individual.count }})</ion-label>
|
<ion-label>{{ 'addon.messages.individualconversations' | translate }} ({{ individual.count }})</ion-label>
|
||||||
<ion-badge slot="end" *ngIf="individual.unread">{{ individual.unread }}</ion-badge>
|
<ion-badge slot="end" *ngIf="individual.unread">{{ individual.unread }}</ion-badge>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
<div [hidden]="!individual.conversations || !individual.expanded || individual.loading" #indlist>
|
<div [hidden]="!individual.conversations || !individual.expanded || individual.loading" #indlist>
|
||||||
<ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: individual.conversations}"></ng-container>
|
<ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: individual.conversations}">
|
||||||
|
</ng-container>
|
||||||
<!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. -->
|
<!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. -->
|
||||||
<core-infinite-loading [enabled]="individual.canLoadMore" (action)="loadMoreConversations(individual, $event)" [error]="individual.loadMoreError"></core-infinite-loading>
|
<core-infinite-loading [enabled]="individual.canLoadMore" (action)="loadMoreConversations(individual, $event)"
|
||||||
|
[error]="individual.loadMoreError"></core-infinite-loading>
|
||||||
<ion-item class="ion-text-wrap" *ngIf="individual.conversations && individual.conversations.length == 0">
|
<ion-item class="ion-text-wrap" *ngIf="individual.conversations && individual.conversations.length == 0">
|
||||||
<ion-label><p>{{ 'addon.messages.noindividualconversations' | translate }}</p></ion-label>
|
<ion-label><p>{{ 'addon.messages.noindividualconversations' | translate }}</p></ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
@ -95,10 +100,15 @@
|
||||||
|
|
||||||
<!-- Template to render a list of conversations. -->
|
<!-- Template to render a list of conversations. -->
|
||||||
<ng-template #conversationsTemplate let-conversations="conversations">
|
<ng-template #conversationsTemplate let-conversations="conversations">
|
||||||
<ion-item class="ion-text-wrap" *ngFor="let conversation of conversations" [title]="conversation.name" (click)="gotoConversation(conversation.id, conversation.userid)" [class.core-selected-item]="(conversation.id && conversation.id == selectedConversationId) || (conversation.userid && conversation.userid == selectedUserId)" class="addon-message-discussion" id="addon-message-conversation-{{ conversation.id ? conversation.id : 'user-' + conversation.userid }}">
|
<ion-item class="ion-text-wrap addon-message-discussion" *ngFor="let conversation of conversations" [title]="conversation.name"
|
||||||
|
(click)="gotoConversation(conversation.id, conversation.userid)"
|
||||||
|
[class.core-selected-item]="(conversation.id && conversation.id == selectedConversationId) ||
|
||||||
|
(conversation.userid && conversation.userid == selectedUserId)"
|
||||||
|
id="addon-message-conversation-{{ conversation.id ? conversation.id : 'user-' + conversation.userid }}">
|
||||||
<!-- Group conversation image. -->
|
<!-- Group conversation image. -->
|
||||||
<ion-avatar slot="start" *ngIf="conversation.type == typeGroup">
|
<ion-avatar slot="start" *ngIf="conversation.type == typeGroup">
|
||||||
<img [src]="conversation.imageurl" [alt]="conversation.name" core-external-content onError="this.src='assets/img/group-avatar.png'">
|
<img [src]="conversation.imageurl" [alt]="conversation.name" core-external-content
|
||||||
|
onError="this.src='assets/img/group-avatar.png'">
|
||||||
</ion-avatar>
|
</ion-avatar>
|
||||||
|
|
||||||
<!-- Avatar for individual conversations. -->
|
<!-- Avatar for individual conversations. -->
|
||||||
|
@ -108,20 +118,25 @@
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>
|
<h2>
|
||||||
<core-format-text [text]="conversation.name" contextLevel="system" [contextInstanceId]="0"></core-format-text>
|
<core-format-text [text]="conversation.name" contextLevel="system" [contextInstanceId]="0"></core-format-text>
|
||||||
<ion-icon name="fas-user-slash" *ngIf="conversation.isblocked" [title]="'addon.messages.contactblocked' | translate">
|
<ion-icon name="fas-user-slash" *ngIf="conversation.isblocked"
|
||||||
</ion-icon>
|
[title]="'addon.messages.contactblocked' | translate"></ion-icon>
|
||||||
<ion-icon *ngIf="conversation.ismuted" name="fas-volume-mute" [title]="'addon.messages.mutedconversation' | translate">
|
<ion-icon *ngIf="conversation.ismuted" name="fas-volume-mute"
|
||||||
</ion-icon>
|
[title]="'addon.messages.mutedconversation' | translate"></ion-icon>
|
||||||
</h2>
|
</h2>
|
||||||
<ion-note *ngIf="conversation.lastmessagedate > 0 || conversation.unreadcount">
|
<ion-note *ngIf="conversation.lastmessagedate > 0 || conversation.unreadcount">
|
||||||
<ion-badge *ngIf="conversation.unreadcount > 0">{{ conversation.unreadcount }}</ion-badge>
|
<ion-badge *ngIf="conversation.unreadcount > 0">{{ conversation.unreadcount }}</ion-badge>
|
||||||
<span *ngIf="conversation.lastmessagedate > 0">{{conversation.lastmessagedate | coreDateDayOrTime}}</span>
|
<span *ngIf="conversation.lastmessagedate > 0">{{conversation.lastmessagedate | coreDateDayOrTime}}</span>
|
||||||
</ion-note>
|
</ion-note>
|
||||||
<p *ngIf="conversation.subname"><core-format-text [text]="conversation.subname" contextLevel="system" [contextInstanceId]="0"></core-format-text></p>
|
<p *ngIf="conversation.subname"><core-format-text [text]="conversation.subname" contextLevel="system"
|
||||||
|
[contextInstanceId]="0"></core-format-text></p>
|
||||||
<p class="addon-message-last-message">
|
<p class="addon-message-last-message">
|
||||||
<span *ngIf="conversation.sentfromcurrentuser" class="addon-message-last-message-user">{{ 'addon.messages.you' | translate }}</span>
|
<span *ngIf="conversation.sentfromcurrentuser" class="addon-message-last-message-user">
|
||||||
<span *ngIf="!conversation.sentfromcurrentuser && conversation.type == typeGroup && conversation.members[0]" class="addon-message-last-message-user">{{ conversation.members[0].fullname + ':' }}</span>
|
{{ 'addon.messages.you' | translate }}
|
||||||
<core-format-text clean="true" singleLine="true" [text]="conversation.lastmessage" class="addon-message-last-message-text" contextLevel="system" [contextInstanceId]="0"></core-format-text>
|
</span>
|
||||||
|
<span *ngIf="!conversation.sentfromcurrentuser && conversation.type == typeGroup && conversation.members[0]"
|
||||||
|
class="addon-message-last-message-user">{{ conversation.members[0].fullname + ':' }}</span>
|
||||||
|
<core-format-text clean="true" singleLine="true" [text]="conversation.lastmessage"
|
||||||
|
class="addon-message-last-message-text" contextLevel="system" [contextInstanceId]="0"></core-format-text>
|
||||||
</p>
|
</p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
|
@ -18,31 +18,34 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { conditionalRoutes } from '@/app/app-routing.module';
|
import { conditionalRoutes } from '@/app/app-routing.module';
|
||||||
import { discussionRoute } from '@addons/messages/messages-lazy.module';
|
import { AddonMessagesDiscussionRoute } from '@addons/messages/messages-lazy.module';
|
||||||
import { CoreScreen } from '@services/screen';
|
import { CoreScreen } from '@services/screen';
|
||||||
|
|
||||||
import { CoreSharedModule } from '@/core/shared.module';
|
import { CoreSharedModule } from '@/core/shared.module';
|
||||||
|
|
||||||
import { AddonMessagesGroupConversationsPage } from './group-conversations.page';
|
import { AddonMessagesGroupConversationsPage } from './group-conversations.page';
|
||||||
|
|
||||||
|
const mobileRoutes: Routes = [
|
||||||
const routes: Routes = [
|
|
||||||
{
|
|
||||||
matcher: segments => {
|
|
||||||
const matches = CoreScreen.instance.isMobile ? segments.length === 0 : true;
|
|
||||||
|
|
||||||
return matches ? { consumed: [] } : null;
|
|
||||||
},
|
|
||||||
component: AddonMessagesGroupConversationsPage,
|
|
||||||
children: conditionalRoutes([
|
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
pathMatch: 'full',
|
component: AddonMessagesGroupConversationsPage,
|
||||||
},
|
},
|
||||||
discussionRoute,
|
AddonMessagesDiscussionRoute,
|
||||||
], () => CoreScreen.instance.isTablet),
|
];
|
||||||
|
|
||||||
|
const tabletRoutes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: AddonMessagesGroupConversationsPage,
|
||||||
|
children: [
|
||||||
|
AddonMessagesDiscussionRoute,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
...conditionalRoutes([discussionRoute], () => CoreScreen.instance.isMobile),
|
];
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
...conditionalRoutes(mobileRoutes, () => CoreScreen.instance.isMobile),
|
||||||
|
...conditionalRoutes(tabletRoutes, () => CoreScreen.instance.isTablet),
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -280,11 +280,11 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
|
||||||
* Component loaded.
|
* Component loaded.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.route.queryParams.subscribe(async params => {
|
this.route.queryParams.subscribe(async () => {
|
||||||
// Conversation to load.
|
// Conversation to load.
|
||||||
this.conversationId = params['conversationId'] ? parseInt(params['conversationId'], 10) : undefined;
|
this.conversationId = CoreNavigator.instance.getRouteNumberParam('conversationId') || undefined;
|
||||||
if (!this.conversationId) {
|
if (!this.conversationId) {
|
||||||
this.discussionUserId = params['discussionUserId'] ? parseInt(params['discussionUserId'], 10) : undefined;
|
this.discussionUserId = CoreNavigator.instance.getRouteNumberParam('discussionUserId') || undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.conversationId || this.discussionUserId) {
|
if (this.conversationId || this.discussionUserId) {
|
||||||
|
@ -535,7 +535,7 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
|
||||||
params.message = messageId;
|
params.message = messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
const splitViewLoaded = CoreNavigator.instance.isSplitViewOutletLoaded('**/messages/group-conversations/discussion');
|
const splitViewLoaded = CoreNavigator.instance.isCurrentPathInTablet('**/messages/group-conversations/discussion');
|
||||||
const path = (splitViewLoaded ? '../' : '') + 'discussion';
|
const path = (splitViewLoaded ? '../' : '') + 'discussion';
|
||||||
CoreNavigator.instance.navigate(path, { params });
|
CoreNavigator.instance.navigate(path, { params });
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,15 @@
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
<ion-title>{{ 'addon.messages.searchcombined' | translate }}</ion-title>
|
<ion-title>{{ 'addon.messages.searchcombined' | translate }}</ion-title>
|
||||||
<ion-buttons slot="end">
|
<ion-buttons slot="end">
|
||||||
<!-- Add an empty context menu so discussion page can add items in split view, otherwise the menu disappears in some cases. -->
|
<!-- Add an empty context menu so discussion page can add items in split view,
|
||||||
|
otherwise the menu disappears in some cases. -->
|
||||||
<core-context-menu></core-context-menu>
|
<core-context-menu></core-context-menu>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<core-split-view>
|
<core-split-view>
|
||||||
<core-search-box (onSubmit)="search($event)" (onClear)="clearSearch($event)" [disabled]="disableSearch" autocorrect="off"
|
<core-search-box (onSubmit)="search($event)" (onClear)="clearSearch()" [disabled]="disableSearch" autocorrect="off"
|
||||||
[spellcheck]="false" [autoFocus]="true" [lengthCheck]="1" searchArea="AddonMessagesSearch"></core-search-box>
|
[spellcheck]="false" [autoFocus]="true" [lengthCheck]="1" searchArea="AddonMessagesSearch"></core-search-box>
|
||||||
|
|
||||||
<core-loading [hideUntil]="!displaySearching" [message]="'core.searching' | translate">
|
<core-loading [hideUntil]="!displaySearching" [message]="'core.searching' | translate">
|
||||||
|
@ -55,8 +56,12 @@
|
||||||
{{result.lastmessagedate | coreDateDayOrTime}}
|
{{result.lastmessagedate | coreDateDayOrTime}}
|
||||||
</ion-note>
|
</ion-note>
|
||||||
<p class="addon-message-last-message">
|
<p class="addon-message-last-message">
|
||||||
<span *ngIf="result.sentfromcurrentuser" class="addon-message-last-message-user">{{ 'addon.messages.you' | translate }}</span>
|
<span *ngIf="result.sentfromcurrentuser" class="addon-message-last-message-user">
|
||||||
<core-format-text clean="true" singleLine="true" [text]="result.lastmessage" [highlight]="result.highlightMessage" contextLevel="system" [contextInstanceId]="0" class="addon-message-last-message-text"></core-format-text>
|
{{ 'addon.messages.you' | translate }}
|
||||||
|
</span>
|
||||||
|
<core-format-text clean="true" singleLine="true" [text]="result.lastmessage"
|
||||||
|
[highlight]="result.highlightMessage" contextLevel="system" [contextInstanceId]="0"
|
||||||
|
class="addon-message-last-message-text"></core-format-text>
|
||||||
</p>
|
</p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
|
@ -19,30 +19,34 @@ import { RouterModule, Routes } from '@angular/router';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { CoreScreen } from '@services/screen';
|
import { CoreScreen } from '@services/screen';
|
||||||
import { conditionalRoutes } from '@/app/app-routing.module';
|
import { conditionalRoutes } from '@/app/app-routing.module';
|
||||||
import { discussionRoute } from '@addons/messages/messages-lazy.module';
|
import { AddonMessagesDiscussionRoute } from '@addons/messages/messages-lazy.module';
|
||||||
|
|
||||||
import { CoreSharedModule } from '@/core/shared.module';
|
import { CoreSharedModule } from '@/core/shared.module';
|
||||||
import { CoreSearchComponentsModule } from '@features/search/components/components.module';
|
import { CoreSearchComponentsModule } from '@features/search/components/components.module';
|
||||||
|
|
||||||
import { AddonMessagesSearchPage } from './search.page';
|
import { AddonMessagesSearchPage } from './search.page';
|
||||||
|
|
||||||
const routes: Routes = [
|
const mobileRoutes: Routes = [
|
||||||
{
|
|
||||||
matcher: segments => {
|
|
||||||
const matches = CoreScreen.instance.isMobile ? segments.length === 0 : true;
|
|
||||||
|
|
||||||
return matches ? { consumed: [] } : null;
|
|
||||||
},
|
|
||||||
component: AddonMessagesSearchPage,
|
|
||||||
children: conditionalRoutes([
|
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
pathMatch: 'full',
|
component: AddonMessagesSearchPage,
|
||||||
},
|
},
|
||||||
discussionRoute,
|
AddonMessagesDiscussionRoute,
|
||||||
], () => CoreScreen.instance.isTablet),
|
];
|
||||||
|
|
||||||
|
const tabletRoutes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: AddonMessagesSearchPage,
|
||||||
|
children: [
|
||||||
|
AddonMessagesDiscussionRoute,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
...conditionalRoutes([discussionRoute], () => CoreScreen.instance.isMobile),
|
];
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
...conditionalRoutes(mobileRoutes, () => CoreScreen.instance.isMobile),
|
||||||
|
...conditionalRoutes(tabletRoutes, () => CoreScreen.instance.isTablet),
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -108,7 +108,7 @@ export class AddonMessagesSearchPage implements OnDestroy {
|
||||||
this.displayResults = false;
|
this.displayResults = false;
|
||||||
|
|
||||||
// Empty details.
|
// Empty details.
|
||||||
const splitViewLoaded = CoreNavigator.instance.isSplitViewOutletLoaded('**/messages/search/discussion');
|
const splitViewLoaded = CoreNavigator.instance.isCurrentPathInTablet('**/messages/search/discussion');
|
||||||
if (splitViewLoaded) {
|
if (splitViewLoaded) {
|
||||||
CoreNavigator.instance.navigate('../');
|
CoreNavigator.instance.navigate('../');
|
||||||
}
|
}
|
||||||
|
@ -258,7 +258,7 @@ export class AddonMessagesSearchPage implements OnDestroy {
|
||||||
params.userId = result.id;
|
params.userId = result.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const splitViewLoaded = CoreNavigator.instance.isSplitViewOutletLoaded('**/messages/search/discussion');
|
const splitViewLoaded = CoreNavigator.instance.isCurrentPathInTablet('**/messages/search/discussion');
|
||||||
const path = (splitViewLoaded ? '../' : '') + 'discussion';
|
const path = (splitViewLoaded ? '../' : '') + 'discussion';
|
||||||
CoreNavigator.instance.navigate(path, { params });
|
CoreNavigator.instance.navigate(path, { params });
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,13 +20,13 @@ import { CoreSettingsDelegate, CoreSettingsHandlerData } from '../../services/se
|
||||||
import { CoreEventObserver, CoreEvents, CoreEventSiteUpdatedData } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents, CoreEventSiteUpdatedData } from '@singletons/events';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
// import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
|
||||||
// import { CoreSharedFiles } from '@features/sharedfiles/services/sharedfiles';
|
// import { CoreSharedFiles } from '@features/sharedfiles/services/sharedfiles';
|
||||||
import { CoreSettingsHelper, CoreSiteSpaceUsage } from '../../services/settings-helper';
|
import { CoreSettingsHelper, CoreSiteSpaceUsage } from '../../services/settings-helper';
|
||||||
import { CoreApp } from '@services/app';
|
import { CoreApp } from '@services/app';
|
||||||
import { CoreSiteInfo } from '@classes/site';
|
import { CoreSiteInfo } from '@classes/site';
|
||||||
import { Translate } from '@singletons';
|
import { Translate } from '@singletons';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
|
import { CoreScreen } from '@services/screen';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays the list of site settings pages.
|
* Page that displays the list of site settings pages.
|
||||||
|
@ -37,8 +37,6 @@ import { CoreNavigator } from '@services/navigator';
|
||||||
})
|
})
|
||||||
export class CoreSitePreferencesPage implements OnInit, OnDestroy {
|
export class CoreSitePreferencesPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
// @ViewChild(CoreSplitViewComponent) splitviewCtrl?: CoreSplitViewComponent;
|
|
||||||
|
|
||||||
isIOS: boolean;
|
isIOS: boolean;
|
||||||
selectedPage?: string;
|
selectedPage?: string;
|
||||||
|
|
||||||
|
@ -80,13 +78,14 @@ export class CoreSitePreferencesPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
if (this.selectedPage) {
|
if (this.selectedPage) {
|
||||||
this.openHandler(this.selectedPage);
|
this.openHandler(this.selectedPage);
|
||||||
} /* else if (this.splitviewCtrl.isOn()) {
|
} else if (CoreScreen.instance.isTablet) {
|
||||||
if (this.isIOS) {
|
if (this.isIOS) {
|
||||||
this.openHandler('CoreSharedFilesListPage', { manage: true, siteId: this.siteId, hideSitePicker: true });
|
// @todo
|
||||||
|
// this.openHandler('CoreSharedFilesListPage', { manage: true, siteId: this.siteId, hideSitePicker: true });
|
||||||
} else if (this.handlers.length > 0) {
|
} else if (this.handlers.length > 0) {
|
||||||
this.openHandler(this.handlers[0].page, this.handlers[0].params);
|
this.openHandler(this.handlers[0].page, this.handlers[0].params);
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { Component, OnInit, Type } from '@angular/core';
|
||||||
import { IonInfiniteScroll, IonRefresher } from '@ionic/angular';
|
import { IonInfiniteScroll, IonRefresher } from '@ionic/angular';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreTag } from '@features/tag/services/tag';
|
import { CoreTag } from '@features/tag/services/tag';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { CoreTagAreaDelegate } from '../../services/tag-area-delegate';
|
import { CoreTagAreaDelegate } from '../../services/tag-area-delegate';
|
||||||
import { Translate } from '@singletons';
|
import { Translate } from '@singletons';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
|
@ -49,10 +50,17 @@ export class CoreTagIndexAreaPage implements OnInit {
|
||||||
areaComponent?: Type<unknown>;
|
areaComponent?: Type<unknown>;
|
||||||
loadMoreError = false;
|
loadMoreError = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected route: ActivatedRoute,
|
||||||
|
) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View loaded.
|
* View loaded.
|
||||||
*/
|
*/
|
||||||
async ngOnInit(): Promise<void> {
|
async ngOnInit(): Promise<void> {
|
||||||
|
this.route.queryParams.subscribe(async () => {
|
||||||
|
this.loaded = false;
|
||||||
|
|
||||||
this.tagId = CoreNavigator.instance.getRouteNumberParam('tagId') || this.tagId;
|
this.tagId = CoreNavigator.instance.getRouteNumberParam('tagId') || this.tagId;
|
||||||
this.tagName = CoreNavigator.instance.getRouteParam('tagName') || this.tagName;
|
this.tagName = CoreNavigator.instance.getRouteParam('tagName') || this.tagName;
|
||||||
this.collectionId = CoreNavigator.instance.getRouteNumberParam('collectionId') || this.collectionId;
|
this.collectionId = CoreNavigator.instance.getRouteNumberParam('collectionId') || this.collectionId;
|
||||||
|
@ -78,6 +86,7 @@ export class CoreTagIndexAreaPage implements OnInit {
|
||||||
} finally {
|
} finally {
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
<ion-title>{{ 'core.tag.tag' | translate }}: {{ tagName }}</ion-title>
|
<ion-title>{{ 'core.tag.tag' | translate }}: {{ tagName }}</ion-title>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<!--@todo <core-split-view>-->
|
|
||||||
<ion-content>
|
<ion-content>
|
||||||
|
<core-split-view>
|
||||||
<ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshData($event)">
|
<ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshData($event)">
|
||||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
|
@ -28,4 +29,5 @@
|
||||||
<core-empty-box icon="fa-tag" *ngIf="!hasUnsupportedAreas && (!areas || !areas.length)"
|
<core-empty-box icon="fa-tag" *ngIf="!hasUnsupportedAreas && (!areas || !areas.length)"
|
||||||
[message]="'core.tag.noresultsfor' | translate: { $a: tagName }"></core-empty-box>
|
[message]="'core.tag.noresultsfor' | translate: { $a: tagName }"></core-empty-box>
|
||||||
</core-loading>
|
</core-loading>
|
||||||
|
</core-split-view>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
|
@ -17,15 +17,34 @@ import { IonicModule } from '@ionic/angular';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
import { conditionalRoutes } from '@/app/app-routing.module';
|
||||||
|
import { CoreTagIndexAreaRoute } from '@features/tag/tag-lazy.module';
|
||||||
|
import { CoreScreen } from '@services/screen';
|
||||||
|
|
||||||
import { CoreSharedModule } from '@/core/shared.module';
|
import { CoreSharedModule } from '@/core/shared.module';
|
||||||
import { CoreTagIndexPage } from './index.page';
|
import { CoreTagIndexPage } from './index.page';
|
||||||
|
|
||||||
const routes: Routes = [
|
const mobileRoutes: Routes = [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: CoreTagIndexPage,
|
component: CoreTagIndexPage,
|
||||||
},
|
},
|
||||||
|
CoreTagIndexAreaRoute,
|
||||||
|
];
|
||||||
|
|
||||||
|
const tabletRoutes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: CoreTagIndexPage,
|
||||||
|
children: [
|
||||||
|
CoreTagIndexAreaRoute,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
...conditionalRoutes(mobileRoutes, () => CoreScreen.instance.isMobile),
|
||||||
|
...conditionalRoutes(tabletRoutes, () => CoreScreen.instance.isTablet),
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { IonRefresher } from '@ionic/angular';
|
import { IonRefresher } from '@ionic/angular';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
// import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
|
||||||
import { CoreTag } from '@features/tag/services/tag';
|
import { CoreTag } from '@features/tag/services/tag';
|
||||||
import { CoreTagAreaDelegate } from '@features/tag/services/tag-area-delegate';
|
import { CoreTagAreaDelegate } from '@features/tag/services/tag-area-delegate';
|
||||||
|
import { CoreScreen } from '@services/screen';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,8 +29,6 @@ import { CoreNavigator } from '@services/navigator';
|
||||||
})
|
})
|
||||||
export class CoreTagIndexPage implements OnInit {
|
export class CoreTagIndexPage implements OnInit {
|
||||||
|
|
||||||
// @ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent;
|
|
||||||
|
|
||||||
tagId = 0;
|
tagId = 0;
|
||||||
tagName = '';
|
tagName = '';
|
||||||
collectionId = 0;
|
collectionId = 0;
|
||||||
|
@ -42,7 +40,7 @@ export class CoreTagIndexPage implements OnInit {
|
||||||
selectedAreaId?: number;
|
selectedAreaId?: number;
|
||||||
hasUnsupportedAreas = false;
|
hasUnsupportedAreas = false;
|
||||||
|
|
||||||
areas: (CoreTagAreaDisplay | null)[] = [];
|
areas: CoreTagAreaDisplay[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View loaded.
|
* View loaded.
|
||||||
|
@ -58,10 +56,10 @@ export class CoreTagIndexPage implements OnInit {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.fetchData();
|
await this.fetchData();
|
||||||
/* if (this.splitviewCtrl.isOn() && this.areas && this.areas.length > 0) {
|
if (CoreScreen.instance.isTablet && this.areas && this.areas.length > 0) {
|
||||||
const area = this.areas.find((area) => area.id == this.areaId);
|
const area = this.areas.find((area) => area.id == this.areaId);
|
||||||
this.openArea(area || this.areas[0]);
|
this.openArea(area || this.areas[0]);
|
||||||
}*/
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
}
|
}
|
||||||
|
@ -88,17 +86,19 @@ export class CoreTagIndexPage implements OnInit {
|
||||||
this.areas = [];
|
this.areas = [];
|
||||||
this.hasUnsupportedAreas = false;
|
this.hasUnsupportedAreas = false;
|
||||||
|
|
||||||
const areasDisplay: (CoreTagAreaDisplay | null)[] = await Promise.all(areas.map(async (area) => {
|
const areasDisplay: CoreTagAreaDisplay[] = [];
|
||||||
|
|
||||||
|
await Promise.all(areas.map(async (area) => {
|
||||||
const items = await CoreTagAreaDelegate.instance.parseContent(area.component, area.itemtype, area.content);
|
const items = await CoreTagAreaDelegate.instance.parseContent(area.component, area.itemtype, area.content);
|
||||||
|
|
||||||
if (!items || !items.length) {
|
if (!items || !items.length) {
|
||||||
// Tag area not supported, skip.
|
// Tag area not supported, skip.
|
||||||
this.hasUnsupportedAreas = true;
|
this.hasUnsupportedAreas = true;
|
||||||
|
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
areasDisplay.push({
|
||||||
id: area.ta,
|
id: area.ta,
|
||||||
componentName: area.component,
|
componentName: area.component,
|
||||||
itemType: area.itemtype,
|
itemType: area.itemtype,
|
||||||
|
@ -106,10 +106,10 @@ export class CoreTagIndexPage implements OnInit {
|
||||||
items,
|
items,
|
||||||
canLoadMore: !!area.nextpageurl,
|
canLoadMore: !!area.nextpageurl,
|
||||||
badge: items && items.length ? items.length + (area.nextpageurl ? '+' : '') : '',
|
badge: items && items.length ? items.length + (area.nextpageurl ? '+' : '') : '',
|
||||||
};
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.areas = areasDisplay.filter((area) => area != null);
|
this.areas = areasDisplay;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
CoreDomUtils.instance.showErrorModalDefault(error, 'Error loading tag index');
|
CoreDomUtils.instance.showErrorModalDefault(error, 'Error loading tag index');
|
||||||
|
@ -160,8 +160,11 @@ export class CoreTagIndexPage implements OnInit {
|
||||||
canLoadMore: area.canLoadMore,
|
canLoadMore: area.canLoadMore,
|
||||||
nextPage: 1,
|
nextPage: 1,
|
||||||
};
|
};
|
||||||
// this.splitviewCtrl.push('index-area', params);
|
|
||||||
CoreNavigator.instance.navigate('../index-area', { params });
|
const splitViewLoaded = CoreNavigator.instance.isCurrentPathInTablet('**/tag/index/index-area');
|
||||||
|
const path = (splitViewLoaded ? '../' : '') + 'index-area';
|
||||||
|
|
||||||
|
CoreNavigator.instance.navigate(path, { params });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,16 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Injector, NgModule } from '@angular/core';
|
import { Injector, NgModule } from '@angular/core';
|
||||||
import { RouterModule, ROUTES, Routes } from '@angular/router';
|
import { Route, RouterModule, ROUTES, Routes } from '@angular/router';
|
||||||
|
|
||||||
import { buildTabMainRoutes } from '@features/mainmenu/mainmenu-tab-routing.module';
|
import { buildTabMainRoutes } from '@features/mainmenu/mainmenu-tab-routing.module';
|
||||||
|
|
||||||
|
export const CoreTagIndexAreaRoute: Route = {
|
||||||
|
path: 'index-area',
|
||||||
|
loadChildren: () =>
|
||||||
|
import('@features/tag/pages/index-area/index-area.page.module').then(m => m.CoreTagIndexAreaPageModule),
|
||||||
|
};
|
||||||
|
|
||||||
function buildRoutes(injector: Injector): Routes {
|
function buildRoutes(injector: Injector): Routes {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
@ -27,11 +33,7 @@ function buildRoutes(injector: Injector): Routes {
|
||||||
path: 'search',
|
path: 'search',
|
||||||
loadChildren: () => import('@features/tag//pages/search/search.page.module').then(m => m.CoreTagSearchPageModule),
|
loadChildren: () => import('@features/tag//pages/search/search.page.module').then(m => m.CoreTagSearchPageModule),
|
||||||
},
|
},
|
||||||
{
|
CoreTagIndexAreaRoute,
|
||||||
path: 'index-area',
|
|
||||||
loadChildren: () =>
|
|
||||||
import('@features/tag/pages/index-area/index-area.page.module').then(m => m.CoreTagIndexAreaPageModule),
|
|
||||||
},
|
|
||||||
...buildTabMainRoutes(injector, {
|
...buildTabMainRoutes(injector, {
|
||||||
redirectTo: 'search',
|
redirectTo: 'search',
|
||||||
pathMatch: 'full',
|
pathMatch: 'full',
|
||||||
|
|
Loading…
Reference in New Issue