new overlay navigation functionnal

This commit is contained in:
Nicolas Constant 2019-08-10 23:52:56 -04:00
parent eb66cb7760
commit 798f8f404d
No known key found for this signature in database
GPG Key ID: 1E9F677FB01A5688
6 changed files with 151 additions and 101 deletions

View File

@ -1,5 +1,5 @@
import { Component, OnInit, Output, EventEmitter, Input, ViewChild } from '@angular/core';
import { Subject } from 'rxjs';
import { Component, OnInit, Output, EventEmitter, Input, ViewChild, OnDestroy } from '@angular/core';
import { Subject, Subscription } from 'rxjs';
import { Store } from '@ngxs/store';
import { StreamElement, StreamTypeEnum, AddStream } from '../../../states/streams.state';
@ -12,8 +12,9 @@ import { AccountInfo } from '../../../states/accounts.state';
templateUrl: './hashtag.component.html',
styleUrls: ['./hashtag.component.scss']
})
export class HashtagComponent implements OnInit {
export class HashtagComponent implements OnInit, OnDestroy {
@Input() refreshEventEmitter: EventEmitter<any>;
@Output() browseAccountEvent = new EventEmitter<string>();
@Output() browseHashtagEvent = new EventEmitter<string>();
@Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
@ -27,18 +28,29 @@ export class HashtagComponent implements OnInit {
get hashtagElement(): StreamElement{
return this._hashtagElement;
}
@ViewChild('appStreamStatuses') appStreamStatuses: StreamStatusesComponent;
goToTopSubject: Subject<void> = new Subject<void>();
private lastUsedAccount: AccountInfo;
private refreshSubscription: Subscription;
constructor(
private readonly store: Store,
private readonly toolsService: ToolsService) { }
ngOnInit() {
if(this.refreshEventEmitter) {
this.refreshSubscription = this.refreshEventEmitter.subscribe(() => {
this.refresh();
})
}
}
ngOnDestroy(): void {
if(this.refreshSubscription) this.refreshSubscription.unsubscribe();
}
goToTop(): boolean {

View File

@ -4,29 +4,41 @@
<fa-icon [icon]="faTimes"></fa-icon>
</button>
<button class="overlay__button overlay-previous" [ngClass]="{'overlay__button--focus': previousElements.length > 0 }" title="previous" (click)="previous()">
<button class="overlay__button overlay-previous"
[ngClass]="{'overlay__button--focus': hasPreviousElements }" title="previous" (click)="previous()">
<fa-icon [icon]="faAngleLeft"></fa-icon>
</button>
<button class="overlay__button overlay-refresh" [ngClass]="{'overlay__button--focus': refreshFocused }" title="refresh" (click)="refresh()">
<button class="overlay__button overlay-refresh" [ngClass]="{'overlay__button--focus': refreshFocused }"
title="refresh" (click)="refresh()">
<fa-icon [icon]="faRedoAlt"></fa-icon>
</button>
<button class="overlay__button overlay-next" [ngClass]="{'overlay__button--focus': nextElements.length > 0 }" title="next" (click)="next()">
<button class="overlay__button overlay-next" [ngClass]="{'overlay__button--focus': hasNextElements > 0 }"
title="next" (click)="next()">
<fa-icon [icon]="faAngleRight"></fa-icon>
</button>
<!-- <a href class="overlay-close" (click)="close()">CLOSE</a>
<a href class="overlay-previous" (click)="previous()">PREV</a>
<a href class="overlay-refresh" *ngIf="canRefresh" (click)="refresh()">REFRESH</a>
<a href class="overlay-next" *ngIf="canGoForward" (click)="next()">NEXT</a> -->
</button>
</div>
<app-user-profile #appUserProfile *ngIf="accountName" [currentAccount]="accountName" class="stream-overlay__content"
(browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)"
(browseThreadEvent)="browseThread($event)"></app-user-profile>
<app-hashtag #appHashtag *ngIf="hashtagElement" [hashtagElement]="hashtagElement" class="stream-overlay__content"
(browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)"
(browseThreadEvent)="browseThread($event)"></app-hashtag>
<app-thread #appThread *ngIf="browseThread" [currentThread]="thread" class="stream-overlay__content"
(browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)"
(browseThreadEvent)="browseThread($event)"></app-thread>
<div *ngFor="let e of loadedElements" class="stream-overlay__content-wrapper"
[class.stream-overlay__content-wrapper--selected]="e.isVisible">
<app-user-profile #appUserProfile *ngIf="e.type === 'account'"
[currentAccount]="e.account"
[refreshEventEmitter]="e.refreshEventEmitter"
class="stream-overlay__content"
(browseAccountEvent)="browseAccount($event)"
(browseHashtagEvent)="browseHashtag($event)"
(browseThreadEvent)="browseThread($event)"></app-user-profile>
<app-hashtag #appHashtag *ngIf="e.type === 'hashtag'"
[hashtagElement]="e.hashtag"
[refreshEventEmitter]="e.refreshEventEmitter"
class="stream-overlay__content"
(browseAccountEvent)="browseAccount($event)"
(browseHashtagEvent)="browseHashtag($event)"
(browseThreadEvent)="browseThread($event)"></app-hashtag>
<app-thread #appThread *ngIf="e.type === 'thread'"
[currentThread]="e.thread" class="stream-overlay__content"
[refreshEventEmitter]="e.refreshEventEmitter"
(browseAccountEvent)="browseAccount($event)"
(browseHashtagEvent)="browseHashtag($event)"
(browseThreadEvent)="browseThread($event)"></app-thread>
</div>
</div>

View File

@ -3,9 +3,11 @@
@import "commons";
$header-content: 40px;
.stream-overlay {
// width: $stream-column-width;
// width: $stream-column-width;
height: calc(100%);
background-color: $column-color;
position: relative;
&__header {
width: calc(100%);
height: $header-content;
@ -17,6 +19,25 @@ $header-content: 40px;
font-weight: normal;
}
}
&__content-wrapper {
transition: all .2s;
position: absolute;
top: $header-content;
right: 0;
left: 0;
bottom: 0;
// outline: 1px solid greenyellow;
// background-color: salmon;
z-index: 1;
opacity: 0;
&--selected {
z-index: 10;
opacity: 1;
}
}
&__content {
display: block;
width: calc(100%);

View File

@ -5,9 +5,6 @@ import { Store } from '@ngxs/store';
import { ToolsService, OpenThreadEvent } from '../../../services/tools.service';
import { StreamElement, StreamTypeEnum } from '../../../states/streams.state';
import { ThreadComponent } from '../thread/thread.component';
import { UserProfileComponent } from '../user-profile/user-profile.component';
import { HashtagComponent } from '../hashtag/hashtag.component';
import { AccountInfo } from '../../../states/accounts.state';
@ -21,18 +18,13 @@ export class StreamOverlayComponent implements OnInit, OnDestroy {
faAngleRight = faAngleRight;
faTimes = faTimes;
faRedoAlt = faRedoAlt;
refreshFocused: boolean;
previousElements: OverlayBrowsing[] = [];
nextElements: OverlayBrowsing[] = [];
private currentElement: OverlayBrowsing;
hasPreviousElements: boolean;
hasNextElements: boolean;
// canRefresh: boolean = true;
// canGoForward: boolean;
accountName: string;
thread: OpenThreadEvent;
hashtagElement: StreamElement;
loadedElements: OverlayBrowsing[] = [];
visibleElementIndex: number = -1;
@Output() closeOverlay = new EventEmitter();
@ -51,17 +43,13 @@ export class StreamOverlayComponent implements OnInit, OnDestroy {
this.browseHashtag(hashtag);
}
@ViewChild('appUserProfile') appUserProfile: UserProfileComponent;
@ViewChild('appHashtag') appHashtag: HashtagComponent;
@ViewChild('appThread') appThread: ThreadComponent;
private currentlyUsedAccount: AccountInfo;
private accounts$: Observable<AccountInfo[]>;
private accountSub: Subscription;
constructor(
private readonly store: Store,
private readonly toolsService: ToolsService) {
private readonly toolsService: ToolsService) {
this.accounts$ = this.store.select(state => state.registeredaccounts.accounts);
}
@ -87,36 +75,41 @@ export class StreamOverlayComponent implements OnInit, OnDestroy {
}
next(): boolean {
if (this.nextElements.length === 0) {
if (this.visibleElementIndex >= this.loadedElements.length - 1) {
return false;
}
}
if (this.currentElement) {
this.previousElements.push(this.currentElement);
}
this.loadedElements[this.visibleElementIndex].hide();
let newIndex = this.visibleElementIndex + 1;
this.loadedElements[newIndex].show();
this.visibleElementIndex = newIndex;
const nextElement = this.nextElements.pop();
this.loadElement(nextElement);
console.warn(`visibleElementIndex ${this.visibleElementIndex}`);
console.warn(`this.loadedElements ${this.loadedElements.length}`);
//if(this.nextElements.length === 0) this.canGoForward = false;
this.hasPreviousElements = true;
this.hasNextElements = this.visibleElementIndex < this.loadedElements.length - 1;
return false;
}
previous(): boolean {
if (this.previousElements.length === 0) {
if (this.visibleElementIndex <= 0) {
this.closeOverlay.next();
return false;
}
if (this.currentElement) {
this.nextElements.push(this.currentElement);
}
this.loadedElements[this.visibleElementIndex].hide();
let newIndex = this.visibleElementIndex - 1;
this.loadedElements[newIndex].show();
this.visibleElementIndex = newIndex;
const previousElement = this.previousElements.pop();
this.loadElement(previousElement);
console.warn(`visibleElementIndex ${this.visibleElementIndex}`);
console.warn(`this.loadedElements ${this.loadedElements.length}`);
this.hasPreviousElements = this.visibleElementIndex > 0;
this.hasNextElements = true;
//this.canGoForward = true;
return false;
}
@ -124,92 +117,84 @@ export class StreamOverlayComponent implements OnInit, OnDestroy {
this.currentlyUsedAccount = this.toolsService.getSelectedAccounts()[0];
this.refreshFocused = false;
if(this.thread){
this.appThread.refresh();
} else if(this.hashtagElement){
this.appHashtag.refresh();
} else if(this.accountName){
this.appUserProfile.refresh();
}
this.loadedElements[this.visibleElementIndex].refresh();
return false;
}
browseAccount(accountName: string): void {
if(!accountName) return;
if (!accountName) return;
this.nextElements.length = 0;
if (this.currentElement) {
this.previousElements.push(this.currentElement);
}
const newElement = new OverlayBrowsing(null, accountName, null);
this.loadElement(newElement);
//this.canGoForward = false;
}
browseHashtag(hashtag: string): void {
if(!hashtag) return;
this.nextElements.length = 0;
if (this.currentElement) {
this.previousElements.push(this.currentElement);
}
if (!hashtag) return;
const selectedAccount = this.toolsService.getSelectedAccounts()[0];
const hashTagElement = new StreamElement(StreamTypeEnum.tag, hashtag, selectedAccount.id, hashtag, null, null, selectedAccount.instance);
const newElement = new OverlayBrowsing(hashTagElement, null, null);
this.loadElement(newElement);
// this.canGoForward = false;
}
browseThread(openThread: OpenThreadEvent): any {
if(!openThread) return;
this.nextElements.length = 0;
if (this.currentElement) {
this.previousElements.push(this.currentElement);
}
if (!openThread) return;
const newElement = new OverlayBrowsing(null, null, openThread);
this.loadElement(newElement);
//this.canGoForward = false;
}
private loadElement(element: OverlayBrowsing) {
this.currentlyUsedAccount = this.toolsService.getSelectedAccounts()[0];
this.refreshFocused = false;
this.refreshFocused = false;
this.currentElement = element;
if (this.visibleElementIndex >= 0) {
this.loadedElements[this.visibleElementIndex].hide();
this.loadedElements = this.loadedElements.slice(0, this.visibleElementIndex + 1);
}
this.accountName = this.currentElement.account;
this.thread = this.currentElement.thread;
this.hashtagElement = this.currentElement.hashtag;
this.visibleElementIndex = this.visibleElementIndex + 1;
this.loadedElements.push(element)
this.loadedElements[this.visibleElementIndex].show();
this.hasPreviousElements = this.visibleElementIndex > 0;
this.hasNextElements = false;
}
}
class OverlayBrowsing {
refreshEventEmitter = new EventEmitter();
constructor(
public readonly hashtag: StreamElement,
public readonly account: string,
public readonly thread: OpenThreadEvent) {
if (hashtag) {
this.type = OverlayEnum.hashtag;
this.type = 'hashtag';
} else if (account) {
this.type = OverlayEnum.account;
this.type = 'account';
} else if (thread) {
this.type = OverlayEnum.thread;
this.type = 'thread';
} else {
throw Error('NotImplemented');
}
}
type: OverlayEnum;
}
show(): any {
setTimeout(() => {
this.isVisible = true;
}, 200);
}
hide(): any {
this.isVisible = false;
}
enum OverlayEnum {
unknown = 0,
hashtag = 1,
account = 2,
thread = 3
refresh(): any {
this.refreshEventEmitter.next();
}
isVisible: boolean;
type: 'hashtag' | 'account' | 'thread';
}

View File

@ -28,6 +28,8 @@ export class ThreadComponent implements OnInit, OnDestroy {
@Output() browseHashtagEvent = new EventEmitter<string>();
@Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
@Input() refreshEventEmitter: EventEmitter<any>;
@Input('currentThread')
set currentThread(thread: OpenThreadEvent) {
if (thread) {
@ -41,6 +43,7 @@ export class ThreadComponent implements OnInit, OnDestroy {
private newPostSub: Subscription;
private hideAccountSubscription: Subscription;
private deleteStatusSubscription: Subscription;
private refreshSubscription: Subscription;
constructor(
private readonly notificationService: NotificationService,
@ -48,6 +51,12 @@ export class ThreadComponent implements OnInit, OnDestroy {
private readonly mastodonService: MastodonService) { }
ngOnInit() {
if(this.refreshEventEmitter) {
this.refreshSubscription = this.refreshEventEmitter.subscribe(() => {
this.refresh();
})
}
this.newPostSub = this.notificationService.newRespondPostedStream.subscribe((replyData: NewReplyData) => {
if(replyData){
const repondingStatus = this.statuses.find(x => x.status.id === replyData.uiStatusId);
@ -97,6 +106,7 @@ export class ThreadComponent implements OnInit, OnDestroy {
if (this.newPostSub) this.newPostSub.unsubscribe();
if (this.hideAccountSubscription) this.hideAccountSubscription.unsubscribe();
if (this.deleteStatusSubscription) this.deleteStatusSubscription.unsubscribe();
if(this.refreshSubscription) this.refreshSubscription.unsubscribe();
}
private getThread(openThreadEvent: OpenThreadEvent) {

View File

@ -55,6 +55,7 @@ export class UserProfileComponent implements OnInit {
private accounts$: Observable<AccountInfo[]>;
private accountSub: Subscription;
private deleteStatusSubscription: Subscription;
private refreshSubscription: Subscription;
@ViewChild('statusstream') public statustream: ElementRef;
@ViewChild('profilestatuses') public profilestatuses: ElementRef;
@ -63,6 +64,8 @@ export class UserProfileComponent implements OnInit {
@Output() browseHashtagEvent = new EventEmitter<string>();
@Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
@Input() refreshEventEmitter: EventEmitter<any>;
@Input('currentAccount')
set currentAccount(accountName: string) {
this.load(accountName);
@ -79,6 +82,12 @@ export class UserProfileComponent implements OnInit {
}
ngOnInit() {
if(this.refreshEventEmitter) {
this.refreshSubscription = this.refreshEventEmitter.subscribe(() => {
this.refresh();
})
}
this.accountSub = this.accounts$.subscribe((accounts: AccountInfo[]) => {
if (this.displayedAccount) {
const userAccount = accounts.filter(x => x.isSelected)[0];
@ -107,8 +116,9 @@ export class UserProfileComponent implements OnInit {
}
ngOnDestroy() {
this.accountSub.unsubscribe();
this.deleteStatusSubscription.unsubscribe();
if(this.accountSub) this.accountSub.unsubscribe();
if(this.deleteStatusSubscription) this.deleteStatusSubscription.unsubscribe();
if(this.refreshSubscription) this.refreshSubscription.unsubscribe();
}
private load(accountName: string) {