2020-05-22 08:34:08 +02:00
|
|
|
import { Component, Input } from '@angular/core';
|
2019-02-12 05:41:21 +01:00
|
|
|
import { HttpErrorResponse } from '@angular/common/http';
|
|
|
|
import { Observable, Subscription } from 'rxjs';
|
2018-11-16 05:57:52 +01:00
|
|
|
import { Store } from '@ngxs/store';
|
|
|
|
|
2024-03-09 06:40:37 +01:00
|
|
|
import { StreamElement, StreamTypeEnum } from '../../../states/streams.state';
|
2018-11-16 05:57:52 +01:00
|
|
|
import { AccountInfo } from '../../../states/accounts.state';
|
2020-05-22 08:34:08 +02:00
|
|
|
import { StreamingService, EventEnum, StatusUpdate } from '../../../services/streaming.service';
|
2018-11-16 05:57:52 +01:00
|
|
|
import { Status } from '../../../services/models/mastodon.interfaces';
|
2019-10-02 06:14:40 +02:00
|
|
|
import { MastodonWrapperService } from '../../../services/mastodon-wrapper.service';
|
2019-02-12 05:41:21 +01:00
|
|
|
import { NotificationService } from '../../../services/notification.service';
|
2020-05-22 08:34:08 +02:00
|
|
|
import { ToolsService } from '../../../services/tools.service';
|
2019-03-06 04:46:50 +01:00
|
|
|
import { StatusWrapper } from '../../../models/common.model';
|
2020-04-19 07:06:22 +02:00
|
|
|
import { TimeLineModeEnum } from '../../../states/settings.state';
|
2020-05-22 08:17:26 +02:00
|
|
|
import { TimelineBase } from '../../common/timeline-base';
|
2021-02-28 08:38:42 +01:00
|
|
|
import { SettingsService } from '../../../services/settings.service';
|
2018-11-16 05:57:52 +01:00
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'app-stream-statuses',
|
|
|
|
templateUrl: './stream-statuses.component.html',
|
|
|
|
styleUrls: ['./stream-statuses.component.scss']
|
|
|
|
})
|
2024-03-09 06:40:37 +01:00
|
|
|
export class StreamStatusesComponent extends TimelineBase {
|
2020-05-22 08:17:26 +02:00
|
|
|
protected _streamElement: StreamElement;
|
2018-11-16 05:57:52 +01:00
|
|
|
|
2024-03-09 06:40:37 +01:00
|
|
|
context: 'home' | 'notifications' | 'public' | 'thread' | 'account';
|
|
|
|
|
2018-11-16 05:57:52 +01:00
|
|
|
@Input()
|
|
|
|
set streamElement(streamElement: StreamElement) {
|
|
|
|
this._streamElement = streamElement;
|
2019-06-24 20:22:42 +02:00
|
|
|
|
|
|
|
this.hideBoosts = streamElement.hideBoosts;
|
|
|
|
this.hideBots = streamElement.hideBots;
|
|
|
|
this.hideReplies = streamElement.hideReplies;
|
|
|
|
|
2019-02-19 05:45:35 +01:00
|
|
|
this.load(this._streamElement);
|
2024-03-09 06:40:37 +01:00
|
|
|
|
|
|
|
this.setContext(this._streamElement);
|
2018-11-16 05:57:52 +01:00
|
|
|
}
|
|
|
|
get streamElement(): StreamElement {
|
|
|
|
return this._streamElement;
|
|
|
|
}
|
|
|
|
|
|
|
|
private goToTopSubscription: Subscription;
|
2019-06-24 05:11:16 +02:00
|
|
|
private streamsSubscription: Subscription;
|
2019-07-04 00:55:46 +02:00
|
|
|
private hideAccountSubscription: Subscription;
|
2020-04-18 03:46:38 +02:00
|
|
|
private deleteStatusSubscription: Subscription;
|
2019-06-24 05:11:16 +02:00
|
|
|
private streams$: Observable<StreamElement[]>;
|
2018-11-16 05:57:52 +01:00
|
|
|
|
|
|
|
constructor(
|
2021-02-28 08:38:42 +01:00
|
|
|
protected readonly settingsService: SettingsService,
|
2020-05-22 08:17:26 +02:00
|
|
|
protected readonly store: Store,
|
|
|
|
protected readonly toolsService: ToolsService,
|
|
|
|
protected readonly notificationService: NotificationService,
|
|
|
|
protected readonly streamingService: StreamingService,
|
|
|
|
protected readonly mastodonService: MastodonWrapperService) {
|
2019-06-24 05:11:16 +02:00
|
|
|
|
2020-05-22 08:17:26 +02:00
|
|
|
super(toolsService, notificationService, mastodonService);
|
2019-06-24 05:11:16 +02:00
|
|
|
this.streams$ = this.store.select(state => state.streamsstatemodel.streams);
|
2018-11-16 05:57:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ngOnInit() {
|
2021-02-28 08:38:42 +01:00
|
|
|
let settings = this.settingsService.getSettings();
|
2020-04-19 07:06:22 +02:00
|
|
|
this.timelineLoadingMode = settings.timelineMode;
|
|
|
|
|
2018-11-16 05:57:52 +01:00
|
|
|
this.goToTopSubscription = this.goToTop.subscribe(() => {
|
|
|
|
this.applyGoToTop();
|
|
|
|
});
|
2019-06-24 05:11:16 +02:00
|
|
|
|
|
|
|
this.streamsSubscription = this.streams$.subscribe((streams: StreamElement[]) => {
|
2019-06-24 20:22:42 +02:00
|
|
|
let updatedStream = streams.find(x => x.id === this.streamElement.id);
|
2019-09-28 21:52:04 +02:00
|
|
|
if (!updatedStream) return;
|
2019-07-04 00:55:46 +02:00
|
|
|
|
2019-06-24 20:22:42 +02:00
|
|
|
if (this.hideBoosts !== updatedStream.hideBoosts
|
|
|
|
|| this.hideBots !== updatedStream.hideBots
|
|
|
|
|| this.hideReplies !== updatedStream.hideReplies) {
|
|
|
|
this.streamElement = updatedStream;
|
|
|
|
}
|
2019-06-24 05:11:16 +02:00
|
|
|
});
|
2019-07-04 00:55:46 +02:00
|
|
|
|
|
|
|
this.hideAccountSubscription = this.notificationService.hideAccountUrlStream.subscribe((accountUrl: string) => {
|
|
|
|
if (accountUrl) {
|
|
|
|
this.statuses = this.statuses.filter(x => {
|
2019-07-06 04:27:40 +02:00
|
|
|
if (x.status.reblog) {
|
2019-07-04 00:55:46 +02:00
|
|
|
return x.status.reblog.account.url != accountUrl;
|
|
|
|
} else {
|
|
|
|
return x.status.account.url != accountUrl;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
this.bufferStream = this.bufferStream.filter(x => {
|
2019-07-06 04:27:40 +02:00
|
|
|
if (x.reblog) {
|
2019-07-04 00:55:46 +02:00
|
|
|
return x.reblog.account.url != accountUrl;
|
|
|
|
} else {
|
|
|
|
return x.account.url != accountUrl;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2020-04-18 03:46:38 +02:00
|
|
|
|
|
|
|
this.deleteStatusSubscription = this.notificationService.deletedStatusStream.subscribe((status: StatusWrapper) => {
|
|
|
|
if (status) {
|
2020-04-19 07:06:22 +02:00
|
|
|
this.statuses = this.statuses.filter(x => {
|
2020-04-18 03:46:38 +02:00
|
|
|
return !(x.status.url.replace('https://', '').split('/')[0] === status.provider.instance && x.status.id === status.status.id);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2022-11-26 21:48:33 +01:00
|
|
|
|
|
|
|
this.numNewItems = 0;
|
2018-11-16 05:57:52 +01:00
|
|
|
}
|
|
|
|
|
2019-02-19 05:45:35 +01:00
|
|
|
ngOnDestroy() {
|
|
|
|
if (this.goToTopSubscription) this.goToTopSubscription.unsubscribe();
|
2019-06-24 05:11:16 +02:00
|
|
|
if (this.streamsSubscription) this.streamsSubscription.unsubscribe();
|
2019-07-04 00:55:46 +02:00
|
|
|
if (this.hideAccountSubscription) this.hideAccountSubscription.unsubscribe();
|
2020-04-18 03:46:38 +02:00
|
|
|
if (this.deleteStatusSubscription) this.deleteStatusSubscription.unsubscribe();
|
2019-02-19 05:45:35 +01:00
|
|
|
}
|
|
|
|
|
2024-03-09 06:40:37 +01:00
|
|
|
private setContext(streamElement: StreamElement) {
|
|
|
|
switch(streamElement.type){
|
|
|
|
case StreamTypeEnum.global:
|
|
|
|
case StreamTypeEnum.local:
|
|
|
|
case StreamTypeEnum.tag:
|
|
|
|
this.context = 'public';
|
|
|
|
break;
|
|
|
|
case StreamTypeEnum.personnal:
|
|
|
|
case StreamTypeEnum.list:
|
|
|
|
this.context = 'home';
|
|
|
|
break;
|
|
|
|
case StreamTypeEnum.activity:
|
|
|
|
case StreamTypeEnum.directmessages:
|
|
|
|
this.context = 'notifications';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-19 05:45:35 +01:00
|
|
|
refresh(): any {
|
|
|
|
this.load(this._streamElement);
|
|
|
|
}
|
|
|
|
|
2020-05-22 08:17:26 +02:00
|
|
|
protected load(streamElement: StreamElement) {
|
2019-02-19 05:45:35 +01:00
|
|
|
this.resetStream();
|
|
|
|
|
|
|
|
if (this.userLocked) {
|
|
|
|
const splitedUserName = streamElement.accountId.split('@');
|
|
|
|
const user = splitedUserName[0];
|
|
|
|
const instance = splitedUserName[1];
|
|
|
|
this.account = this.getRegisteredAccounts().find(x => x.username == user && x.instance == instance);
|
|
|
|
} else {
|
|
|
|
this.account = this.toolsService.getSelectedAccounts()[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
this.retrieveToots();
|
|
|
|
this.launchWebsocket();
|
2018-11-16 05:57:52 +01:00
|
|
|
}
|
|
|
|
|
2018-11-24 05:04:02 +01:00
|
|
|
private resetStream() {
|
|
|
|
this.statuses.length = 0;
|
|
|
|
this.bufferStream.length = 0;
|
2022-11-26 21:48:33 +01:00
|
|
|
this.numNewItems = 0;
|
2019-02-19 05:45:35 +01:00
|
|
|
if (this.websocketStreaming) this.websocketStreaming.dispose();
|
2018-11-24 05:04:02 +01:00
|
|
|
}
|
|
|
|
|
2018-11-16 05:57:52 +01:00
|
|
|
private launchWebsocket(): void {
|
|
|
|
this.websocketStreaming = this.streamingService.getStreaming(this.account, this._streamElement);
|
|
|
|
this.websocketStreaming.statusUpdateSubjet.subscribe((update: StatusUpdate) => {
|
|
|
|
if (update) {
|
|
|
|
if (update.type === EventEnum.update) {
|
|
|
|
if (!this.statuses.find(x => x.status.id == update.status.id)) {
|
2020-04-19 07:06:22 +02:00
|
|
|
if ((this.streamPositionnedAtTop || this.timelineLoadingMode === TimeLineModeEnum.Continuous)
|
|
|
|
&& this.timelineLoadingMode !== TimeLineModeEnum.SlowMode) {
|
|
|
|
|
2019-06-24 05:11:16 +02:00
|
|
|
if (this.isFiltered(update.status)) {
|
2019-06-24 04:57:03 +02:00
|
|
|
return;
|
2019-06-24 05:11:16 +02:00
|
|
|
}
|
2019-06-24 04:57:03 +02:00
|
|
|
|
2020-04-01 08:29:51 +02:00
|
|
|
let cwPolicy = this.toolsService.checkContentWarning(update.status);
|
|
|
|
const wrapper = new StatusWrapper(cwPolicy.status, this.account, cwPolicy.applyCw, cwPolicy.hide);
|
2018-11-16 05:57:52 +01:00
|
|
|
this.statuses.unshift(wrapper);
|
|
|
|
} else {
|
|
|
|
this.bufferStream.push(update.status);
|
2022-11-26 21:48:33 +01:00
|
|
|
this.numNewItems++;
|
2018-11-16 05:57:52 +01:00
|
|
|
}
|
|
|
|
}
|
2019-07-06 04:27:40 +02:00
|
|
|
} else if (update.type === EventEnum.delete) {
|
|
|
|
this.statuses = this.statuses.filter(x => !(x.status.id === update.messageId && this.account.id === update.account.id));
|
|
|
|
this.bufferStream = this.bufferStream.filter(x => !(x.id === update.messageId && x.url.replace('https://', '').split('/')[0] === update.account.instance));
|
2018-11-16 05:57:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.checkAndCleanUpStream();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-05-22 08:31:14 +02:00
|
|
|
protected statusProcessOnGoToTop(){
|
2018-11-16 05:57:52 +01:00
|
|
|
if (this.statuses.length > 2 * this.streamingService.nbStatusPerIteration) {
|
|
|
|
this.statuses.length = 2 * this.streamingService.nbStatusPerIteration;
|
|
|
|
}
|
2020-05-22 08:31:14 +02:00
|
|
|
}
|
2019-10-12 04:42:08 +02:00
|
|
|
|
2018-11-16 05:57:52 +01:00
|
|
|
textSelected(): void {
|
2019-02-11 00:57:16 +01:00
|
|
|
console.warn(`status comp: textSelected`); //TODO
|
2018-11-16 05:57:52 +01:00
|
|
|
}
|
|
|
|
|
2020-05-22 08:31:14 +02:00
|
|
|
protected scrolledToTop() {
|
2018-11-16 05:57:52 +01:00
|
|
|
this.streamPositionnedAtTop = true;
|
|
|
|
|
2020-04-19 07:06:22 +02:00
|
|
|
if (this.timelineLoadingMode !== TimeLineModeEnum.SlowMode) {
|
|
|
|
this.loadBuffer();
|
|
|
|
}
|
2018-11-16 05:57:52 +01:00
|
|
|
}
|
|
|
|
|
2020-04-19 07:06:22 +02:00
|
|
|
loadBuffer(): boolean {
|
2019-02-19 05:45:35 +01:00
|
|
|
if (this.bufferWasCleared) {
|
2018-11-16 05:57:52 +01:00
|
|
|
this.statuses.length = 0;
|
|
|
|
this.bufferWasCleared = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const status of this.bufferStream) {
|
2019-06-24 05:11:16 +02:00
|
|
|
if (this.isFiltered(status)) {
|
2019-06-24 04:57:03 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-04-01 08:29:51 +02:00
|
|
|
let cwPolicy = this.toolsService.checkContentWarning(status);
|
|
|
|
const wrapper = new StatusWrapper(cwPolicy.status, this.account, cwPolicy.applyCw, cwPolicy.hide);
|
2019-02-19 05:45:35 +01:00
|
|
|
this.statuses.unshift(wrapper);
|
2018-11-16 05:57:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
this.bufferStream.length = 0;
|
2022-11-26 21:48:33 +01:00
|
|
|
this.numNewItems = 0;
|
2020-04-19 07:06:22 +02:00
|
|
|
return false;
|
2018-11-16 05:57:52 +01:00
|
|
|
}
|
|
|
|
|
2020-05-22 08:17:26 +02:00
|
|
|
protected getNextStatuses(): Promise<Status[]> {
|
2018-11-16 05:57:52 +01:00
|
|
|
const lastStatus = this.statuses[this.statuses.length - 1];
|
2019-06-24 04:57:03 +02:00
|
|
|
|
2020-05-22 08:17:26 +02:00
|
|
|
return this.mastodonService.getTimeline(this.account, this._streamElement.type, lastStatus.status.id, null, this.streamingService.nbStatusPerIteration, this._streamElement.tag, this._streamElement.listId)
|
|
|
|
.then((status: Status[]) =>{
|
2020-05-22 08:31:14 +02:00
|
|
|
return status.filter(x => !this.isFiltered(x));
|
2018-11-16 05:57:52 +01:00
|
|
|
});
|
|
|
|
}
|
2022-11-26 21:48:33 +01:00
|
|
|
|
2020-05-22 08:17:26 +02:00
|
|
|
private isFiltered(status: Status): boolean {
|
|
|
|
if (this.streamElement.hideBoosts) {
|
|
|
|
if (status.reblog) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (this.streamElement.hideBots) {
|
|
|
|
if (status.account.bot) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (this.streamElement.hideReplies) {
|
|
|
|
if (status.in_reply_to_account_id && status.account.id !== status.in_reply_to_account_id) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2018-11-16 05:57:52 +01:00
|
|
|
|
|
|
|
private getRegisteredAccounts(): AccountInfo[] {
|
|
|
|
var regAccounts = <AccountInfo[]>this.store.snapshot().registeredaccounts.accounts;
|
|
|
|
return regAccounts;
|
|
|
|
}
|
|
|
|
|
2019-09-28 21:52:04 +02:00
|
|
|
// @ViewChildren('status') private statusEls: QueryList<ElementRef>;
|
2019-09-28 07:23:15 +02:00
|
|
|
focus(): boolean {
|
2019-09-28 21:52:04 +02:00
|
|
|
setTimeout(() => {
|
|
|
|
var element = this.statustream.nativeElement as HTMLElement;
|
2020-05-22 08:17:26 +02:00
|
|
|
element.focus({ preventScroll: true });
|
2019-09-29 00:03:13 +02:00
|
|
|
}, 0);
|
2019-09-28 07:23:15 +02:00
|
|
|
return false;
|
|
|
|
}
|
2019-02-19 05:45:35 +01:00
|
|
|
|
2018-11-16 05:57:52 +01:00
|
|
|
private retrieveToots(): void {
|
2019-05-19 02:44:36 +02:00
|
|
|
this.mastodonService.getTimeline(this.account, this._streamElement.type, null, null, this.streamingService.nbStatusPerIteration, this._streamElement.tag, this._streamElement.listId)
|
2018-11-16 05:57:52 +01:00
|
|
|
.then((results: Status[]) => {
|
2019-02-24 21:35:48 +01:00
|
|
|
this.isLoading = false;
|
2018-11-16 05:57:52 +01:00
|
|
|
for (const s of results) {
|
2019-06-24 05:11:16 +02:00
|
|
|
if (this.isFiltered(s)) {
|
2019-06-24 04:57:03 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-04-01 08:29:51 +02:00
|
|
|
let cwPolicy = this.toolsService.checkContentWarning(s);
|
|
|
|
const wrapper = new StatusWrapper(cwPolicy.status, this.account, cwPolicy.applyCw, cwPolicy.hide);
|
2018-11-16 05:57:52 +01:00
|
|
|
this.statuses.push(wrapper);
|
|
|
|
}
|
2019-02-12 05:41:21 +01:00
|
|
|
})
|
|
|
|
.catch((err: HttpErrorResponse) => {
|
2019-09-07 23:52:07 +02:00
|
|
|
this.notificationService.notifyHttpError(err, this.account);
|
2018-11-16 05:57:52 +01:00
|
|
|
});
|
|
|
|
}
|
2019-02-19 05:45:35 +01:00
|
|
|
|
2018-11-16 05:57:52 +01:00
|
|
|
private checkAndCleanUpStream(): void {
|
|
|
|
if (this.streamPositionnedAtTop && this.statuses.length > 3 * this.streamingService.nbStatusPerIteration) {
|
|
|
|
this.statuses.length = 2 * this.streamingService.nbStatusPerIteration;
|
2020-05-22 08:17:26 +02:00
|
|
|
this.maxReached = false;
|
2020-06-25 02:25:37 +02:00
|
|
|
this.lastCallReachedMax = false;
|
2018-11-16 05:57:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (this.bufferStream.length > 3 * this.streamingService.nbStatusPerIteration) {
|
|
|
|
this.bufferWasCleared = true;
|
|
|
|
this.bufferStream.length = 2 * this.streamingService.nbStatusPerIteration;
|
|
|
|
}
|
2019-06-24 05:11:16 +02:00
|
|
|
}
|
2018-11-16 05:57:52 +01:00
|
|
|
}
|
|
|
|
|