Sengi-Windows-MacOS-Linux/src/app/components/stream/status/action-bar/action-bar.component.ts

321 lines
11 KiB
TypeScript
Raw Normal View History

2019-07-01 22:30:28 +02:00
import { Component, OnInit, OnDestroy, Input, Output, EventEmitter, ViewChild } from '@angular/core';
2019-02-12 04:33:54 +01:00
import { HttpErrorResponse } from '@angular/common/http';
2018-10-02 06:19:11 +02:00
import { Store } from '@ngxs/store';
2018-10-13 17:38:23 +02:00
import { Observable, Subscription } from 'rxjs';
2019-06-01 20:22:12 +02:00
import { faWindowClose, faReply, faRetweet, faStar, faEllipsisH, faLock } from "@fortawesome/free-solid-svg-icons";
import { faWindowClose as faWindowCloseRegular } from "@fortawesome/free-regular-svg-icons";
2019-07-04 01:55:33 +02:00
import { ContextMenuComponent, ContextMenuService } from 'ngx-contextmenu';
2018-10-02 06:19:11 +02:00
import { MastodonService } from '../../../../services/mastodon.service';
import { AccountInfo } from '../../../../states/accounts.state';
2019-07-04 00:25:35 +02:00
import { Status, Account } from '../../../../services/models/mastodon.interfaces';
2019-07-04 02:23:23 +02:00
import { ToolsService, OpenThreadEvent } from '../../../../services/tools.service';
2019-02-12 04:33:54 +01:00
import { NotificationService } from '../../../../services/notification.service';
import { StatusWrapper } from '../../../../models/common.model';
2019-07-04 01:55:33 +02:00
import { NavigationService } from '../../../../services/navigation.service';
2019-07-01 22:30:28 +02:00
@Component({
selector: 'app-action-bar',
templateUrl: './action-bar.component.html',
styleUrls: ['./action-bar.component.scss']
})
export class ActionBarComponent implements OnInit, OnDestroy {
faWindowClose = faWindowClose;
faReply = faReply;
faRetweet = faRetweet;
faStar = faStar;
faWindowCloseRegular = faWindowCloseRegular;
2019-06-01 20:22:12 +02:00
faEllipsisH = faEllipsisH;
faLock = faLock;
2019-07-04 02:08:05 +02:00
@ViewChild(ContextMenuComponent) public contextMenu: ContextMenuComponent;
2019-07-01 22:30:28 +02:00
public items = [
{ name: 'John', otherProperty: 'Foo' },
{ name: 'Joe', otherProperty: 'Bar' }
];
@Input() statusWrapper: StatusWrapper;
2018-10-13 07:10:43 +02:00
@Output() replyEvent = new EventEmitter();
@Output() cwIsActiveEvent = new EventEmitter<boolean>();
2019-07-04 02:23:23 +02:00
@Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
isFavorited: boolean;
isBoosted: boolean;
2018-10-02 06:19:11 +02:00
isBoostLocked: boolean;
isLocked: boolean;
2019-04-07 20:18:10 +02:00
favoriteIsLoading: boolean;
boostIsLoading: boolean;
isContentWarningActive: boolean = false;
private isProviderSelected: boolean;
private selectedAccounts: AccountInfo[];
private favoriteStatePerAccountId: { [id: string]: boolean; } = {};
private bootedStatePerAccountId: { [id: string]: boolean; } = {};
private accounts$: Observable<AccountInfo[]>;
private accountSub: Subscription;
2018-10-02 06:19:11 +02:00
constructor(
2019-07-04 01:55:33 +02:00
private readonly navigationService: NavigationService,
private readonly contextMenuService: ContextMenuService,
2018-10-02 06:19:11 +02:00
private readonly store: Store,
2019-02-12 04:28:15 +01:00
private readonly toolsService: ToolsService,
2019-04-07 20:18:10 +02:00
private readonly mastodonService: MastodonService,
2019-02-12 04:33:54 +01:00
private readonly notificationService: NotificationService) {
this.accounts$ = this.store.select(state => state.registeredaccounts.accounts);
}
2019-07-04 00:25:35 +02:00
username: string;
private fullHandle: string;
private displayedStatus: Status;
2019-07-04 00:43:37 +02:00
private loadedAccounts: AccountInfo[];
2019-07-04 00:25:35 +02:00
ngOnInit() {
const status = this.statusWrapper.status;
const account = this.statusWrapper.provider;
2019-04-07 21:51:32 +02:00
2019-07-03 23:53:53 +02:00
if (status.reblog) {
2019-04-07 21:51:32 +02:00
this.favoriteStatePerAccountId[account.id] = status.reblog.favourited;
this.bootedStatePerAccountId[account.id] = status.reblog.reblogged;
2019-07-04 00:25:35 +02:00
this.extractHandle(status.reblog.account);
this.displayedStatus = status.reblog;
2019-04-07 21:51:32 +02:00
} else {
this.favoriteStatePerAccountId[account.id] = status.favourited;
this.bootedStatePerAccountId[account.id] = status.reblogged;
2019-07-04 00:25:35 +02:00
this.extractHandle(status.account);
this.displayedStatus = status;
2019-07-03 23:53:53 +02:00
}
this.accountSub = this.accounts$.subscribe((accounts: AccountInfo[]) => {
2019-07-04 00:43:37 +02:00
this.loadedAccounts = accounts;
this.checkStatus(accounts);
});
}
2019-07-04 00:25:35 +02:00
private extractHandle(account: Account) {
this.username = account.acct.split('@')[0];
2019-07-04 01:55:33 +02:00
this.fullHandle = account.acct.toLowerCase();
2019-07-04 00:25:35 +02:00
if (!this.fullHandle.includes('@')) {
this.fullHandle += `@${account.url.replace('https://', '').split('/')[0]}`;
}
2019-07-04 02:15:53 +02:00
this.fullHandle = `@${this.fullHandle}`;
2019-07-04 00:25:35 +02:00
}
ngOnDestroy(): void {
this.accountSub.unsubscribe();
}
2018-10-04 02:13:31 +02:00
private checkStatus(accounts: AccountInfo[]): void {
const status = this.statusWrapper.status;
const provider = this.statusWrapper.provider;
this.selectedAccounts = accounts.filter(x => x.isSelected);
this.isProviderSelected = this.selectedAccounts.filter(x => x.id === provider.id).length > 0;
if (status.visibility === 'direct' || status.visibility === 'private') {
this.isBoostLocked = true;
} else {
this.isBoostLocked = false;
}
if ((status.visibility === 'direct' || status.visibility === 'private') && !this.isProviderSelected) {
this.isLocked = true;
} else {
this.isLocked = false;
}
2019-04-07 20:18:10 +02:00
if (status.sensitive || status.spoiler_text) {
this.isContentWarningActive = true;
}
this.checkIfFavorited();
this.checkIfBoosted();
}
showContent(): boolean {
this.isContentWarningActive = false;
this.cwIsActiveEvent.next(false);
return false;
}
hideContent(): boolean {
this.isContentWarningActive = true;
this.cwIsActiveEvent.next(true);
return false;
}
reply(): boolean {
2018-10-13 07:10:43 +02:00
this.replyEvent.emit();
return false;
}
boost(): boolean {
2019-07-03 23:53:53 +02:00
if (this.boostIsLoading) return;
2019-04-07 20:18:10 +02:00
this.boostIsLoading = true;
const account = this.toolsService.getSelectedAccounts()[0];
const usableStatus = this.toolsService.getStatusUsableByAccount(account, this.statusWrapper);
usableStatus
.then((status: Status) => {
if (this.isBoosted && status.reblogged) {
return this.mastodonService.unreblog(account, status);
} else if (!this.isBoosted && !status.reblogged) {
return this.mastodonService.reblog(account, status);
} else {
return Promise.resolve(status);
}
})
.then((boostedStatus: Status) => {
2019-07-03 23:53:53 +02:00
if (boostedStatus.pleroma) {
2019-04-13 23:04:24 +02:00
this.bootedStatePerAccountId[account.id] = boostedStatus.reblog !== null; //FIXME: when Pleroma will return the good status
} else {
this.bootedStatePerAccountId[account.id] = boostedStatus.reblogged;
2019-07-03 23:53:53 +02:00
}
2019-04-07 20:18:10 +02:00
this.checkIfBoosted();
})
.catch((err: HttpErrorResponse) => {
this.notificationService.notifyHttpError(err);
})
.then(() => {
this.boostIsLoading = false;
});
return false;
}
favorite(): boolean {
2019-07-03 23:53:53 +02:00
if (this.favoriteIsLoading) return;
2019-04-07 20:18:10 +02:00
this.favoriteIsLoading = true;
const account = this.toolsService.getSelectedAccounts()[0];
const usableStatus = this.toolsService.getStatusUsableByAccount(account, this.statusWrapper);
usableStatus
.then((status: Status) => {
if (this.isFavorited && status.favourited) {
return this.mastodonService.unfavorite(account, status);
} else if (!this.isFavorited && !status.favourited) {
return this.mastodonService.favorite(account, status);
} else {
return Promise.resolve(status);
}
})
.then((favoritedStatus: Status) => {
this.favoriteStatePerAccountId[account.id] = favoritedStatus.favourited;
this.checkIfFavorited();
// this.isFavorited = !this.isFavorited;
})
.catch((err: HttpErrorResponse) => {
this.notificationService.notifyHttpError(err);
})
.then(() => {
this.favoriteIsLoading = false;
});
return false;
}
private checkIfBoosted() {
const selectedAccount = <AccountInfo>this.selectedAccounts[0];
if (selectedAccount) {
this.isBoosted = this.bootedStatePerAccountId[selectedAccount.id];
} else {
this.isBoosted = false;
}
}
private checkIfFavorited() {
const selectedAccount = <AccountInfo>this.selectedAccounts[0];
if (selectedAccount) {
this.isFavorited = this.favoriteStatePerAccountId[selectedAccount.id];
} else {
this.isFavorited = false;
}
}
2019-07-04 02:08:05 +02:00
public onContextMenu($event: MouseEvent): void {
2019-07-02 04:05:48 +02:00
this.contextMenuService.show.next({
2019-07-03 23:53:53 +02:00
// Optional - if unspecified, all context menu components will open
2019-07-04 02:08:05 +02:00
contextMenu: this.contextMenu,
2019-07-03 23:53:53 +02:00
event: $event,
2019-07-04 02:08:05 +02:00
item: null
2019-07-02 04:05:48 +02:00
});
$event.preventDefault();
$event.stopPropagation();
2019-07-03 23:53:53 +02:00
}
expandStatus(): boolean {
2019-07-04 02:23:23 +02:00
const openThread = new OpenThreadEvent(this.displayedStatus, this.statusWrapper.provider);
this.browseThreadEvent.next(openThread);
2019-07-03 23:53:53 +02:00
return false;
}
copyStatusLink(): boolean {
2019-07-04 00:25:35 +02:00
let selBox = document.createElement('textarea');
selBox.style.position = 'fixed';
selBox.style.left = '0';
selBox.style.top = '0';
selBox.style.opacity = '0';
selBox.value = this.displayedStatus.url;
document.body.appendChild(selBox);
selBox.focus();
selBox.select();
document.execCommand('copy');
document.body.removeChild(selBox);
2019-07-03 23:53:53 +02:00
return false;
}
mentionAccount(): boolean {
2019-07-04 01:55:33 +02:00
this.navigationService.replyToUser(this.fullHandle, false);
2019-07-03 23:53:53 +02:00
return false;
}
dmAccount(): boolean {
2019-07-04 01:55:33 +02:00
this.navigationService.replyToUser(this.fullHandle, true);
2019-07-03 23:53:53 +02:00
return false;
}
muteAccount(): boolean {
2019-07-04 00:43:37 +02:00
this.loadedAccounts.forEach(acc => {
this.toolsService.findAccount(acc, this.fullHandle)
.then((target: Account) => {
this.mastodonService.mute(acc, target.id);
2019-07-04 00:55:46 +02:00
return target;
})
.then((target: Account) => {
this.notificationService.hideAccount(target);
2019-07-04 00:43:37 +02:00
})
.catch(err => {
this.notificationService.notifyHttpError(err);
});
});
2019-07-03 23:53:53 +02:00
return false;
}
blockAccount(): boolean {
2019-07-04 00:43:37 +02:00
this.loadedAccounts.forEach(acc => {
this.toolsService.findAccount(acc, this.fullHandle)
.then((target: Account) => {
this.mastodonService.block(acc, target.id);
2019-07-04 00:55:46 +02:00
return target;
})
.then((target: Account) => {
this.notificationService.hideAccount(target);
2019-07-04 00:43:37 +02:00
})
.catch(err => {
this.notificationService.notifyHttpError(err);
});
});
2019-07-03 23:53:53 +02:00
return false;
}
}