mirror of
https://github.com/NicolasConstant/sengi
synced 2025-02-02 11:36:54 +01:00
commit
c674d8f52c
@ -10,7 +10,7 @@
|
||||
<select class="form-control form-control-sm form-control--privacy" id="privacy" name="privacy" [(ngModel)]="selectedPrivacy">
|
||||
<option *ngFor="let p of privacyList" [ngValue]="p">{{p}}</option>
|
||||
</select>
|
||||
<button type="submit" class="btn btn-sm btn-custom-primary">TOOT!</button>
|
||||
<button type="submit" class="btn btn-sm btn-custom-primary">POST!</button>
|
||||
</form>
|
||||
|
||||
|
||||
|
@ -24,16 +24,16 @@ export class ManageAccountComponent implements OnInit {
|
||||
ngOnInit() {
|
||||
const instance = this.account.info.instance;
|
||||
this.availableStreams.length = 0;
|
||||
this.availableStreams.push(new StreamElement(StreamTypeEnum.global, 'Federated Timeline', this.account.info.id, null, null, `federate@${instance}`));
|
||||
this.availableStreams.push(new StreamElement(StreamTypeEnum.local, 'Local Timeline', this.account.info.id, null, null, `local@${instance}`));
|
||||
this.availableStreams.push(new StreamElement(StreamTypeEnum.personnal, 'Home', this.account.info.id, null, null, `home@${instance}`));
|
||||
this.availableStreams.push(new StreamElement(StreamTypeEnum.global, 'Federated Timeline', this.account.info.id, null, null, instance));
|
||||
this.availableStreams.push(new StreamElement(StreamTypeEnum.local, 'Local Timeline', this.account.info.id, null, null, instance));
|
||||
this.availableStreams.push(new StreamElement(StreamTypeEnum.personnal, 'Home', this.account.info.id, null, null, instance));
|
||||
}
|
||||
|
||||
addStream(stream: StreamElement): boolean {
|
||||
if (stream) {
|
||||
this.store.dispatch([new AddStream(stream)]).toPromise()
|
||||
.then(() => {
|
||||
this.notificationService.notify(`${stream.displayableFullName} added`, false);
|
||||
this.notificationService.notify(`stream added`, false);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
|
@ -1,39 +1,44 @@
|
||||
<div class="panel">
|
||||
<h3 class="panel__title">search</h3>
|
||||
|
||||
<form class="form-section" (ngSubmit)="onSubmit()">
|
||||
<input type="text" class="form-control form-control-sm form-with-button" [(ngModel)]="searchHandle" name="searchHandle"
|
||||
placeholder="Search" autocomplete="off" />
|
||||
<button class="form-button" type="submit" title="search">GO</button>
|
||||
</form>
|
||||
<div class="search-result-form">
|
||||
<h3 class="panel__title">search</h3>
|
||||
|
||||
<app-waiting-animation *ngIf="isLoading" class="waiting-icon"></app-waiting-animation>
|
||||
|
||||
<div *ngIf="accounts.length > 0" class="search-results">
|
||||
<h3 class="search-results__title">Accounts</h3>
|
||||
<a href *ngFor="let account of accounts" class="account" title="open account"
|
||||
(click)="browseAccount(account.acct)">
|
||||
<img src="{{account.avatar}}" class="account__avatar" />
|
||||
<div class="account__name">{{ account.username }}</div>
|
||||
<div class="account__fullhandle">@{{ account.acct }}</div>
|
||||
</a>
|
||||
<form class="form-section" (ngSubmit)="onSubmit()">
|
||||
<input type="text" class="form-control form-control-sm form-with-button" [(ngModel)]="searchHandle"
|
||||
name="searchHandle" placeholder="Search" autocomplete="off" />
|
||||
<button class="form-button" type="submit" title="search">GO</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div *ngIf="hashtags.length > 0" class="search-results">
|
||||
<h3 class="search-results__title">Hashtags</h3>
|
||||
<a (click)="browseHashtag(hashtag)" href *ngFor="let hashtag of hashtags" class="search-results__hashtag" title="browse hashtag">
|
||||
#{{ hashtag }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="search-result-display flexcroll">
|
||||
<app-waiting-animation *ngIf="isLoading" class="waiting-icon"></app-waiting-animation>
|
||||
|
||||
<div *ngIf="statuses.length > 0" class="search-results">
|
||||
<h3 class="search-results__title">Statuses</h3>
|
||||
<div *ngIf="accounts.length > 0" class="search-results">
|
||||
<h3 class="search-results__title">Accounts</h3>
|
||||
<a href *ngFor="let account of accounts" class="account" title="open account"
|
||||
(click)="browseAccount(account.acct)">
|
||||
<img src="{{account.avatar}}" class="account__avatar" />
|
||||
<div class="account__name">{{ account.username }}</div>
|
||||
<div class="account__fullhandle">@{{ account.acct }}</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="search-results__status" *ngFor="let statusWrapper of statuses">
|
||||
<app-status [statusWrapper]="statusWrapper"
|
||||
(browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-status>
|
||||
<div *ngIf="hashtags.length > 0" class="search-results">
|
||||
<h3 class="search-results__title">Hashtags</h3>
|
||||
<a (click)="browseHashtag(hashtag)" href *ngFor="let hashtag of hashtags" class="search-results__hashtag"
|
||||
title="browse hashtag">
|
||||
#{{ hashtag }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div *ngIf="statuses.length > 0" class="search-results">
|
||||
<h3 class="search-results__title">Statuses</h3>
|
||||
|
||||
<div class="search-results__status" *ngFor="let statusWrapper of statuses">
|
||||
<app-status [statusWrapper]="statusWrapper" (browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)" (browseThreadEvent)="browseThread($event)">
|
||||
</app-status>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -2,7 +2,10 @@
|
||||
@import "mixins";
|
||||
@import "panel";
|
||||
@import "commons";
|
||||
|
||||
.panel {
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
overflow: auto;
|
||||
@ -29,10 +32,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
$search-form-height: 70px;
|
||||
.search-result-form {
|
||||
height: $search-form-height;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
border-bottom: 1px solid #222736;
|
||||
}
|
||||
|
||||
.search-result-display {
|
||||
overflow: auto;
|
||||
height: calc(100% - #{$search-form-height});
|
||||
}
|
||||
|
||||
.search-results {
|
||||
// outline: 1px solid greenyellow;
|
||||
margin-top: 10px; // &:first-of-type{
|
||||
// margin-top: 10px;
|
||||
padding-left: 10px; // margin-top: 10px;
|
||||
padding-right: 10px; // margin-top: 10px;
|
||||
// }
|
||||
&__title {
|
||||
text-transform: uppercase;
|
||||
@ -44,18 +61,15 @@
|
||||
padding: 5px;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
|
||||
transition: all .3s;
|
||||
&:hover {
|
||||
background-color: $button-background-color-hover;
|
||||
}
|
||||
|
||||
border-top: 1px solid $separator-color;
|
||||
&:last-of-type {
|
||||
border-bottom: 1px solid $separator-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__status {
|
||||
font-size: 15px;
|
||||
border-top: 1px solid $separator-color;
|
||||
@ -68,12 +82,8 @@
|
||||
.account {
|
||||
display: block;
|
||||
color: white;
|
||||
|
||||
border-radius: 2px;
|
||||
transition: all .3s;
|
||||
|
||||
|
||||
// &:hover &__name {
|
||||
transition: all .3s; // &:hover &__name {
|
||||
// text-decoration: underline;
|
||||
// }
|
||||
border-top: 1px solid $separator-color;
|
||||
@ -92,18 +102,15 @@
|
||||
&__fullhandle {
|
||||
margin: 0 0 5px 0;
|
||||
color: $status-secondary-color;
|
||||
transition: all .3s;
|
||||
// &:hover {
|
||||
transition: all .3s; // &:hover {
|
||||
// color: white;
|
||||
// }
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:hover &__fullhandle {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
background-color: $button-background-color-hover;
|
||||
}
|
||||
|
||||
@include clearfix;
|
||||
}
|
@ -44,7 +44,7 @@ $inner-column-size: 320px;
|
||||
|
||||
.hashtag-stream {
|
||||
display: block;
|
||||
height: calc(100% - #{$hashtag-header-height} - 30px);
|
||||
height: calc(100% - #{$hashtag-header-height});
|
||||
width: $inner-column-size;
|
||||
// outline: 1px greenyellow solid;
|
||||
}
|
@ -50,7 +50,7 @@ export class HashtagComponent implements OnInit {
|
||||
event.stopPropagation();
|
||||
|
||||
const hashtag = this.hashtagElement.tag;
|
||||
const newStream = new StreamElement(StreamTypeEnum.tag, `${hashtag}`, this.lastUsedAccount.id, hashtag, null, this.hashtagElement.displayableFullName);
|
||||
const newStream = new StreamElement(StreamTypeEnum.tag, `${hashtag}`, this.lastUsedAccount.id, hashtag, null, this.lastUsedAccount.instance);
|
||||
this.store.dispatch([new AddStream(newStream)]);
|
||||
|
||||
return false;
|
||||
|
@ -1,21 +1,32 @@
|
||||
<div class="stream-overlay">
|
||||
<div class="stream-overlay__header">
|
||||
<a href class="overlay-close" (click)="close()">CLOSE</a>
|
||||
<button class="overlay__button overlay-close" title="close" (click)="close()">
|
||||
<fa-icon [icon]="faTimes"></fa-icon>
|
||||
</button>
|
||||
|
||||
<button class="overlay__button overlay-previous" [ngClass]="{'overlay__button--focus': previousElements.length > 0 }" 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()">
|
||||
<fa-icon [icon]="faRedoAlt"></fa-icon>
|
||||
</button>
|
||||
<button class="overlay__button overlay-next" [ngClass]="{'overlay__button--focus': nextElements.length > 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>
|
||||
<a href class="overlay-next" *ngIf="canGoForward" (click)="next()">NEXT</a> -->
|
||||
</div>
|
||||
|
||||
<app-user-profile #appUserProfile *ngIf="accountName" [currentAccount]="accountName"
|
||||
(browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)"
|
||||
<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"
|
||||
(browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)"
|
||||
<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"
|
||||
(browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)"
|
||||
<app-thread #appThread *ngIf="browseThread" [currentThread]="thread" class="stream-overlay__content"
|
||||
(browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-thread>
|
||||
</div>
|
@ -1,20 +1,27 @@
|
||||
@import "variables";
|
||||
@import "mixins";
|
||||
@import "commons";
|
||||
$header-content: 40px;
|
||||
.stream-overlay {
|
||||
// width: $stream-column-width;
|
||||
height: calc(100%);
|
||||
background-color: $column-color;
|
||||
&__header {
|
||||
width: calc(100%);
|
||||
height: 30px;
|
||||
background-color: $column-header-background-color;
|
||||
padding: 6px 10px 0 10px;
|
||||
height: $header-content;
|
||||
background-color: $column-header-background-color; // padding: 6px 10px 0 10px;
|
||||
border-bottom: 1px solid #222736;
|
||||
& a {
|
||||
color: whitesmoke;
|
||||
font-size: 0.8em;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
&__content {
|
||||
display: block;
|
||||
width: calc(100%);
|
||||
height: calc(100% - #{$header-content});
|
||||
}
|
||||
&__title {
|
||||
width: calc(100%);
|
||||
height: 30px;
|
||||
@ -27,23 +34,45 @@
|
||||
|
||||
.overlay {
|
||||
margin: 0;
|
||||
&__button {
|
||||
@include clearButton;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
color: #354060;
|
||||
transition: all .2s;
|
||||
margin: 8px 0 0 8px;
|
||||
&:hover {
|
||||
color: whitesmoke;
|
||||
}
|
||||
&--focus {
|
||||
color: whitesmoke;
|
||||
}
|
||||
}
|
||||
&-previous {
|
||||
display: block;
|
||||
float: left;
|
||||
font-size: 18px;
|
||||
& fa-icon {
|
||||
position: relative;
|
||||
left: -1px;
|
||||
}
|
||||
}
|
||||
&-refresh {
|
||||
display: block;
|
||||
float: left;
|
||||
margin-left: 65px;
|
||||
font-size: 14px;
|
||||
}
|
||||
&-next {
|
||||
display: block;
|
||||
float: right;
|
||||
padding-right: 20px;
|
||||
float: left;
|
||||
font-size: 18px;
|
||||
}
|
||||
&-close {
|
||||
display: block;
|
||||
float: right;
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,28 +1,37 @@
|
||||
import { Component, OnInit, Output, EventEmitter, Input, ViewChild } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy, Output, EventEmitter, Input, ViewChild } from '@angular/core';
|
||||
import { faAngleLeft, faAngleRight, faTimes, faRedoAlt } from "@fortawesome/free-solid-svg-icons";
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
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';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-stream-overlay',
|
||||
templateUrl: './stream-overlay.component.html',
|
||||
styleUrls: ['./stream-overlay.component.scss']
|
||||
})
|
||||
export class StreamOverlayComponent implements OnInit {
|
||||
export class StreamOverlayComponent implements OnInit, OnDestroy {
|
||||
faAngleLeft = faAngleLeft;
|
||||
faAngleRight = faAngleRight;
|
||||
faTimes = faTimes;
|
||||
faRedoAlt = faRedoAlt;
|
||||
|
||||
private previousElements: OverlayBrowsing[] = [];
|
||||
private nextElements: OverlayBrowsing[] = [];
|
||||
refreshFocused: boolean;
|
||||
previousElements: OverlayBrowsing[] = [];
|
||||
nextElements: OverlayBrowsing[] = [];
|
||||
private currentElement: OverlayBrowsing;
|
||||
|
||||
canRefresh: boolean = true;
|
||||
canGoForward: boolean;
|
||||
// canRefresh: boolean = true;
|
||||
// canGoForward: boolean;
|
||||
|
||||
accountName: string;
|
||||
thread: OpenThreadEvent;
|
||||
// hashtag: string;
|
||||
hashtagElement: StreamElement;
|
||||
|
||||
@Output() closeOverlay = new EventEmitter();
|
||||
@ -30,7 +39,6 @@ export class StreamOverlayComponent implements OnInit {
|
||||
@Input('browseAccountData')
|
||||
set browseAccountData(accountName: string) {
|
||||
this.browseAccount(accountName);
|
||||
// this.accountName = accountName;
|
||||
}
|
||||
|
||||
@Input('browseThreadData')
|
||||
@ -47,9 +55,30 @@ export class StreamOverlayComponent implements OnInit {
|
||||
@ViewChild('appHashtag') appHashtag: HashtagComponent;
|
||||
@ViewChild('appThread') appThread: ThreadComponent;
|
||||
|
||||
constructor(private readonly toolsService: ToolsService) { }
|
||||
private currentlyUsedAccount: AccountInfo;
|
||||
private accounts$: Observable<AccountInfo[]>;
|
||||
private accountSub: Subscription;
|
||||
|
||||
constructor(
|
||||
private readonly store: Store,
|
||||
private readonly toolsService: ToolsService) {
|
||||
this.accounts$ = this.store.select(state => state.registeredaccounts.accounts);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.currentlyUsedAccount = this.toolsService.getSelectedAccounts()[0];
|
||||
this.accountSub = this.accounts$.subscribe((accounts: AccountInfo[]) => {
|
||||
this.checkAccountChanges(accounts);
|
||||
});
|
||||
}
|
||||
|
||||
checkAccountChanges(accounts: AccountInfo[]): any {
|
||||
const selectedAccount = accounts.filter(x => x.isSelected)[0];
|
||||
this.refreshFocused = selectedAccount.id !== this.currentlyUsedAccount.id;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.accountSub.unsubscribe();
|
||||
}
|
||||
|
||||
close(): boolean {
|
||||
@ -69,7 +98,8 @@ export class StreamOverlayComponent implements OnInit {
|
||||
const nextElement = this.nextElements.pop();
|
||||
this.loadElement(nextElement);
|
||||
|
||||
if(this.nextElements.length === 0) this.canGoForward = false;
|
||||
//if(this.nextElements.length === 0) this.canGoForward = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -86,11 +116,14 @@ export class StreamOverlayComponent implements OnInit {
|
||||
const previousElement = this.previousElements.pop();
|
||||
this.loadElement(previousElement);
|
||||
|
||||
this.canGoForward = true;
|
||||
//this.canGoForward = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
refresh(): boolean {
|
||||
this.currentlyUsedAccount = this.toolsService.getSelectedAccounts()[0];
|
||||
this.refreshFocused = false;
|
||||
|
||||
if(this.thread){
|
||||
this.appThread.refresh();
|
||||
} else if(this.hashtagElement){
|
||||
@ -111,7 +144,7 @@ export class StreamOverlayComponent implements OnInit {
|
||||
}
|
||||
const newElement = new OverlayBrowsing(null, accountName, null);
|
||||
this.loadElement(newElement);
|
||||
this.canGoForward = false;
|
||||
//this.canGoForward = false;
|
||||
}
|
||||
|
||||
browseHashtag(hashtag: string): void {
|
||||
@ -123,10 +156,10 @@ export class StreamOverlayComponent implements OnInit {
|
||||
}
|
||||
|
||||
const selectedAccount = this.toolsService.getSelectedAccounts()[0];
|
||||
const hashTagElement = new StreamElement(StreamTypeEnum.tag, hashtag, selectedAccount.id, hashtag, null, `#${hashtag}@${selectedAccount.instance}`);
|
||||
const hashTagElement = new StreamElement(StreamTypeEnum.tag, hashtag, selectedAccount.id, hashtag, null, selectedAccount.instance);
|
||||
const newElement = new OverlayBrowsing(hashTagElement, null, null);
|
||||
this.loadElement(newElement);
|
||||
this.canGoForward = false;
|
||||
// this.canGoForward = false;
|
||||
}
|
||||
|
||||
browseThread(openThread: OpenThreadEvent): any {
|
||||
@ -139,10 +172,13 @@ export class StreamOverlayComponent implements OnInit {
|
||||
|
||||
const newElement = new OverlayBrowsing(null, null, openThread);
|
||||
this.loadElement(newElement);
|
||||
this.canGoForward = false;
|
||||
//this.canGoForward = false;
|
||||
}
|
||||
|
||||
private loadElement(element: OverlayBrowsing) {
|
||||
this.currentlyUsedAccount = this.toolsService.getSelectedAccounts()[0];
|
||||
this.refreshFocused = false;
|
||||
|
||||
this.currentElement = element;
|
||||
|
||||
this.accountName = this.currentElement.account;
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div class="stream-toots flexcroll" #statusstream (scroll)="onScroll()">
|
||||
<app-waiting-animation *ngIf="isLoading" class="waiting-icon"></app-waiting-animation>
|
||||
<app-waiting-animation *ngIf="statuses.length === 0" class="waiting-icon"></app-waiting-animation>
|
||||
|
||||
<div *ngIf="displayError" class="stream-toots__error">{{displayError}}</div>
|
||||
|
||||
|
@ -1,25 +1,27 @@
|
||||
<div class="stream-column">
|
||||
|
||||
<app-stream-overlay class="stream-overlay" *ngIf="overlayActive" (closeOverlay)="closeOverlay()"
|
||||
[browseAccountData]="overlayAccountToBrowse"
|
||||
[browseHashtagData]="overlayHashtagToBrowse"
|
||||
[browseAccountData]="overlayAccountToBrowse" [browseHashtagData]="overlayHashtagToBrowse"
|
||||
[browseThreadData]="overlayThreadToBrowse"></app-stream-overlay>
|
||||
|
||||
<div class="stream-column__stream-header">
|
||||
<a class="stream-column__open-menu" href title="edit column" (click)="openEditionMenu()">
|
||||
<fa-icon class="stream-column__open-menu--icon" [icon]="menuFaIcon"></fa-icon>
|
||||
</a>
|
||||
<a class="stream-column__stream-selector" href title="return to top" (click)="goToTop()">
|
||||
<fa-icon class="stream-column__stream-selector--icon" [icon]="columnFaIcon"></fa-icon>
|
||||
<h1 class="stream-column__stream-selector--title">{{ streamElement.name.toUpperCase() }}</h1>
|
||||
<span class="stream-column__stream-selector--subtitle"
|
||||
*ngIf="streamElement.instance">{{ streamElement.instance.toLowerCase() }}</span>
|
||||
</a>
|
||||
<a class="stream-column__open-menu" href title="edit column" (click)="openEditionMenu()">
|
||||
<fa-icon class="stream-column__open-menu--icon" [icon]="menuFaIcon"></fa-icon>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<app-stream-edition class="stream-edition" *ngIf="editionPanelIsOpen"
|
||||
[streamElement]="streamElement"></app-stream-edition>
|
||||
<app-stream-edition class="stream-edition" *ngIf="editionPanelIsOpen" [streamElement]="streamElement">
|
||||
</app-stream-edition>
|
||||
|
||||
<app-stream-statuses class="stream-statuses" [streamElement]="streamElement" [goToTop]="goToTopSubject.asObservable()"
|
||||
(browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)" (browseThreadEvent)="browseThread($event)"></app-stream-statuses>
|
||||
<app-stream-statuses class="stream-statuses" [streamElement]="streamElement"
|
||||
[goToTop]="goToTopSubject.asObservable()" (browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)" (browseThreadEvent)="browseThread($event)"></app-stream-statuses>
|
||||
<!-- <div class="stream-toots flexcroll" #statusstream (scroll)="onScroll()">
|
||||
<div class="stream-toots__status" *ngFor="let statusWrapper of statuses">
|
||||
<app-status [statusWrapper]="statusWrapper" (browseAccount)="browseAccount($event)" (browseHashtag)="browseHashtag($event)"></app-status>
|
||||
|
@ -17,17 +17,20 @@ $stream-header-height: 40px;
|
||||
border-bottom: 1px solid #222736;
|
||||
}
|
||||
&__open-menu {
|
||||
float: right;
|
||||
display: block;
|
||||
width: $stream-header-height - 10px;
|
||||
height: $stream-header-height - 10px;
|
||||
margin: 5px;
|
||||
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
|
||||
&:hover &--icon {
|
||||
color: darken(whitesmoke, 30);
|
||||
}
|
||||
&--icon {
|
||||
color: whitesmoke; // float: left;
|
||||
position: relative;
|
||||
// position: relative;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 8px;
|
||||
}
|
||||
@ -37,20 +40,30 @@ $stream-header-height: 40px;
|
||||
width: calc(100%);
|
||||
height: $stream-header-height;
|
||||
background-color: $column-header-background-color;
|
||||
text-decoration: none; // &:hover {
|
||||
// }
|
||||
text-decoration: none;
|
||||
color: whitesmoke;
|
||||
position: relative;
|
||||
&--icon {
|
||||
color: whitesmoke;
|
||||
float: left;
|
||||
position: relative;
|
||||
left: 11px;
|
||||
top: 9px;
|
||||
}
|
||||
&--title {
|
||||
color: whitesmoke;
|
||||
font-size: 0.8em;
|
||||
font-weight: normal; // margin: 0 0 0 25px;
|
||||
padding: 14px 0 0 35px;
|
||||
font-weight: normal;
|
||||
position: absolute;
|
||||
top: 9px;
|
||||
left: 35px;
|
||||
}
|
||||
&--subtitle {
|
||||
color: $font-link-primary-hover;
|
||||
font-size: 0.7em;
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
position: absolute;
|
||||
top: 21px;
|
||||
left: 35px;;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,53 @@
|
||||
<div class="profile ">
|
||||
<div class="profile flexcroll">
|
||||
<app-waiting-animation *ngIf="isLoading" class="waiting-icon"></app-waiting-animation>
|
||||
|
||||
<div class="profile-sub-header flexcroll">
|
||||
<div *ngIf="account" class="profile-header" [ngStyle]="{'background-image':'url('+account.header+')'}">
|
||||
<div class="profile-header__inner">
|
||||
<!-- <img class="profile-header__header" src="{{account.header}}" alt="header" /> -->
|
||||
<img class="profile-header__avatar" src="{{account.avatar}}" alt="header" />
|
||||
<h2 class="profile-header__display-name">{{account.display_name}}</h2>
|
||||
<h2 class="profile-header__fullhandle"><a href="{{account.url}}" target="_blank">@{{account.acct}}</a></h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="account && hasNote" class="profile-description">
|
||||
<app-databinded-text class="status__content" [textIsSelectable]="false" [text]="account.note"
|
||||
(accountSelected)="browseAccount($event)"
|
||||
(hashtagSelected)="browseHashtag($event)"></app-databinded-text>
|
||||
<!-- <p innerHTML="{{account.note}}"></p> -->
|
||||
<div *ngIf="account" class="profile-header" [ngStyle]="{'background-image':'url('+account.header+')'}">
|
||||
<div class="profile-header__inner">
|
||||
<!-- <img class="profile-header__header" src="{{account.header}}" alt="header" /> -->
|
||||
<img class="profile-header__avatar" src="{{account.avatar}}" alt="header" />
|
||||
<h2 class="profile-header__display-name">{{account.display_name}}</h2>
|
||||
<h2 class="profile-header__fullhandle"><a href="{{account.url}}" target="_blank">@{{account.acct}}</a></h2>
|
||||
|
||||
<div class="profile-header__follow" *ngIf="relationship">
|
||||
<button class="profile-header__follow--button profile-header__follow--unfollowed" title="follow"
|
||||
(click)="follow()" *ngIf="!relationship.following && !relationship.requested">
|
||||
<fa-icon [icon]="faUserRegular"></fa-icon>
|
||||
</button>
|
||||
<button class="profile-header__follow--button profile-header__follow--followed" title="unfollow"
|
||||
(click)="unfollow()" *ngIf="relationship.following">
|
||||
<fa-icon [icon]="faUserCheck"></fa-icon>
|
||||
</button>
|
||||
<button class="profile-header__follow--button profile-header__follow--followed" title="pending"
|
||||
(click)="unfollow()" *ngIf="relationship.requested">
|
||||
<fa-icon [icon]="faHourglassHalf"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="profile-header__state" *ngIf="relationship">
|
||||
<div class="profile-header__state--data" *ngIf="relationship.followed_by">follows you</div>
|
||||
<div class="profile-header__state--data" *ngIf="relationship.blocking">blocked</div>
|
||||
<div class="profile-header__state--data" *ngIf="relationship.muting">muted</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="profile-sub-header ">
|
||||
<div *ngIf="account && hasNote" class="profile-description">
|
||||
<!-- <div *ngIf="account && account.note" class="profile-description"> -->
|
||||
<app-databinded-text class="profile-description__content" [textIsSelectable]="false" [text]="account.note"
|
||||
(accountSelected)="browseAccount($event)" (hashtagSelected)="browseHashtag($event)">
|
||||
</app-databinded-text>
|
||||
</div>
|
||||
<div class="profile-fields" *ngIf="account && account.fields.length > 0">
|
||||
<div class="profile-fields__field" *ngFor="let field of account.fields">
|
||||
<div class="profile-fields__field--value" innerHTML="{{field.value}}" [ngClass]="{'profile-fields__field--validated': field.verified_at }">
|
||||
</div>
|
||||
<div class="profile-fields__field--name">
|
||||
{{ field.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="profile-statuses">
|
||||
<app-waiting-animation *ngIf="statusLoading" class="waiting-icon"></app-waiting-animation>
|
||||
|
||||
@ -25,10 +56,9 @@
|
||||
</div>
|
||||
|
||||
<div *ngFor="let statusWrapper of statuses">
|
||||
<app-status [statusWrapper]="statusWrapper"
|
||||
(browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseAccountEvent)="browseAccount($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-status>
|
||||
<app-status [statusWrapper]="statusWrapper" (browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseAccountEvent)="browseAccount($event)" (browseThreadEvent)="browseThread($event)">
|
||||
</app-status>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,12 +1,13 @@
|
||||
@import "variables";
|
||||
@import "mixins";
|
||||
@import "commons";
|
||||
|
||||
$validated-font-color: #4fde23;
|
||||
$validated-background: #164109;
|
||||
$header-height: 160px;
|
||||
|
||||
.profile {
|
||||
// overflow: auto;
|
||||
height: calc(100% - 30px);
|
||||
|
||||
height: calc(100%);
|
||||
overflow: auto;
|
||||
&-header {
|
||||
background-size: cover;
|
||||
position: relative; // height: 140px;
|
||||
@ -31,34 +32,131 @@ $header-height: 160px;
|
||||
position: absolute;
|
||||
top: 105px;
|
||||
left: 15px;
|
||||
width: calc(100% - 30px);
|
||||
overflow: hidden;
|
||||
color: white;
|
||||
}
|
||||
&__fullhandle a {
|
||||
position: absolute;
|
||||
top: 130px;
|
||||
left: 15px;
|
||||
width: calc(100% - 30px);
|
||||
overflow: hidden;
|
||||
color: white;
|
||||
}
|
||||
&__follow {
|
||||
// transition: all .4s;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 15px;
|
||||
font-size: 28px;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
&--button {
|
||||
@include clearButton;
|
||||
}
|
||||
&--unfollowed {}
|
||||
&--followed {
|
||||
color: #38abff;
|
||||
color: #5fbcff;
|
||||
color: #85ccff;
|
||||
}
|
||||
}
|
||||
&__state {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
right: 15px;
|
||||
font-size: 12px;
|
||||
&--data {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-sub-header {
|
||||
overflow: auto;
|
||||
height: calc(100% - #{$header-height});
|
||||
height: calc(100%);
|
||||
// overflow: auto;
|
||||
// height: calc(100% - #{$header-height});
|
||||
// height: calc(100%);
|
||||
// height: calc(20% - 190px);
|
||||
// height: 150px;
|
||||
// border: 1px solid greenyellow;
|
||||
}
|
||||
|
||||
&-description {
|
||||
padding: 10px 10px 15px 10px;
|
||||
font-size: 13px;
|
||||
border-bottom: 1px solid black;
|
||||
&__content {
|
||||
width: calc(100%);
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
&-fields {
|
||||
font-size: 13px;
|
||||
border-bottom: 1px solid black;
|
||||
&__field {
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
&--name {
|
||||
padding: 10px;
|
||||
border-right: 1px solid black;
|
||||
text-align: center;
|
||||
width: calc(33%);
|
||||
background-color: #0b0d13;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
&--value {
|
||||
padding: 10px;
|
||||
width: calc(66%);
|
||||
float: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
&--validated {
|
||||
background-color: $validated-background;
|
||||
// border: 1px solid $validated-font-color;
|
||||
}
|
||||
}
|
||||
@include clearfix;
|
||||
}
|
||||
|
||||
&-no-toots {
|
||||
text-align: center;
|
||||
margin: 15px;
|
||||
border: 2px solid whitesmoke;
|
||||
}
|
||||
}
|
||||
|
||||
//Mastodon styling
|
||||
:host ::ng-deep .profile-fields__field--value {
|
||||
// font-size: 14px;
|
||||
color: $status-primary-color;
|
||||
& a,
|
||||
.mention,
|
||||
.ellipsis {
|
||||
color: $status-links-color;
|
||||
}
|
||||
& .invisible {
|
||||
display: none;
|
||||
}
|
||||
& p {
|
||||
margin: 0px; //font-size: .9em;
|
||||
// font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
:host ::ng-deep .profile-fields__field--validated {
|
||||
// font-size: 14px;
|
||||
color: $validated-font-color;
|
||||
& a,
|
||||
.mention,
|
||||
.ellipsis {
|
||||
color: $validated-font-color;
|
||||
}
|
||||
& .invisible {
|
||||
display: none;
|
||||
}
|
||||
& p {
|
||||
margin: 0px; //font-size: .9em;
|
||||
// font-size: 14px;
|
||||
}
|
||||
}
|
@ -1,11 +1,18 @@
|
||||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { faUser, faHourglassHalf, faUserCheck } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faUser as faUserRegular } from "@fortawesome/free-regular-svg-icons";
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { Store } from '@ngxs/store';
|
||||
|
||||
import { Account, Status } from "../../../services/models/mastodon.interfaces";
|
||||
import { Account, Status, Relationship } from "../../../services/models/mastodon.interfaces";
|
||||
import { MastodonService } from '../../../services/mastodon.service';
|
||||
import { ToolsService, OpenThreadEvent } from '../../../services/tools.service';
|
||||
import { StatusWrapper } from '../stream.component';
|
||||
import { NotificationService } from '../../../services/notification.service';
|
||||
import { AccountInfo } from '../../../states/accounts.state';
|
||||
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-user-profile',
|
||||
@ -13,6 +20,10 @@ import { NotificationService } from '../../../services/notification.service';
|
||||
styleUrls: ['./user-profile.component.scss']
|
||||
})
|
||||
export class UserProfileComponent implements OnInit {
|
||||
faUser = faUser;
|
||||
faUserRegular = faUserRegular;
|
||||
faHourglassHalf = faHourglassHalf;
|
||||
faUserCheck = faUserCheck;
|
||||
|
||||
account: Account;
|
||||
hasNote: boolean;
|
||||
@ -21,38 +32,77 @@ export class UserProfileComponent implements OnInit {
|
||||
statusLoading: boolean;
|
||||
error: string;
|
||||
|
||||
relationship: Relationship;
|
||||
statuses: StatusWrapper[] = [];
|
||||
|
||||
private lastAccountName: string;
|
||||
|
||||
private currentlyUsedAccount: AccountInfo;
|
||||
private accounts$: Observable<AccountInfo[]>;
|
||||
private accountSub: Subscription;
|
||||
|
||||
@Output() browseAccountEvent = new EventEmitter<string>();
|
||||
@Output() browseHashtagEvent = new EventEmitter<string>();
|
||||
@Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
|
||||
|
||||
@Input('currentAccount')
|
||||
//set currentAccount(account: Account) {
|
||||
set currentAccount(accountName: string) {
|
||||
this.lastAccountName = accountName;
|
||||
this.load(this.lastAccountName);
|
||||
this.load(accountName);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly store: Store,
|
||||
private readonly notificationService: NotificationService,
|
||||
private readonly mastodonService: MastodonService,
|
||||
private readonly toolsService: ToolsService) { }
|
||||
private readonly toolsService: ToolsService) {
|
||||
|
||||
this.accounts$ = this.store.select(state => state.registeredaccounts.accounts);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.accountSub = this.accounts$.subscribe((accounts: AccountInfo[]) => {
|
||||
if (this.account) {
|
||||
this.currentlyUsedAccount = accounts.filter(x => x.isSelected)[0];
|
||||
|
||||
this.toolsService.findAccount(this.currentlyUsedAccount, this.lastAccountName)
|
||||
.then((account: Account) => {
|
||||
this.getFollowStatus(this.currentlyUsedAccount, account);
|
||||
})
|
||||
.catch((err: HttpErrorResponse) => {
|
||||
this.notificationService.notifyHttpError(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.accountSub.unsubscribe();
|
||||
}
|
||||
|
||||
private load(accountName: string) {
|
||||
this.statuses.length = 0;
|
||||
|
||||
this.account = null;
|
||||
this.isLoading = true;
|
||||
|
||||
this.loadAccount(accountName)
|
||||
this.lastAccountName = accountName;
|
||||
this.currentlyUsedAccount = this.toolsService.getSelectedAccounts()[0];
|
||||
|
||||
return this.toolsService.findAccount(this.currentlyUsedAccount, this.lastAccountName)
|
||||
.then((account: Account) => {
|
||||
|
||||
console.warn(account);
|
||||
|
||||
this.isLoading = false;
|
||||
this.statusLoading = true;
|
||||
|
||||
this.account = account;
|
||||
this.hasNote = account && account.note && account.note !== '<p></p>';
|
||||
return this.getStatuses(this.account);
|
||||
|
||||
const getFollowStatusPromise = this.getFollowStatus(this.currentlyUsedAccount, this.account);
|
||||
const getStatusesPromise = this.getStatuses(this.currentlyUsedAccount, this.account);
|
||||
|
||||
return Promise.all([getFollowStatusPromise, getStatusesPromise]);
|
||||
})
|
||||
.catch((err: HttpErrorResponse) => {
|
||||
this.notificationService.notifyHttpError(err);
|
||||
@ -63,6 +113,26 @@ export class UserProfileComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
private getStatuses(userAccount: AccountInfo, account: Account): Promise<void> {
|
||||
this.statusLoading = true;
|
||||
return this.mastodonService.getAccountStatuses(userAccount, account.id, false, false, true, null, null, 40)
|
||||
.then((result: Status[]) => {
|
||||
for (const status of result) {
|
||||
const wrapper = new StatusWrapper(status, userAccount);
|
||||
this.statuses.push(wrapper);
|
||||
}
|
||||
this.statusLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
private getFollowStatus(userAccount: AccountInfo, account: Account): Promise<void> {
|
||||
// this.relationship = null;
|
||||
return this.mastodonService.getRelationships(userAccount, [account])
|
||||
.then((result: Relationship[]) => {
|
||||
this.relationship = result.filter(x => x.id === account.id)[0];
|
||||
});
|
||||
}
|
||||
|
||||
refresh(): any {
|
||||
this.load(this.lastAccountName);
|
||||
}
|
||||
@ -79,37 +149,33 @@ export class UserProfileComponent implements OnInit {
|
||||
this.browseThreadEvent.next(openThreadEvent);
|
||||
}
|
||||
|
||||
private loadAccount(accountName: string): Promise<Account> {
|
||||
this.account = null;
|
||||
|
||||
let selectedAccounts = this.toolsService.getSelectedAccounts();
|
||||
|
||||
if (selectedAccounts.length === 0) {
|
||||
this.error = 'no user selected';
|
||||
console.error(this.error);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
this.isLoading = true;
|
||||
return this.toolsService.findAccount(selectedAccounts[0], accountName)
|
||||
.then((result) => {
|
||||
this.isLoading = false;
|
||||
return result;
|
||||
follow(): boolean {
|
||||
this.currentlyUsedAccount = this.toolsService.getSelectedAccounts()[0];
|
||||
this.toolsService.findAccount(this.currentlyUsedAccount, this.lastAccountName)
|
||||
.then((account: Account) => {
|
||||
return this.mastodonService.follow(this.currentlyUsedAccount, account);
|
||||
})
|
||||
.then((relationship: Relationship) => {
|
||||
this.relationship = relationship;
|
||||
})
|
||||
.catch((err: HttpErrorResponse) => {
|
||||
this.notificationService.notifyHttpError(err);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
private getStatuses(account: Account): Promise<void> {
|
||||
let selectedAccounts = this.toolsService.getSelectedAccounts();
|
||||
if (selectedAccounts.length === 0) return;
|
||||
|
||||
this.statusLoading = true;
|
||||
return this.mastodonService.getAccountStatuses(selectedAccounts[0], account.id, false, false, true, null, null, 40)
|
||||
.then((result: Status[]) => {
|
||||
for (const status of result) {
|
||||
const wrapper = new StatusWrapper(status, selectedAccounts[0]);
|
||||
this.statuses.push(wrapper);
|
||||
}
|
||||
this.statusLoading = false;
|
||||
unfollow(): boolean {
|
||||
this.currentlyUsedAccount = this.toolsService.getSelectedAccounts()[0];
|
||||
this.toolsService.findAccount(this.currentlyUsedAccount, this.lastAccountName)
|
||||
.then((account: Account) => {
|
||||
return this.mastodonService.unfollow(this.currentlyUsedAccount, account);
|
||||
})
|
||||
.then((relationship: Relationship) => {
|
||||
this.relationship = relationship;
|
||||
})
|
||||
.catch((err: HttpErrorResponse) => {
|
||||
this.notificationService.notifyHttpError(err);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div class="streams-selection-footer">
|
||||
<a class="stream-selection" *ngFor="let str of streams; let i=index" href (click)="onColumnSelection(i)" title="open {{str.displayableFullName}}">
|
||||
<a class="stream-selection" *ngFor="let str of streams; let i=index" href (click)="onColumnSelection(i)" title="open {{getDisplayableName(str)}}">
|
||||
<span class="stream-selection__column-reprensentation"></span>
|
||||
</a>
|
||||
</div>
|
@ -1,32 +1,54 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { StreamElement } from '../../states/streams.state';
|
||||
import { StreamElement, StreamTypeEnum } from '../../states/streams.state';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { NavigationService } from '../../services/navigation.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-streams-selection-footer',
|
||||
templateUrl: './streams-selection-footer.component.html',
|
||||
styleUrls: ['./streams-selection-footer.component.scss']
|
||||
selector: 'app-streams-selection-footer',
|
||||
templateUrl: './streams-selection-footer.component.html',
|
||||
styleUrls: ['./streams-selection-footer.component.scss']
|
||||
})
|
||||
export class StreamsSelectionFooterComponent implements OnInit {
|
||||
streams: StreamElement[] = [];
|
||||
private streams$: Observable<StreamElement[]>;
|
||||
streams: StreamElement[] = [];
|
||||
private streams$: Observable<StreamElement[]>;
|
||||
|
||||
constructor(
|
||||
private readonly navigationService: NavigationService,
|
||||
private readonly store: Store) {
|
||||
this.streams$ = this.store.select(state => state.streamsstatemodel.streams);
|
||||
}
|
||||
constructor(
|
||||
private readonly navigationService: NavigationService,
|
||||
private readonly store: Store) {
|
||||
this.streams$ = this.store.select(state => state.streamsstatemodel.streams);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.streams$.subscribe((streams: StreamElement[]) => {
|
||||
this.streams = streams;
|
||||
});
|
||||
}
|
||||
ngOnInit() {
|
||||
this.streams$.subscribe((streams: StreamElement[]) => {
|
||||
this.streams = streams;
|
||||
});
|
||||
}
|
||||
|
||||
onColumnSelection(index: number): boolean {
|
||||
this.navigationService.columnSelected(index);
|
||||
return false;
|
||||
}
|
||||
onColumnSelection(index: number): boolean {
|
||||
this.navigationService.columnSelected(index);
|
||||
return false;
|
||||
}
|
||||
|
||||
getDisplayableName(stream: StreamElement): string {
|
||||
let prefix = '';
|
||||
switch (stream.type) {
|
||||
case StreamTypeEnum.local:
|
||||
prefix = "local";
|
||||
break;
|
||||
case StreamTypeEnum.personnal:
|
||||
prefix = "home";
|
||||
break;
|
||||
case StreamTypeEnum.global:
|
||||
prefix = "federated";
|
||||
break;
|
||||
case StreamTypeEnum.tag:
|
||||
prefix = `#${stream.tag}`;
|
||||
break;
|
||||
case StreamTypeEnum.list:
|
||||
prefix = `${stream.list}`;
|
||||
break;
|
||||
}
|
||||
return `${prefix}@${stream.instance}`;
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
<div class="open-account__mouse-icon"></div>
|
||||
<h3 class="open-account__title">Nice!</h3>
|
||||
<p class="open-account__description">
|
||||
Now <span class="underline">left-click</span> on your avatar to open your account and be able to add some timelines!
|
||||
Now <span class="underline">right-click</span> on your avatar to open your account and be able to add some timelines!
|
||||
</p>
|
||||
</div>
|
||||
<!-- </div> -->
|
@ -2,14 +2,14 @@ import { Injectable } from '@angular/core';
|
||||
import { HttpHeaders, HttpClient } from '@angular/common/http';
|
||||
|
||||
import { ApiRoutes } from './models/api.settings';
|
||||
import { Account, Status, Results, Context } from "./models/mastodon.interfaces";
|
||||
import { Account, Status, Results, Context, Relationship } from "./models/mastodon.interfaces";
|
||||
import { AccountInfo } from '../states/accounts.state';
|
||||
import { StreamTypeEnum } from '../states/streams.state';
|
||||
import { stat } from 'fs';
|
||||
import { forEach } from '@angular/router/src/utils/collection';
|
||||
|
||||
@Injectable()
|
||||
export class MastodonService {
|
||||
|
||||
private apiRoutes = new ApiRoutes();
|
||||
|
||||
constructor(private readonly httpClient: HttpClient) { }
|
||||
@ -166,6 +166,32 @@ export class MastodonService {
|
||||
const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}` });
|
||||
return this.httpClient.post<Status>(route, null, { headers: headers }).toPromise()
|
||||
}
|
||||
|
||||
getRelationships(account: AccountInfo, accountsToRetrieve: Account[]): Promise<Relationship[]> {
|
||||
let params = "?";
|
||||
accountsToRetrieve.forEach(x => {
|
||||
if(params.includes('id')) params += '&';
|
||||
params += `id[]=${x.id}`;
|
||||
});
|
||||
|
||||
const route = `https://${account.instance}${this.apiRoutes.getAccountRelationships}${params}`;
|
||||
const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}` });
|
||||
return this.httpClient.get<Relationship[]>(route, { headers: headers }).toPromise();
|
||||
}
|
||||
|
||||
follow(currentlyUsedAccount: AccountInfo, account: Account): Promise<Relationship> {
|
||||
const route = `https://${currentlyUsedAccount.instance}${this.apiRoutes.follow}`.replace('{0}', account.id.toString());
|
||||
const headers = new HttpHeaders({ 'Authorization': `Bearer ${currentlyUsedAccount.token.access_token}` });
|
||||
return this.httpClient.post<Relationship>(route, null, { headers: headers }).toPromise();
|
||||
}
|
||||
|
||||
unfollow(currentlyUsedAccount: AccountInfo, account: Account): Promise<Relationship> {
|
||||
const route = `https://${currentlyUsedAccount.instance}${this.apiRoutes.unfollow}`.replace('{0}', account.id.toString());
|
||||
const headers = new HttpHeaders({ 'Authorization': `Bearer ${currentlyUsedAccount.token.access_token}` });
|
||||
return this.httpClient.post<Relationship>(route, null, { headers: headers }).toPromise();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export enum VisibilityEnum {
|
||||
|
@ -1,136 +1,153 @@
|
||||
export interface AppData {
|
||||
client_id: string;
|
||||
client_secret: string;
|
||||
id: string;
|
||||
name: string;
|
||||
redirect_uri: string;
|
||||
website: string;
|
||||
client_id: string;
|
||||
client_secret: string;
|
||||
id: string;
|
||||
name: string;
|
||||
redirect_uri: string;
|
||||
website: string;
|
||||
}
|
||||
|
||||
export interface TokenData {
|
||||
access_token: string;
|
||||
token_type: string;
|
||||
scope: string;
|
||||
created_at: string;
|
||||
access_token: string;
|
||||
token_type: string;
|
||||
scope: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface Account {
|
||||
id: number;
|
||||
username: string;
|
||||
acct: string;
|
||||
display_name: string;
|
||||
locked: string;
|
||||
created_at: string;
|
||||
followers_count: number;
|
||||
following_count: number;
|
||||
statuses_count: number;
|
||||
note: string;
|
||||
url: string;
|
||||
avatar: string;
|
||||
avatar_static: string;
|
||||
header: string;
|
||||
header_static: string;
|
||||
id: number;
|
||||
username: string;
|
||||
acct: string;
|
||||
display_name: string;
|
||||
locked: string;
|
||||
created_at: string;
|
||||
followers_count: number;
|
||||
following_count: number;
|
||||
statuses_count: number;
|
||||
note: string;
|
||||
url: string;
|
||||
avatar: string;
|
||||
avatar_static: string;
|
||||
header: string;
|
||||
header_static: string;
|
||||
emojis: Emoji[];
|
||||
moved: boolean;
|
||||
fields: Field[];
|
||||
bot: boolean;
|
||||
}
|
||||
|
||||
export interface Emoji {
|
||||
shortcode: string;
|
||||
static_url: string;
|
||||
url: string;
|
||||
visible_in_picker: boolean;
|
||||
}
|
||||
|
||||
export interface Field {
|
||||
name: string;
|
||||
value: string;
|
||||
verified_at: string;
|
||||
}
|
||||
|
||||
export interface Application {
|
||||
name: string;
|
||||
website: string;
|
||||
name: string;
|
||||
website: string;
|
||||
}
|
||||
|
||||
export interface Attachment {
|
||||
id: string;
|
||||
type: 'image' | 'video' | 'gifv';
|
||||
url: string;
|
||||
remote_url: string;
|
||||
preview_url: string;
|
||||
text_url: string;
|
||||
id: string;
|
||||
type: 'image' | 'video' | 'gifv';
|
||||
url: string;
|
||||
remote_url: string;
|
||||
preview_url: string;
|
||||
text_url: string;
|
||||
}
|
||||
|
||||
export interface Card {
|
||||
url: string;
|
||||
title: string;
|
||||
description: string;
|
||||
image: string;
|
||||
url: string;
|
||||
title: string;
|
||||
description: string;
|
||||
image: string;
|
||||
}
|
||||
|
||||
export interface Context {
|
||||
ancestors: Status[];
|
||||
descendants: Status[];
|
||||
ancestors: Status[];
|
||||
descendants: Status[];
|
||||
}
|
||||
|
||||
export interface Error {
|
||||
error: string;
|
||||
error: string;
|
||||
}
|
||||
|
||||
export interface Instance {
|
||||
uri: string;
|
||||
title: string;
|
||||
description: string;
|
||||
email: string;
|
||||
uri: string;
|
||||
title: string;
|
||||
description: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export interface Mention {
|
||||
url: string;
|
||||
username: string;
|
||||
acct: string;
|
||||
id: string;
|
||||
url: string;
|
||||
username: string;
|
||||
acct: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface Notification {
|
||||
id: string;
|
||||
type: 'mention' | 'reblog' | 'favourite' | 'follow';
|
||||
created_at: string;
|
||||
account: Account;
|
||||
status?: Status;
|
||||
id: string;
|
||||
type: 'mention' | 'reblog' | 'favourite' | 'follow';
|
||||
created_at: string;
|
||||
account: Account;
|
||||
status?: Status;
|
||||
}
|
||||
|
||||
export interface Relationship {
|
||||
id: string;
|
||||
following: string;
|
||||
followed_by: string;
|
||||
blocking: string;
|
||||
muting: string;
|
||||
requested: string;
|
||||
id: number;
|
||||
following: boolean;
|
||||
followed_by: boolean;
|
||||
blocking: boolean;
|
||||
muting: boolean;
|
||||
requested: boolean;
|
||||
}
|
||||
|
||||
export interface Report {
|
||||
id: string;
|
||||
action_taken: boolean;
|
||||
id: string;
|
||||
action_taken: boolean;
|
||||
}
|
||||
|
||||
export interface Results {
|
||||
accounts: Account[];
|
||||
statuses: Status[];
|
||||
hashtags: string[];
|
||||
accounts: Account[];
|
||||
statuses: Status[];
|
||||
hashtags: string[];
|
||||
}
|
||||
|
||||
export interface Status {
|
||||
id: string;
|
||||
uri: string;
|
||||
url: string;
|
||||
account: Account;
|
||||
in_reply_to_id: string;
|
||||
in_reply_to_account_id: string;
|
||||
reblog: Status;
|
||||
content: string;
|
||||
created_at: string;
|
||||
reblogs_count: string;
|
||||
favourites_count: string;
|
||||
reblogged: boolean;
|
||||
favourited: boolean;
|
||||
sensitive: boolean;
|
||||
spoiler_text: string;
|
||||
visibility: string;
|
||||
media_attachments: Attachment[];
|
||||
mentions: Mention[];
|
||||
tags: Tag[];
|
||||
application: Application;
|
||||
emojis: any[];
|
||||
language: string;
|
||||
pinned: boolean;
|
||||
id: string;
|
||||
uri: string;
|
||||
url: string;
|
||||
account: Account;
|
||||
in_reply_to_id: string;
|
||||
in_reply_to_account_id: string;
|
||||
reblog: Status;
|
||||
content: string;
|
||||
created_at: string;
|
||||
reblogs_count: string;
|
||||
favourites_count: string;
|
||||
reblogged: boolean;
|
||||
favourited: boolean;
|
||||
sensitive: boolean;
|
||||
spoiler_text: string;
|
||||
visibility: string;
|
||||
media_attachments: Attachment[];
|
||||
mentions: Mention[];
|
||||
tags: Tag[];
|
||||
application: Application;
|
||||
emojis: any[];
|
||||
language: string;
|
||||
pinned: boolean;
|
||||
}
|
||||
export interface Tag {
|
||||
name: string;
|
||||
url: string;
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,8 @@ export class NotificationService {
|
||||
|
||||
public notifyHttpError(err: HttpErrorResponse){
|
||||
console.error(err.message);
|
||||
let message = `${err.status}: ${err.statusText}`;
|
||||
// let message = `${err.status}: ${err.statusText}`;
|
||||
let message = `${err.statusText}`;
|
||||
this.notify(message, true);
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ export class StreamElement {
|
||||
public accountId: string,
|
||||
public tag: string,
|
||||
public list: string,
|
||||
public displayableFullName: string) {
|
||||
public instance: string) {
|
||||
this.id = `${type}-${name}-${accountId}`;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
padding: 10px 10px 0 7px;
|
||||
font-size: $small-font-size;
|
||||
white-space: normal;
|
||||
// overflow: auto;
|
||||
&__title {
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
|
Loading…
x
Reference in New Issue
Block a user