(Chat Panel) Don't unfold the panel on hover

(Chat Panel) Always keep the contacts list in view
This commit is contained in:
Sercan Yemen 2018-07-10 14:55:30 +03:00
parent 585709cf93
commit e1c906f08b
8 changed files with 105 additions and 78 deletions

View File

@ -1,6 +1,6 @@
<div class="header mat-elevation-z4 mat-primary-bg" fxLayout="row" fxLayoutAlign="space-between center"> <div class="header mat-elevation-z4 mat-primary-bg" fxLayout="row" fxLayoutAlign="space-between center">
<ng-container *ngIf="view === 'contacts'"> <ng-container *ngIf="selectedContact === null">
<div class="title ml-16" fxLayout="row" fxLayoutAlign="start center"> <div class="title ml-16" fxLayout="row" fxLayoutAlign="start center">
<mat-icon class="s-32 white-fg">chat</mat-icon> <mat-icon class="s-32 white-fg">chat</mat-icon>
@ -9,21 +9,17 @@
</ng-container> </ng-container>
<ng-container *ngIf="view === 'chat'"> <ng-container *ngIf="selectedContact !== null">
<div class="title" fxLayout="row" fxLayoutAlign="start center"> <div class="title" fxLayout="row" fxLayoutAlign="start center">
<button class="mx-8" mat-icon-button (click)="goToContacts()"> <img [src]="selectedContact.avatar" class="avatar mx-16">
<mat-icon>arrow_back</mat-icon> <h3 class="text-truncate">{{selectedContact.name}}</h3>
</button>
<img [src]="contact.avatar" class="avatar mr-0 w-32 h-32">
<h3 class="ml-12 text-truncate">{{contact.name}}</h3>
</div> </div>
</ng-container> </ng-container>
<button mat-icon-button class="toggle-sidebar-folded mr-8" (click)="toggleSidebarFolded()" fxHide fxShow.gt-md> <button mat-icon-button class="toggle-sidebar-folded mr-8" (click)="foldSidebarTemporarily()" fxHide fxShow.gt-md>
<mat-icon class="secondary-text s-20" *ngIf="sidebarFolded">lock_open</mat-icon> <mat-icon class="secondary-text s-20">arrow_forward</mat-icon>
<mat-icon class="secondary-text s-20" *ngIf="!sidebarFolded">lock_outline</mat-icon>
</button> </button>
<button mat-icon-button class="toggle-sidebar-folded mr-8" (click)="toggleSidebarOpen()" fxHide.gt-md> <button mat-icon-button class="toggle-sidebar-folded mr-8" (click)="toggleSidebarOpen()" fxHide.gt-md>
@ -32,54 +28,57 @@
</div> </div>
<ng-container *ngIf="view === 'contacts'"> <div>
<!-- Contacts -->
<mat-list id="contacts-list" fusePerfectScrollbar [fusePerfectScrollbarOptions]="{suppressScrollX: true}"> <mat-list id="contacts-list" fusePerfectScrollbar [fusePerfectScrollbarOptions]="{suppressScrollX: true}">
<mat-list-item *ngFor="let contact of contacts" [ngClass]="contact.status" (click)="goToChat(contact)" <mat-list-item *ngFor="let contact of contacts"
[ngClass]="contact.status"
[class.active]="contact.id === selectedContact?.id"
(click)="goToChat(contact)"
[matTooltip]="contact.name"
matTooltipPosition="left"
matRipple> matRipple>
<img matListAvatar [src]="contact.avatar"> <img matListAvatar [src]="contact.avatar">
<h3 matLine>
{{contact.name}}
</h3>
<div class="unread-count" *ngIf="contact.unread">{{contact.unread}}</div> <div class="unread-count" *ngIf="contact.unread">{{contact.unread}}</div>
<div class="status-icon" [ngClass]="contact.status"></div> <div class="status-icon" [ngClass]="contact.status"></div>
</mat-list-item> </mat-list-item>
</mat-list> </mat-list>
<!-- / Contacts -->
</ng-container> <!-- Chat -->
<ng-container *ngIf="view === 'chat'">
<div id="chat" fxLayout="column" fxFlex="1 1 auto"> <div id="chat" fxLayout="column" fxFlex="1 1 auto">
<div class="messages" fxFlex="1 1 auto" fusePerfectScrollbar> <div id="messages" class="messages" fxFlex="1 1 auto" fusePerfectScrollbar>
<div *ngFor="let message of chat.dialog; let i = index" class="message-row" <ng-container *ngIf="chat && chat.dialog && chat.dialog.length > 0">
[ngClass]="{
<div *ngFor="let message of chat.dialog; let i = index" class="message-row"
[ngClass]="{
'me': message.who === user.id, 'me': message.who === user.id,
'contact': message.who !== user.id, 'contact': message.who !== user.id,
'first-of-group': isFirstMessageOfGroup(message, i), 'first-of-group': isFirstMessageOfGroup(message, i),
'last-of-group': isLastMessageOfGroup(message, i) 'last-of-group': isLastMessageOfGroup(message, i)
}"> }">
<img *ngIf="shouldShowContactAvatar(message, i)" <img *ngIf="shouldShowContactAvatar(message, i)"
src="{{contact.avatar}}" src="{{selectedContact.avatar}}"
class="avatar"> class="avatar">
<div class="bubble">
<div class="message">{{message.message}}</div>
<div class="time secondary-text">{{message.time | date:'short'}}</div>
</div>
<div class="bubble">
<div class="message">{{message.message}}</div>
<div class="time secondary-text">{{message.time | date:'short'}}</div>
</div> </div>
</div> </ng-container>
<ng-container *ngIf="chat.dialog.length === 0"> <ng-container *ngIf="chat && chat.dialog && chat.dialog.length === 0">
<div class="no-messages-icon"> <div class="no-messages-icon">
<mat-icon class="s-128">chat</mat-icon> <mat-icon class="s-128">chat</mat-icon>
@ -115,5 +114,6 @@
</div> </div>
</div> </div>
<!-- / Chat -->
</ng-container> </div>

View File

@ -4,9 +4,9 @@ chat-panel {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1 1 auto; flex: 1 1 auto;
width: 280px; width: 360px;
min-width: 280px; min-width: 360px;
max-width: 280px; max-width: 360px;
z-index: 99; z-index: 99;
overflow: hidden; overflow: hidden;
@ -31,11 +31,28 @@ chat-panel {
#contacts-list { #contacts-list {
padding: 8px 0; padding: 8px 0;
overflow: auto; overflow: auto;
width: 72px;
min-width: 72px;
max-width: 72px;
// Perfect scrollbar
.ps__rail-y {
width: 3px !important;
.ps__thumb-y {
width: 3px !important;
}
}
.mat-list-item { .mat-list-item {
cursor: pointer; cursor: pointer;
position: relative; position: relative;
&.active {
background-color: mat-color(mat-palette($mat-grey, 300));
@include mat-elevation(2);
}
&.offline { &.offline {
.mat-list-item-content { .mat-list-item-content {
@ -316,6 +333,9 @@ chat-panel {
fuse-sidebar { fuse-sidebar {
&.chat-panel { &.chat-panel {
width: 360px;
min-width: 360px;
max-width: 360px;
// Folded // Folded
&.folded { &.folded {

View File

@ -1,4 +1,4 @@
import { Component, ElementRef, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; import { AfterViewInit, Component, ElementRef, OnDestroy, OnInit, QueryList, ViewChild, ViewChildren, ViewEncapsulation } from '@angular/core';
import { NgForm } from '@angular/forms'; import { NgForm } from '@angular/forms';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
@ -15,20 +15,13 @@ import { ChatPanelService } from 'app/layout/components/chat-panel/chat-panel.se
styleUrls : ['./chat-panel.component.scss'], styleUrls : ['./chat-panel.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class ChatPanelComponent implements OnInit, OnDestroy export class ChatPanelComponent implements OnInit, AfterViewInit, OnDestroy
{ {
contacts: any[]; contacts: any[];
contact: any;
chat: any; chat: any;
selectedContact: any;
sidebarFolded: boolean; sidebarFolded: boolean;
user: any; user: any;
view: string;
@ViewChild(FusePerfectScrollbarDirective)
set fusePerfectScrollbarDirective(content: FusePerfectScrollbarDirective)
{
this._fusePerfectScrollbarDirective = content;
}
@ViewChild('replyForm') @ViewChild('replyForm')
set replyForm(content: NgForm) set replyForm(content: NgForm)
@ -42,8 +35,11 @@ export class ChatPanelComponent implements OnInit, OnDestroy
this._replyInput = content; this._replyInput = content;
} }
@ViewChildren(FusePerfectScrollbarDirective)
private _fusePerfectScrollbarDirectives: QueryList<FusePerfectScrollbarDirective>;
// Private // Private
private _fusePerfectScrollbarDirective: FusePerfectScrollbarDirective; private _chatViewScrollbar: FusePerfectScrollbarDirective;
private _replyForm: NgForm; private _replyForm: NgForm;
private _replyInput: ElementRef; private _replyInput: ElementRef;
private _unsubscribeAll: Subject<any>; private _unsubscribeAll: Subject<any>;
@ -62,9 +58,8 @@ export class ChatPanelComponent implements OnInit, OnDestroy
) )
{ {
// Set the defaults // Set the defaults
this.contact = null; this.selectedContact = null;
this.sidebarFolded = true; this.sidebarFolded = true;
this.view = 'contacts';
// Set the private defaults // Set the private defaults
this._unsubscribeAll = new Subject(); this._unsubscribeAll = new Subject();
@ -94,6 +89,16 @@ export class ChatPanelComponent implements OnInit, OnDestroy
}); });
} }
/**
* After view init
*/
ngAfterViewInit(): void
{
this._chatViewScrollbar = this._fusePerfectScrollbarDirectives.find((directive) => {
return directive.elementRef.nativeElement.id === 'messages';
});
}
/** /**
* On destroy * On destroy
*/ */
@ -122,12 +127,12 @@ export class ChatPanelComponent implements OnInit, OnDestroy
this._replyInput.nativeElement.focus(); this._replyInput.nativeElement.focus();
// Scroll to the bottom of the messages list // Scroll to the bottom of the messages list
if ( this._fusePerfectScrollbarDirective ) if ( this._chatViewScrollbar )
{ {
this._fusePerfectScrollbarDirective.update(); this._chatViewScrollbar.update();
setTimeout(() => { setTimeout(() => {
this._fusePerfectScrollbarDirective.scrollToBottom(0); this._chatViewScrollbar.scrollToBottom(0);
}); });
} }
}); });
@ -145,6 +150,22 @@ export class ChatPanelComponent implements OnInit, OnDestroy
this._fuseSidebarService.getSidebar('chatPanel').toggleFold(); this._fuseSidebarService.getSidebar('chatPanel').toggleFold();
} }
/**
* Fold the temporarily unfolded sidebar back
*/
foldSidebarTemporarily(): void
{
this._fuseSidebarService.getSidebar('chatPanel').foldTemporarily();
}
/**
* Unfold the sidebar temporarily
*/
unfoldSidebarTemporarily(): void
{
this._fuseSidebarService.getSidebar('chatPanel').unfoldTemporarily();
}
/** /**
* Toggle sidebar opened status * Toggle sidebar opened status
*/ */
@ -163,8 +184,8 @@ export class ChatPanelComponent implements OnInit, OnDestroy
shouldShowContactAvatar(message, i): boolean shouldShowContactAvatar(message, i): boolean
{ {
return ( return (
message.who === this.contact.id && message.who === this.selectedContact.id &&
((this.chat.dialog[i + 1] && this.chat.dialog[i + 1].who !== this.contact.id) || !this.chat.dialog[i + 1]) ((this.chat.dialog[i + 1] && this.chat.dialog[i + 1].who !== this.selectedContact.id) || !this.chat.dialog[i + 1])
); );
} }
@ -199,11 +220,11 @@ export class ChatPanelComponent implements OnInit, OnDestroy
*/ */
goToChat(contact): void goToChat(contact): void
{ {
// Change the view // Unfold the sidebar temporarily
this.view = 'chat'; this.unfoldSidebarTemporarily();
// Set the current contact // Set the selected contact
this.contact = contact; this.selectedContact = contact;
// Load the chat // Load the chat
this._chatPanelService.getChat(contact.id).then((chat) => { this._chatPanelService.getChat(contact.id).then((chat) => {
@ -216,21 +237,6 @@ export class ChatPanelComponent implements OnInit, OnDestroy
}); });
} }
/**
* Go to contact view
*/
goToContacts(): void
{
// Change the view
this.view = 'contacts';
// Set the current contact as null
this.contact = null;
// Clear the chat data
this.chat = null;
}
/** /**
* Reply * Reply
*/ */

View File

@ -1,5 +1,5 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { MatButtonModule, MatFormFieldModule, MatIconModule, MatInputModule, MatListModule, MatRippleModule, MatTabsModule } from '@angular/material'; import { MatButtonModule, MatFormFieldModule, MatIconModule, MatInputModule, MatListModule, MatRippleModule, MatTabsModule, MatTooltipModule } from '@angular/material';
import { FuseSharedModule } from '@fuse/shared.module'; import { FuseSharedModule } from '@fuse/shared.module';
@ -20,6 +20,7 @@ import { ChatPanelService } from 'app/layout/components/chat-panel/chat-panel.se
MatInputModule, MatInputModule,
MatListModule, MatListModule,
MatTabsModule, MatTabsModule,
MatTooltipModule,
MatRippleModule, MatRippleModule,
FuseSharedModule FuseSharedModule

View File

@ -57,7 +57,7 @@
<!-- CHAT PANEL --> <!-- CHAT PANEL -->
<fuse-sidebar class="chat-panel" name="chatPanel" position="right" <fuse-sidebar class="chat-panel" name="chatPanel" position="right"
[folded]="true" [foldedWidth]="70" [folded]="true" [foldedWidth]="70" [foldedAutoTriggerOnHover]="false"
lockedOpen="gt-md"> lockedOpen="gt-md">
<chat-panel></chat-panel> <chat-panel></chat-panel>
</fuse-sidebar> </fuse-sidebar>

View File

@ -69,7 +69,7 @@
<!-- CHAT PANEL --> <!-- CHAT PANEL -->
<fuse-sidebar class="chat-panel" name="chatPanel" position="right" <fuse-sidebar class="chat-panel" name="chatPanel" position="right"
[folded]="true" [foldedWidth]="70" [folded]="true" [foldedWidth]="70" [foldedAutoTriggerOnHover]="false"
lockedOpen="gt-md"> lockedOpen="gt-md">
<chat-panel></chat-panel> <chat-panel></chat-panel>
</fuse-sidebar> </fuse-sidebar>

View File

@ -69,7 +69,7 @@
<!-- CHAT PANEL --> <!-- CHAT PANEL -->
<fuse-sidebar class="chat-panel" name="chatPanel" position="right" <fuse-sidebar class="chat-panel" name="chatPanel" position="right"
[folded]="true" [foldedWidth]="70" [folded]="true" [foldedWidth]="70" [foldedAutoTriggerOnHover]="false"
lockedOpen="gt-md"> lockedOpen="gt-md">
<chat-panel></chat-panel> <chat-panel></chat-panel>
</fuse-sidebar> </fuse-sidebar>

View File

@ -55,7 +55,7 @@
<!-- CHAT PANEL --> <!-- CHAT PANEL -->
<fuse-sidebar class="chat-panel" name="chatPanel" position="right" <fuse-sidebar class="chat-panel" name="chatPanel" position="right"
[folded]="true" [foldedWidth]="70" [folded]="true" [foldedWidth]="70" [foldedAutoTriggerOnHover]="false"
lockedOpen="gt-md"> lockedOpen="gt-md">
<chat-panel></chat-panel> <chat-panel></chat-panel>
</fuse-sidebar> </fuse-sidebar>