This commit is contained in:
Nicolas Constant 2019-02-18 22:44:21 -05:00
parent f3a9ff1013
commit 5c88bda225
No known key found for this signature in database
GPG Key ID: 1E9F677FB01A5688
10 changed files with 101 additions and 56 deletions

View File

@ -4,7 +4,7 @@ import { HttpErrorResponse } from '@angular/common/http';
import { MastodonService } from '../../../services/mastodon.service'; import { MastodonService } from '../../../services/mastodon.service';
import { AccountInfo } from '../../../states/accounts.state'; import { AccountInfo } from '../../../states/accounts.state';
import { Results, Account } from '../../../services/models/mastodon.interfaces'; import { Results, Account } from '../../../services/models/mastodon.interfaces';
import { ToolsService } from '../../../services/tools.service'; import { ToolsService, OpenThreadEvent } from '../../../services/tools.service';
import { StatusWrapper } from '../../stream/stream.component'; import { StatusWrapper } from '../../stream/stream.component';
import { NotificationService } from '../../../services/notification.service'; import { NotificationService } from '../../../services/notification.service';
@ -24,7 +24,7 @@ export class SearchComponent implements OnInit {
@Output() browseAccountEvent = new EventEmitter<string>(); @Output() browseAccountEvent = new EventEmitter<string>();
@Output() browseHashtagEvent = new EventEmitter<string>(); @Output() browseHashtagEvent = new EventEmitter<string>();
@Output() browseThreadEvent = new EventEmitter<string>(); @Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
constructor( constructor(
private readonly notificationService: NotificationService, private readonly notificationService: NotificationService,

View File

@ -3,6 +3,7 @@ import { Subject } from 'rxjs';
import { Store } from '@ngxs/store'; import { Store } from '@ngxs/store';
import { StreamElement, StreamTypeEnum, AddStream } from '../../../states/streams.state'; import { StreamElement, StreamTypeEnum, AddStream } from '../../../states/streams.state';
import { OpenThreadEvent } from '../../../services/tools.service';
@Component({ @Component({
selector: 'app-hashtag', selector: 'app-hashtag',
@ -12,7 +13,7 @@ import { StreamElement, StreamTypeEnum, AddStream } from '../../../states/stream
export class HashtagComponent implements OnInit { export class HashtagComponent implements OnInit {
@Output() browseAccountEvent = new EventEmitter<string>(); @Output() browseAccountEvent = new EventEmitter<string>();
@Output() browseHashtagEvent = new EventEmitter<string>(); @Output() browseHashtagEvent = new EventEmitter<string>();
@Output() browseThreadEvent = new EventEmitter<string>(); @Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
@Input() hashtagElement: StreamElement; @Input() hashtagElement: StreamElement;
@ -47,7 +48,7 @@ export class HashtagComponent implements OnInit {
this.browseHashtagEvent.next(hashtag); this.browseHashtagEvent.next(hashtag);
} }
browseThread(statusUri: string): void { browseThread(openThreadEvent: OpenThreadEvent): void {
this.browseThreadEvent.next(statusUri); this.browseThreadEvent.next(openThreadEvent);
} }
} }

View File

@ -1,6 +1,7 @@
import { Component, OnInit, Input, Output, EventEmitter } from "@angular/core"; import { Component, OnInit, Input, Output, EventEmitter } from "@angular/core";
import { Status, Account } from "../../../services/models/mastodon.interfaces"; import { Status, Account } from "../../../services/models/mastodon.interfaces";
import { StatusWrapper } from "../stream.component"; import { StatusWrapper } from "../stream.component";
import { OpenThreadEvent } from "../../../services/tools.service";
@Component({ @Component({
selector: "app-status", selector: "app-status",
@ -15,7 +16,7 @@ export class StatusComponent implements OnInit {
@Output() browseAccountEvent = new EventEmitter<string>(); @Output() browseAccountEvent = new EventEmitter<string>();
@Output() browseHashtagEvent = new EventEmitter<string>(); @Output() browseHashtagEvent = new EventEmitter<string>();
@Output() browseThreadEvent = new EventEmitter<string>(); @Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
private _statusWrapper: StatusWrapper; private _statusWrapper: StatusWrapper;
status: Status; status: Status;
@ -78,11 +79,15 @@ export class StatusComponent implements OnInit {
textSelected(): void { textSelected(): void {
const status = this._statusWrapper.status; const status = this._statusWrapper.status;
const accountInfo = this._statusWrapper.provider;
if (status.reblog) { let openThread: OpenThreadEvent;
this.browseThreadEvent.next(status.reblog.uri); if (status.reblog) {
openThread = new OpenThreadEvent(status.reblog, accountInfo);
} else { } else {
this.browseThreadEvent.next(this._statusWrapper.status.uri); openThread = new OpenThreadEvent(status, accountInfo);
} }
this.browseThreadEvent.next(openThread);
} }
} }

View File

@ -1,7 +1,7 @@
import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core'; import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core';
import { Account, Results } from "../../../services/models/mastodon.interfaces"; import { Account, Results } from "../../../services/models/mastodon.interfaces";
import { MastodonService } from '../../../services/mastodon.service'; import { MastodonService } from '../../../services/mastodon.service';
import { ToolsService } from '../../../services/tools.service'; import { ToolsService, OpenThreadEvent } from '../../../services/tools.service';
import { StreamElement, StreamTypeEnum } from '../../../states/streams.state'; import { StreamElement, StreamTypeEnum } from '../../../states/streams.state';
@Component({ @Component({
@ -19,7 +19,7 @@ export class StreamOverlayComponent implements OnInit {
canGoForward: boolean; canGoForward: boolean;
accountName: string; accountName: string;
thread: string; thread: OpenThreadEvent;
// hashtag: string; // hashtag: string;
hashtagElement: StreamElement; hashtagElement: StreamElement;
@ -32,8 +32,8 @@ export class StreamOverlayComponent implements OnInit {
} }
@Input('browseThreadData') @Input('browseThreadData')
set browseThreadData(statusUri: string) { set browseThreadData(openThread: OpenThreadEvent) {
this.browseThread(statusUri); this.browseThread(openThread);
} }
@Input('browseHashtagData') @Input('browseHashtagData')
@ -116,15 +116,15 @@ export class StreamOverlayComponent implements OnInit {
this.canGoForward = false; this.canGoForward = false;
} }
browseThread(statusUri: string): any { browseThread(openThread: OpenThreadEvent): any {
if(!statusUri) return; if(!openThread) return;
this.nextElements.length = 0; this.nextElements.length = 0;
if (this.currentElement) { if (this.currentElement) {
this.previousElements.push(this.currentElement); this.previousElements.push(this.currentElement);
} }
const newElement = new OverlayBrowsing(null, null, statusUri); const newElement = new OverlayBrowsing(null, null, openThread);
this.loadElement(newElement); this.loadElement(newElement);
this.canGoForward = false; this.canGoForward = false;
} }
@ -142,7 +142,7 @@ class OverlayBrowsing {
constructor( constructor(
public readonly hashtag: StreamElement, public readonly hashtag: StreamElement,
public readonly account: string, public readonly account: string,
public readonly thread: string) { public readonly thread: OpenThreadEvent) {
if (hashtag) { if (hashtag) {
this.type = OverlayEnum.hashtag; this.type = OverlayEnum.hashtag;

View File

@ -1,6 +1,8 @@
<div class="stream-toots flexcroll" #statusstream (scroll)="onScroll()"> <div class="stream-toots flexcroll" #statusstream (scroll)="onScroll()">
<app-waiting-animation *ngIf="isLoading" class="waiting-icon"></app-waiting-animation> <app-waiting-animation *ngIf="isLoading" class="waiting-icon"></app-waiting-animation>
<div *ngIf="displayError">{{displayError}}</div>
<!-- data-simplebar --> <!-- data-simplebar -->
<div class="stream-toots__status" *ngFor="let statusWrapper of statuses"> <div class="stream-toots__status" *ngFor="let statusWrapper of statuses">
<app-status [statusWrapper]="statusWrapper" (browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)" <app-status [statusWrapper]="statusWrapper" (browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)"

View File

@ -10,6 +10,7 @@ import { Status } from '../../../services/models/mastodon.interfaces';
import { MastodonService } from '../../../services/mastodon.service'; import { MastodonService } from '../../../services/mastodon.service';
import { StatusWrapper } from '../stream.component'; import { StatusWrapper } from '../stream.component';
import { NotificationService } from '../../../services/notification.service'; import { NotificationService } from '../../../services/notification.service';
import { OpenThreadEvent } from '../../../services/tools.service';
@Component({ @Component({
selector: 'app-stream-statuses', selector: 'app-stream-statuses',
@ -18,6 +19,7 @@ import { NotificationService } from '../../../services/notification.service';
}) })
export class StreamStatusesComponent implements OnInit, OnDestroy { export class StreamStatusesComponent implements OnInit, OnDestroy {
isLoading = false; //TODO isLoading = false; //TODO
displayError: string;
private _streamElement: StreamElement; private _streamElement: StreamElement;
private account: AccountInfo; private account: AccountInfo;
@ -29,7 +31,7 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
@Output() browseAccountEvent = new EventEmitter<string>(); @Output() browseAccountEvent = new EventEmitter<string>();
@Output() browseHashtagEvent = new EventEmitter<string>(); @Output() browseHashtagEvent = new EventEmitter<string>();
@Output() browseThreadEvent = new EventEmitter<string>(); @Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
@Input() @Input()
set streamElement(streamElement: StreamElement) { set streamElement(streamElement: StreamElement) {
@ -135,8 +137,8 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
this.browseHashtagEvent.next(hashtag); this.browseHashtagEvent.next(hashtag);
} }
browseThread(statusUri: string): void { browseThread(openThreadEvent: OpenThreadEvent): void {
this.browseThreadEvent.next(statusUri); this.browseThreadEvent.next(openThreadEvent);
} }
textSelected(): void { textSelected(): void {

View File

@ -5,6 +5,7 @@ import { faHome, faGlobe, faUser, faHashtag, faListUl, faBars, IconDefinition }
import { StreamElement, StreamTypeEnum } from "../../states/streams.state"; import { StreamElement, StreamTypeEnum } from "../../states/streams.state";
import { Status } from "../../services/models/mastodon.interfaces"; import { Status } from "../../services/models/mastodon.interfaces";
import { AccountInfo } from "../../states/accounts.state"; import { AccountInfo } from "../../states/accounts.state";
import { OpenThreadEvent } from "../../services/tools.service";
@Component({ @Component({
selector: "app-stream", selector: "app-stream",
@ -18,7 +19,7 @@ export class StreamComponent implements OnInit {
overlayActive: boolean; overlayActive: boolean;
overlayAccountToBrowse: string; overlayAccountToBrowse: string;
overlayHashtagToBrowse: string; overlayHashtagToBrowse: string;
overlayThreadToBrowse: string; overlayThreadToBrowse: OpenThreadEvent;
goToTopSubject: Subject<void> = new Subject<void>(); goToTopSubject: Subject<void> = new Subject<void>();
@ -75,10 +76,10 @@ export class StreamComponent implements OnInit {
this.overlayActive = true; this.overlayActive = true;
} }
browseThread(statusUri: string): void { browseThread(openThreadEvent: OpenThreadEvent): void {
this.overlayAccountToBrowse = null; this.overlayAccountToBrowse = null;
this.overlayHashtagToBrowse = null; this.overlayHashtagToBrowse = null;
this.overlayThreadToBrowse = statusUri; this.overlayThreadToBrowse = openThreadEvent;
this.overlayActive = true; this.overlayActive = true;
} }

View File

@ -3,9 +3,10 @@ import { HttpErrorResponse } from '@angular/common/http';
import { StatusWrapper } from '../stream.component'; import { StatusWrapper } from '../stream.component';
import { MastodonService } from '../../../services/mastodon.service'; import { MastodonService } from '../../../services/mastodon.service';
import { ToolsService } from '../../../services/tools.service'; import { ToolsService, OpenThreadEvent } from '../../../services/tools.service';
import { Results, Context } from '../../../services/models/mastodon.interfaces'; import { Results, Context, Status } from '../../../services/models/mastodon.interfaces';
import { NotificationService } from '../../../services/notification.service'; import { NotificationService } from '../../../services/notification.service';
import { AccountInfo } from '../../../states/accounts.state';
@Component({ @Component({
selector: 'app-thread', selector: 'app-thread',
@ -15,13 +16,14 @@ import { NotificationService } from '../../../services/notification.service';
export class ThreadComponent implements OnInit { export class ThreadComponent implements OnInit {
statuses: StatusWrapper[] = []; statuses: StatusWrapper[] = [];
isLoading: boolean; isLoading: boolean;
displayError: string;
@Output() browseAccountEvent = new EventEmitter<string>(); @Output() browseAccountEvent = new EventEmitter<string>();
@Output() browseHashtagEvent = new EventEmitter<string>(); @Output() browseHashtagEvent = new EventEmitter<string>();
@Output() browseThreadEvent = new EventEmitter<string>(); @Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
@Input('currentThread') @Input('currentThread')
set currentThread(thread: string) { set currentThread(thread: OpenThreadEvent) {
if (thread) { if (thread) {
this.isLoading = true; this.isLoading = true;
this.getThread(thread); this.getThread(thread);
@ -36,33 +38,58 @@ export class ThreadComponent implements OnInit {
ngOnInit() { ngOnInit() {
} }
private getThread(thread: string) { private getThread(openThreadEvent: OpenThreadEvent) {
this.statuses.length = 0; this.statuses.length = 0;
let currentAccount = this.toolsService.getSelectedAccounts()[0]; let currentAccount = this.toolsService.getSelectedAccounts()[0];
this.mastodonService.search(currentAccount, thread, true) const status = openThreadEvent.status;
.then((result: Results) => { const sourceAccount = openThreadEvent.sourceAccount;
if (result.statuses.length === 1) {
const retrievedStatus = result.statuses[0];
this.mastodonService.getStatusContext(currentAccount, retrievedStatus.id)
.then((context: Context) => {
this.isLoading = false;
let contextStatuses = [...context.ancestors, retrievedStatus, ...context.descendants]
for (const s of contextStatuses) { if (status.visibility === 'public' || status.visibility === 'unlisted') {
const wrapper = new StatusWrapper(s, currentAccount); var statusPromise: Promise<Status> = Promise.resolve(status);
this.statuses.push(wrapper);
} if (sourceAccount.id !== currentAccount.id) {
}); statusPromise = this.mastodonService.search(currentAccount, status.uri, true)
} else { .then((result: Results) => {
//TODO handle error if (result.statuses.length === 1) {
this.isLoading = false; const retrievedStatus = result.statuses[0];
console.error('could not retrieve status'); return retrievedStatus;
} }
}) throw new Error('could not find status');
.catch((err: HttpErrorResponse) => { });
this.notificationService.notifyHttpError(err); }
this.retrieveThread(currentAccount, statusPromise);
} else if (sourceAccount.id === currentAccount.id) {
var statusPromise = Promise.resolve(status);
this.retrieveThread(currentAccount, statusPromise);
} else {
this.isLoading = false;
this.displayError = `You need to use your account ${sourceAccount.username}@${sourceAccount.instance} to show this thread`;
}
}
private retrieveThread(currentAccount: AccountInfo, pipeline: Promise<Status>) {
pipeline
.then((status: Status) => {
this.mastodonService.getStatusContext(currentAccount, status.id)
.then((context: Context) => {
this.isLoading = false;
let contextStatuses = [...context.ancestors, status, ...context.descendants]
for (const s of contextStatuses) {
const wrapper = new StatusWrapper(s, currentAccount);
this.statuses.push(wrapper);
}
})
.catch((err: HttpErrorResponse) => {
this.isLoading = false;
this.notificationService.notifyHttpError(err);
});
}); });
} }
@ -78,7 +105,7 @@ export class ThreadComponent implements OnInit {
this.browseHashtagEvent.next(hashtag); this.browseHashtagEvent.next(hashtag);
} }
browseThread(statusUri: string): void { browseThread(openThreadEvent: OpenThreadEvent): void {
this.browseThreadEvent.next(statusUri); this.browseThreadEvent.next(openThreadEvent);
} }
} }

View File

@ -3,7 +3,7 @@ import { HttpErrorResponse } from '@angular/common/http';
import { Account, Status} from "../../../services/models/mastodon.interfaces"; import { Account, Status} from "../../../services/models/mastodon.interfaces";
import { MastodonService } from '../../../services/mastodon.service'; import { MastodonService } from '../../../services/mastodon.service';
import { ToolsService } from '../../../services/tools.service'; import { ToolsService, OpenThreadEvent } from '../../../services/tools.service';
import { StatusWrapper } from '../stream.component'; import { StatusWrapper } from '../stream.component';
import { NotificationService } from '../../../services/notification.service'; import { NotificationService } from '../../../services/notification.service';
@ -26,7 +26,7 @@ export class UserProfileComponent implements OnInit {
@Output() browseAccountEvent = new EventEmitter<string>(); @Output() browseAccountEvent = new EventEmitter<string>();
@Output() browseHashtagEvent = new EventEmitter<string>(); @Output() browseHashtagEvent = new EventEmitter<string>();
@Output() browseThreadEvent = new EventEmitter<string>(); @Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
@Input('currentAccount') @Input('currentAccount')
//set currentAccount(account: Account) { //set currentAccount(account: Account) {
@ -65,8 +65,8 @@ export class UserProfileComponent implements OnInit {
this.browseHashtagEvent.next(hashtag); this.browseHashtagEvent.next(hashtag);
} }
browseThread(statusUri: string): void { browseThread(openThreadEvent: OpenThreadEvent): void {
this.browseThreadEvent.next(statusUri); this.browseThreadEvent.next(openThreadEvent);
} }
private loadAccount(accountName: string): Promise<Account> { private loadAccount(accountName: string): Promise<Account> {

View File

@ -52,5 +52,12 @@ export class ToolsService {
return statusPromise; return statusPromise;
} }
}
export class OpenThreadEvent {
constructor(
public status: Status,
public sourceAccount: AccountInfo
) {
}
} }