mirror of
https://github.com/NicolasConstant/sengi
synced 2025-02-10 17:00:49 +01:00
Merge pull request #239 from NicolasConstant/topic_bookmarks
Topic bookmarks
This commit is contained in:
commit
48e29110c3
@ -81,6 +81,7 @@ import { StreamNotificationsComponent } from './components/stream/stream-notific
|
|||||||
import { NotificationComponent } from './components/floating-column/manage-account/notifications/notification/notification.component';
|
import { NotificationComponent } from './components/floating-column/manage-account/notifications/notification/notification.component';
|
||||||
import { ServiceWorkerModule } from '@angular/service-worker';
|
import { ServiceWorkerModule } from '@angular/service-worker';
|
||||||
import { environment } from '../environments/environment';
|
import { environment } from '../environments/environment';
|
||||||
|
import { BookmarksComponent } from './components/floating-column/manage-account/bookmarks/bookmarks.component';
|
||||||
|
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
@ -142,7 +143,8 @@ const routes: Routes = [
|
|||||||
ScheduledStatusesComponent,
|
ScheduledStatusesComponent,
|
||||||
ScheduledStatusComponent,
|
ScheduledStatusComponent,
|
||||||
StreamNotificationsComponent,
|
StreamNotificationsComponent,
|
||||||
NotificationComponent
|
NotificationComponent,
|
||||||
|
BookmarksComponent
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
EmojiPickerComponent
|
EmojiPickerComponent
|
||||||
|
@ -15,13 +15,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<app-manage-account *ngIf="openPanel === 'manageAccount'" [account]="userAccountUsed"
|
<app-manage-account *ngIf="openPanel === 'manageAccount'" [account]="userAccountUsed"
|
||||||
(browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)"
|
(browseAccountEvent)="browseAccount($event)"
|
||||||
|
(browseHashtagEvent)="browseHashtag($event)"
|
||||||
(browseThreadEvent)="browseThread($event)"></app-manage-account>
|
(browseThreadEvent)="browseThread($event)"></app-manage-account>
|
||||||
<app-add-new-status *ngIf="openPanel === 'createNewStatus'" [isDirectMention]="isDirectMention"
|
<app-add-new-status *ngIf="openPanel === 'createNewStatus'" [isDirectMention]="isDirectMention"
|
||||||
[userHandle]="userHandle" [redraftedStatus]="redraftedStatus"></app-add-new-status>
|
[userHandle]="userHandle" [redraftedStatus]="redraftedStatus"></app-add-new-status>
|
||||||
<app-add-new-account *ngIf="openPanel === 'addNewAccount'"></app-add-new-account>
|
<app-add-new-account *ngIf="openPanel === 'addNewAccount'"></app-add-new-account>
|
||||||
<app-search *ngIf="openPanel === 'search'" (browseAccountEvent)="browseAccount($event)"
|
<app-search *ngIf="openPanel === 'search'"
|
||||||
(browseHashtagEvent)="browseHashtag($event)" (browseThreadEvent)="browseThread($event)">
|
(browseAccountEvent)="browseAccount($event)"
|
||||||
|
(browseHashtagEvent)="browseHashtag($event)"
|
||||||
|
(browseThreadEvent)="browseThread($event)">
|
||||||
</app-search>
|
</app-search>
|
||||||
<app-settings *ngIf="openPanel === 'settings'"></app-settings>
|
<app-settings *ngIf="openPanel === 'settings'"></app-settings>
|
||||||
<app-scheduled-statuses *ngIf="openPanel === 'scheduledStatuses'"></app-scheduled-statuses>
|
<app-scheduled-statuses *ngIf="openPanel === 'scheduledStatuses'"></app-scheduled-statuses>
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
<p>
|
||||||
|
bookmarks works!
|
||||||
|
</p>
|
@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { BookmarksComponent } from './bookmarks.component';
|
||||||
|
|
||||||
|
xdescribe('BookmarksComponent', () => {
|
||||||
|
let component: BookmarksComponent;
|
||||||
|
let fixture: ComponentFixture<BookmarksComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ BookmarksComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(BookmarksComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,125 @@
|
|||||||
|
import { Component, OnInit, Output, EventEmitter, Input, ViewChild, ElementRef } from '@angular/core';
|
||||||
|
|
||||||
|
import { StatusWrapper } from '../../../../models/common.model';
|
||||||
|
import { OpenThreadEvent } from '../../../../services/tools.service';
|
||||||
|
import { AccountWrapper } from '../../../../models/account.models';
|
||||||
|
import { FavoriteResult, BookmarkResult } from '../../../../services/mastodon.service';
|
||||||
|
import { MastodonWrapperService } from '../../../../services/mastodon-wrapper.service';
|
||||||
|
import { Status } from '../../../../services/models/mastodon.interfaces';
|
||||||
|
import { NotificationService } from '../../../../services/notification.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-bookmarks',
|
||||||
|
templateUrl: '../../../stream/stream-statuses/stream-statuses.component.html',
|
||||||
|
styleUrls: ['../../../stream/stream-statuses/stream-statuses.component.scss', './bookmarks.component.scss']
|
||||||
|
})
|
||||||
|
export class BookmarksComponent implements OnInit {
|
||||||
|
statuses: StatusWrapper[] = [];
|
||||||
|
displayError: string;
|
||||||
|
isLoading = true;
|
||||||
|
isThread = false;
|
||||||
|
hasContentWarnings = false;
|
||||||
|
|
||||||
|
bufferStream: Status[] = []; //html compatibility only
|
||||||
|
|
||||||
|
@Output() browseAccountEvent = new EventEmitter<string>();
|
||||||
|
@Output() browseHashtagEvent = new EventEmitter<string>();
|
||||||
|
@Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
|
||||||
|
|
||||||
|
private maxReached = false;
|
||||||
|
private maxId: string;
|
||||||
|
private _account: AccountWrapper;
|
||||||
|
|
||||||
|
@Input('account')
|
||||||
|
set account(acc: AccountWrapper) {
|
||||||
|
this._account = acc;
|
||||||
|
this.getBookmarks();
|
||||||
|
}
|
||||||
|
get account(): AccountWrapper {
|
||||||
|
return this._account;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewChild('statusstream') public statustream: ElementRef;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly notificationService: NotificationService,
|
||||||
|
private readonly mastodonService: MastodonWrapperService) { }
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private reset() {
|
||||||
|
this.isLoading = true;
|
||||||
|
this.statuses.length = 0;
|
||||||
|
this.maxReached = false;
|
||||||
|
this.maxId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getBookmarks() {
|
||||||
|
this.reset();
|
||||||
|
|
||||||
|
this.mastodonService.getBookmarks(this.account.info)
|
||||||
|
.then((result: BookmarkResult) => {
|
||||||
|
this.maxId = result.max_id;
|
||||||
|
for (const s of result.bookmarked) {
|
||||||
|
const wrapper = new StatusWrapper(s, this.account.info);
|
||||||
|
this.statuses.push(wrapper);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
this.notificationService.notifyHttpError(err, this.account.info);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onScroll() {
|
||||||
|
var element = this.statustream.nativeElement as HTMLElement;
|
||||||
|
const atBottom = element.scrollHeight <= element.clientHeight + element.scrollTop + 1000;
|
||||||
|
|
||||||
|
if (atBottom) {
|
||||||
|
this.scrolledToBottom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private scrolledToBottom() {
|
||||||
|
if (this.isLoading || this.maxReached) return;
|
||||||
|
|
||||||
|
this.isLoading = true;
|
||||||
|
this.mastodonService.getBookmarks(this.account.info, this.maxId)
|
||||||
|
.then((result: BookmarkResult) => {
|
||||||
|
const statuses = result.bookmarked;
|
||||||
|
if (statuses.length === 0 || !this.maxId) {
|
||||||
|
this.maxReached = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.maxId = result.max_id;
|
||||||
|
for (const s of statuses) {
|
||||||
|
const wrapper = new StatusWrapper(s, this.account.info);
|
||||||
|
this.statuses.push(wrapper);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
this.notificationService.notifyHttpError(err, this.account.info);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
browseAccount(accountName: string): void {
|
||||||
|
this.browseAccountEvent.next(accountName);
|
||||||
|
}
|
||||||
|
|
||||||
|
browseHashtag(hashtag: string): void {
|
||||||
|
this.browseHashtagEvent.next(hashtag);
|
||||||
|
}
|
||||||
|
|
||||||
|
browseThread(openThreadEvent: OpenThreadEvent): void {
|
||||||
|
this.browseThreadEvent.next(openThreadEvent);
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,6 @@ import { FavoriteResult } from '../../../../services/mastodon.service';
|
|||||||
import { MastodonWrapperService } from '../../../../services/mastodon-wrapper.service';
|
import { MastodonWrapperService } from '../../../../services/mastodon-wrapper.service';
|
||||||
import { Status } from '../../../../services/models/mastodon.interfaces';
|
import { Status } from '../../../../services/models/mastodon.interfaces';
|
||||||
import { NotificationService } from '../../../../services/notification.service';
|
import { NotificationService } from '../../../../services/notification.service';
|
||||||
import { resetCompiledComponents } from '@angular/core/src/render3/jit/module';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-favorites',
|
selector: 'app-favorites',
|
||||||
|
@ -3,10 +3,16 @@
|
|||||||
|
|
||||||
<div class="account__header">
|
<div class="account__header">
|
||||||
<a href (click)="browseLocalAccount()" (auxclick)="openLocalAccount()" title="open {{ account.info.id }}">
|
<a href (click)="browseLocalAccount()" (auxclick)="openLocalAccount()" title="open {{ account.info.id }}">
|
||||||
<img class="account__avatar" src="{{account.avatar}}"/>
|
<img class="account__avatar" src="{{account.avatar}}" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- <a href class="account__header--button"><fa-icon [icon]="faUserPlus"></fa-icon></a> -->
|
<!-- <a href class="account__header--button"><fa-icon [icon]="faUserPlus"></fa-icon></a> -->
|
||||||
|
<a *ngIf="isBookmarksAvailable" href class="account__header--button" title="bookmark"
|
||||||
|
(click)="loadSubPanel('bookmarks')"
|
||||||
|
[ngClass]="{ 'account__header--button--selected': subPanel === 'bookmarks' }">
|
||||||
|
<fa-icon [icon]="faBookmark"></fa-icon>
|
||||||
|
</a>
|
||||||
|
|
||||||
<a href class="account__header--button" title="favorites" (click)="loadSubPanel('favorites')"
|
<a href class="account__header--button" title="favorites" (click)="loadSubPanel('favorites')"
|
||||||
[ngClass]="{ 'account__header--button--selected': subPanel === 'favorites' }">
|
[ngClass]="{ 'account__header--button--selected': subPanel === 'favorites' }">
|
||||||
<fa-icon [icon]="faStar"></fa-icon>
|
<fa-icon [icon]="faStar"></fa-icon>
|
||||||
@ -29,6 +35,9 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<app-bookmarks class="account__body" *ngIf="subPanel === 'bookmarks'" [account]="account"
|
||||||
|
(browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)"
|
||||||
|
(browseThreadEvent)="browseThread($event)"></app-bookmarks>
|
||||||
<app-direct-messages class="account__body" *ngIf="subPanel === 'dm'" [account]="account"
|
<app-direct-messages class="account__body" *ngIf="subPanel === 'dm'" [account]="account"
|
||||||
(browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)"
|
(browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)"
|
||||||
(browseThreadEvent)="browseThread($event)"></app-direct-messages>
|
(browseThreadEvent)="browseThread($event)"></app-direct-messages>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Component, OnInit, OnDestroy, Input, Output, EventEmitter } from '@angular/core';
|
import { Component, OnInit, OnDestroy, Input, Output, EventEmitter } from '@angular/core';
|
||||||
import { faAt, faUserPlus } from "@fortawesome/free-solid-svg-icons";
|
import { faAt, faUserPlus } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { faBell, faEnvelope, faUser, faStar } from "@fortawesome/free-regular-svg-icons";
|
import { faBell, faEnvelope, faUser, faStar, faBookmark } from "@fortawesome/free-regular-svg-icons";
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
import { AccountWrapper } from '../../../models/account.models';
|
import { AccountWrapper } from '../../../models/account.models';
|
||||||
import { UserNotificationService, UserNotification } from '../../../services/user-notification.service';
|
import { UserNotificationService, UserNotification } from '../../../services/user-notification.service';
|
||||||
import { OpenThreadEvent, ToolsService } from '../../../services/tools.service';
|
import { OpenThreadEvent, ToolsService, InstanceInfo } from '../../../services/tools.service';
|
||||||
import { MastodonWrapperService } from '../../../services/mastodon-wrapper.service';
|
import { MastodonWrapperService } from '../../../services/mastodon-wrapper.service';
|
||||||
import { Account } from "../../../services/models/mastodon.interfaces";
|
import { Account } from "../../../services/models/mastodon.interfaces";
|
||||||
import { NotificationService } from '../../../services/notification.service';
|
import { NotificationService } from '../../../services/notification.service';
|
||||||
@ -24,10 +24,12 @@ export class ManageAccountComponent implements OnInit, OnDestroy {
|
|||||||
faUser = faUser;
|
faUser = faUser;
|
||||||
faStar = faStar;
|
faStar = faStar;
|
||||||
faUserPlus = faUserPlus;
|
faUserPlus = faUserPlus;
|
||||||
|
faBookmark = faBookmark;
|
||||||
|
|
||||||
subPanel: 'account' | 'notifications' | 'mentions' | 'dm' | 'favorites' = 'account';
|
subPanel: 'account' | 'notifications' | 'mentions' | 'dm' | 'favorites' | 'bookmarks' = 'account';
|
||||||
hasNotifications = false;
|
hasNotifications = false;
|
||||||
hasMentions = false;
|
hasMentions = false;
|
||||||
|
isBookmarksAvailable = false;
|
||||||
|
|
||||||
userAccount: Account;
|
userAccount: Account;
|
||||||
|
|
||||||
@ -38,6 +40,7 @@ export class ManageAccountComponent implements OnInit, OnDestroy {
|
|||||||
@Input('account')
|
@Input('account')
|
||||||
set account(acc: AccountWrapper) {
|
set account(acc: AccountWrapper) {
|
||||||
this._account = acc;
|
this._account = acc;
|
||||||
|
this.checkIfBookmarksAreAvailable();
|
||||||
this.checkNotifications();
|
this.checkNotifications();
|
||||||
this.getUserUrl(acc.info);
|
this.getUserUrl(acc.info);
|
||||||
}
|
}
|
||||||
@ -61,6 +64,20 @@ export class ManageAccountComponent implements OnInit, OnDestroy {
|
|||||||
this.userNotificationServiceSub.unsubscribe();
|
this.userNotificationServiceSub.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private checkIfBookmarksAreAvailable() {
|
||||||
|
this.toolsService.getInstanceInfo(this.account.info)
|
||||||
|
.then((instance: InstanceInfo) => {
|
||||||
|
if (instance.major >= 3 && instance.minor >= 1) {
|
||||||
|
this.isBookmarksAvailable = true;
|
||||||
|
} else {
|
||||||
|
this.isBookmarksAvailable = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
this.isBookmarksAvailable = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private getUserUrl(account: AccountInfo) {
|
private getUserUrl(account: AccountInfo) {
|
||||||
this.mastodonService.retrieveAccountDetails(this.account.info)
|
this.mastodonService.retrieveAccountDetails(this.account.info)
|
||||||
.then((acc: Account) => {
|
.then((acc: Account) => {
|
||||||
|
@ -35,8 +35,10 @@
|
|||||||
<h3 class="search-results__title">Statuses</h3>
|
<h3 class="search-results__title">Statuses</h3>
|
||||||
|
|
||||||
<div class="search-results__status" *ngFor="let statusWrapper of statuses">
|
<div class="search-results__status" *ngFor="let statusWrapper of statuses">
|
||||||
<app-status [statusWrapper]="statusWrapper" (browseAccountEvent)="browseAccount($event)"
|
<app-status [statusWrapper]="statusWrapper"
|
||||||
(browseHashtagEvent)="browseHashtag($event)" (browseThreadEvent)="browseThread($event)">
|
(browseAccountEvent)="browseAccount($event)"
|
||||||
|
(browseHashtagEvent)="browseHashtag($event)"
|
||||||
|
(browseThreadEvent)="browseThread($event)">
|
||||||
</app-status>
|
</app-status>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -54,15 +54,16 @@ export class SearchComponent implements OnInit {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
browseAccount(account: Account): boolean {
|
browseAccount(account: string): boolean {
|
||||||
let accountName = this.toolsService.getAccountFullHandle(account);
|
if (account) {
|
||||||
this.browseAccountEvent.next(accountName);
|
this.browseAccountEvent.next(account);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private lastAccountUsed: AccountInfo;
|
private lastAccountUsed: AccountInfo;
|
||||||
private search(data: string) {
|
private search(data: string) {
|
||||||
if(!data) return;
|
if (!data) return;
|
||||||
|
|
||||||
this.accounts.length = 0;
|
this.accounts.length = 0;
|
||||||
this.statuses.length = 0;
|
this.statuses.length = 0;
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
<fa-icon *ngIf="isBoostLocked && !isLocked && !isDM" class="action-bar__lock" title="This post cannot be boosted"
|
<fa-icon *ngIf="isBoostLocked && !isLocked && !isDM" class="action-bar__lock" title="This post cannot be boosted"
|
||||||
[icon]="faLock"></fa-icon>
|
[icon]="faLock"></fa-icon>
|
||||||
<fa-icon *ngIf="isLocked" class="action-bar__lock" title="Account can't access this post" [icon]="faLock"></fa-icon>
|
<fa-icon *ngIf="isLocked" class="action-bar__lock" title="Account can't access this post" [icon]="faLock"></fa-icon>
|
||||||
<fa-icon *ngIf="isDM && !isLocked" class="action-bar__envelope" title="DM post cannot be boosted" [icon]="faEnvelope"></fa-icon>
|
<fa-icon *ngIf="isDM && !isLocked" class="action-bar__envelope" title="DM post cannot be boosted"
|
||||||
|
[icon]="faEnvelope"></fa-icon>
|
||||||
|
|
||||||
<a *ngIf="!isLocked" href class="action-bar__link action-bar__link--fav" title="Favourite"
|
<a *ngIf="!isLocked" href class="action-bar__link action-bar__link--fav" title="Favourite"
|
||||||
[class.favorited]="isFavorited" [class.favoriting]="favoriteIsLoading" (click)="favorite()">
|
[class.favorited]="isFavorited" [class.favoriting]="favoriteIsLoading" (click)="favorite()">
|
||||||
@ -19,6 +20,12 @@
|
|||||||
</a>
|
</a>
|
||||||
<fa-icon *ngIf="isLocked" class="action-bar__lock" title="Account can't access this post" [icon]="faLock"></fa-icon>
|
<fa-icon *ngIf="isLocked" class="action-bar__lock" title="Account can't access this post" [icon]="faLock"></fa-icon>
|
||||||
|
|
||||||
|
<a *ngIf="isBookmarksAvailable && !isLocked" href class="action-bar__link action-bar__link--bookmark" title="Bookmark"
|
||||||
|
[class.bookmarked]="isBookmarked" [class.favoriting]="bookmarkingIsLoading" (click)="bookmark()">
|
||||||
|
<fa-icon [icon]="faBookmark"></fa-icon>
|
||||||
|
</a>
|
||||||
|
<fa-icon *ngIf="isBookmarksAvailable && isLocked" class="action-bar__lock" title="Account can't access this post" [icon]="faLock"></fa-icon>
|
||||||
|
|
||||||
<a href class="action-bar__link action-bar__link--cw" title="show content" (click)="showContent()"
|
<a href class="action-bar__link action-bar__link--cw" title="show content" (click)="showContent()"
|
||||||
*ngIf="isContentWarningActive">
|
*ngIf="isContentWarningActive">
|
||||||
<fa-icon [icon]="faWindowClose"></fa-icon>
|
<fa-icon [icon]="faWindowClose"></fa-icon>
|
||||||
@ -28,48 +35,6 @@
|
|||||||
<fa-icon [icon]="faWindowCloseRegular"></fa-icon>
|
<fa-icon [icon]="faWindowCloseRegular"></fa-icon>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<app-status-user-context-menu class="action-bar__link action-bar__link--more" [statusWrapper]="statusWrapper" (browseThreadEvent)="browseThread($event)"></app-status-user-context-menu>
|
<app-status-user-context-menu class="action-bar__link action-bar__link--more" [statusWrapper]="statusWrapper"
|
||||||
<!-- <a href class="action-bar__link action-bar__link--more" (click)="onContextMenu($event)" title="More">
|
(browseThreadEvent)="browseThread($event)"></app-status-user-context-menu>
|
||||||
<fa-icon [icon]="faEllipsisH"></fa-icon>
|
|
||||||
</a>
|
|
||||||
<context-menu #contextMenu>
|
|
||||||
<ng-template contextMenuItem (execute)="expandStatus()">
|
|
||||||
Expand status
|
|
||||||
</ng-template>
|
|
||||||
<ng-template contextMenuItem (execute)="copyStatusLink()">
|
|
||||||
Copy link to status
|
|
||||||
</ng-template>
|
|
||||||
<ng-template contextMenuItem divider="true"></ng-template>
|
|
||||||
<ng-template contextMenuItem (execute)="mentionAccount()" *ngIf="!isOwnerSelected">
|
|
||||||
Mention @{{ this.username }}
|
|
||||||
</ng-template>
|
|
||||||
<ng-template contextMenuItem (execute)="dmAccount()" *ngIf="!isOwnerSelected">
|
|
||||||
Direct message @{{ this.username }}
|
|
||||||
</ng-template>
|
|
||||||
<ng-template contextMenuItem (execute)="muteConversation()" *ngIf="isOwnerSelected && !displayedStatus.muted">
|
|
||||||
Mute conversation
|
|
||||||
</ng-template>
|
|
||||||
<ng-template contextMenuItem (execute)="unmuteConversation()" *ngIf="isOwnerSelected && displayedStatus.muted">
|
|
||||||
Unmute conversation
|
|
||||||
</ng-template>
|
|
||||||
<ng-template contextMenuItem divider="true"></ng-template>
|
|
||||||
<ng-template contextMenuItem (execute)="muteAccount()" *ngIf="!isOwnerSelected">
|
|
||||||
Mute @{{ this.username }}
|
|
||||||
</ng-template>
|
|
||||||
<ng-template contextMenuItem (execute)="blockAccount()" *ngIf="!isOwnerSelected">
|
|
||||||
Block @{{ this.username }}
|
|
||||||
</ng-template>
|
|
||||||
<ng-template contextMenuItem (execute)="pinOnProfile()" *ngIf="isOwnerSelected && !displayedStatus.pinned && displayedStatus.visibility === 'public'">
|
|
||||||
Pin on profile
|
|
||||||
</ng-template>
|
|
||||||
<ng-template contextMenuItem (execute)="unpinFromProfile()" *ngIf="isOwnerSelected && displayedStatus.pinned && displayedStatus.visibility === 'public'">
|
|
||||||
Unpin from profile
|
|
||||||
</ng-template>
|
|
||||||
<ng-template contextMenuItem (execute)="delete(false)" *ngIf="isOwnerSelected">
|
|
||||||
Delete
|
|
||||||
</ng-template>
|
|
||||||
<ng-template contextMenuItem (execute)="delete(true)" *ngIf="isOwnerSelected">
|
|
||||||
Delete & re-draft
|
|
||||||
</ng-template>
|
|
||||||
</context-menu> -->
|
|
||||||
</div>
|
</div>
|
@ -1,7 +1,7 @@
|
|||||||
@import "variables";
|
@import "variables";
|
||||||
|
|
||||||
.action-bar {
|
.action-bar {
|
||||||
// outline: 1px solid greenyellow; // height: 20px;
|
//outline: 1px solid greenyellow; // height: 20px;
|
||||||
margin: 5px 0px 5px $avatar-column-space;
|
margin: 5px 0px 5px $avatar-column-space;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
@ -10,17 +10,18 @@
|
|||||||
// transform: rotate(0.03deg);
|
// transform: rotate(0.03deg);
|
||||||
|
|
||||||
&__link {
|
&__link {
|
||||||
|
//outline: 1px solid greenyellow;
|
||||||
color: $status-secondary-color;
|
color: $status-secondary-color;
|
||||||
|
padding: 0 4px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $status-links-color;
|
color: $status-links-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(:last-child) {
|
&:not(:last-child) {
|
||||||
margin-right: 15px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
&--reply {
|
&--reply {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
@ -35,6 +36,14 @@
|
|||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--bookmark {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
padding: 0 8px;
|
||||||
|
// bottom: -1px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
&--cw {
|
&--cw {
|
||||||
position: relative;
|
position: relative;
|
||||||
bottom: -2px;
|
bottom: -2px;
|
||||||
@ -86,6 +95,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bookmarked {
|
||||||
|
color: $bookmarked-color;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: darken($bookmarked-color, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes loadingAnimation {
|
@keyframes loadingAnimation {
|
||||||
0% {
|
0% {
|
||||||
|
@ -2,13 +2,13 @@ import { Component, OnInit, OnDestroy, Input, Output, EventEmitter } from '@angu
|
|||||||
import { HttpErrorResponse } from '@angular/common/http';
|
import { HttpErrorResponse } from '@angular/common/http';
|
||||||
import { Store } from '@ngxs/store';
|
import { Store } from '@ngxs/store';
|
||||||
import { Observable, Subscription } from 'rxjs';
|
import { Observable, Subscription } from 'rxjs';
|
||||||
import { faWindowClose, faReply, faRetweet, faStar, faEllipsisH, faLock, faEnvelope } from "@fortawesome/free-solid-svg-icons";
|
import { faWindowClose, faReply, faRetweet, faStar, faEllipsisH, faLock, faEnvelope, faBookmark } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { faWindowClose as faWindowCloseRegular } from "@fortawesome/free-regular-svg-icons";
|
import { faWindowClose as faWindowCloseRegular } from "@fortawesome/free-regular-svg-icons";
|
||||||
|
|
||||||
import { MastodonWrapperService } from '../../../../services/mastodon-wrapper.service';
|
import { MastodonWrapperService } from '../../../../services/mastodon-wrapper.service';
|
||||||
import { AccountInfo } from '../../../../states/accounts.state';
|
import { AccountInfo } from '../../../../states/accounts.state';
|
||||||
import { Status, Account, Results } from '../../../../services/models/mastodon.interfaces';
|
import { Status, Account, Results } from '../../../../services/models/mastodon.interfaces';
|
||||||
import { ToolsService, OpenThreadEvent } from '../../../../services/tools.service';
|
import { ToolsService, OpenThreadEvent, InstanceInfo } from '../../../../services/tools.service';
|
||||||
import { NotificationService } from '../../../../services/notification.service';
|
import { NotificationService } from '../../../../services/notification.service';
|
||||||
import { StatusWrapper } from '../../../../models/common.model';
|
import { StatusWrapper } from '../../../../models/common.model';
|
||||||
import { StatusesStateService, StatusState } from '../../../../services/statuses-state.service';
|
import { StatusesStateService, StatusState } from '../../../../services/statuses-state.service';
|
||||||
@ -27,6 +27,7 @@ export class ActionBarComponent implements OnInit, OnDestroy {
|
|||||||
faEllipsisH = faEllipsisH;
|
faEllipsisH = faEllipsisH;
|
||||||
faLock = faLock;
|
faLock = faLock;
|
||||||
faEnvelope = faEnvelope;
|
faEnvelope = faEnvelope;
|
||||||
|
faBookmark = faBookmark;
|
||||||
|
|
||||||
@Input() statusWrapper: StatusWrapper;
|
@Input() statusWrapper: StatusWrapper;
|
||||||
@Output() replyEvent = new EventEmitter();
|
@Output() replyEvent = new EventEmitter();
|
||||||
@ -34,13 +35,16 @@ export class ActionBarComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
@Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
|
@Output() browseThreadEvent = new EventEmitter<OpenThreadEvent>();
|
||||||
|
|
||||||
|
isBookmarked: boolean;
|
||||||
isFavorited: boolean;
|
isFavorited: boolean;
|
||||||
isBoosted: boolean;
|
isBoosted: boolean;
|
||||||
isDM: boolean;
|
isDM: boolean;
|
||||||
|
|
||||||
isBoostLocked: boolean;
|
isBoostLocked: boolean;
|
||||||
isLocked: boolean;
|
isLocked: boolean;
|
||||||
|
isBookmarksAvailable: boolean;
|
||||||
|
|
||||||
|
bookmarkingIsLoading: boolean;
|
||||||
favoriteIsLoading: boolean;
|
favoriteIsLoading: boolean;
|
||||||
boostIsLoading: boolean;
|
boostIsLoading: boolean;
|
||||||
|
|
||||||
@ -53,6 +57,7 @@ export class ActionBarComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
private favoriteStatePerAccountId: { [id: string]: boolean; } = {};
|
private favoriteStatePerAccountId: { [id: string]: boolean; } = {};
|
||||||
private bootedStatePerAccountId: { [id: string]: boolean; } = {};
|
private bootedStatePerAccountId: { [id: string]: boolean; } = {};
|
||||||
|
private bookmarkStatePerAccountId: { [id: string]: boolean; } = {};
|
||||||
|
|
||||||
private accounts$: Observable<AccountInfo[]>;
|
private accounts$: Observable<AccountInfo[]>;
|
||||||
private accountSub: Subscription;
|
private accountSub: Subscription;
|
||||||
@ -69,19 +74,17 @@ export class ActionBarComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
const status = this.statusWrapper.status;
|
this.displayedStatus = this.statusWrapper.status;
|
||||||
const account = this.statusWrapper.provider;
|
const account = this.statusWrapper.provider;
|
||||||
|
|
||||||
if (status.reblog) {
|
if (this.displayedStatus.reblog) {
|
||||||
this.favoriteStatePerAccountId[account.id] = status.reblog.favourited;
|
this.displayedStatus = this.displayedStatus.reblog;
|
||||||
this.bootedStatePerAccountId[account.id] = status.reblog.reblogged;
|
|
||||||
this.displayedStatus = status.reblog;
|
|
||||||
} else {
|
|
||||||
this.favoriteStatePerAccountId[account.id] = status.favourited;
|
|
||||||
this.bootedStatePerAccountId[account.id] = status.reblogged;
|
|
||||||
this.displayedStatus = status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.favoriteStatePerAccountId[account.id] = this.displayedStatus.favourited;
|
||||||
|
this.bootedStatePerAccountId[account.id] = this.displayedStatus.reblogged;
|
||||||
|
this.bookmarkStatePerAccountId[account.id] = this.displayedStatus.bookmarked;
|
||||||
|
|
||||||
this.analyseMemoryStatus();
|
this.analyseMemoryStatus();
|
||||||
|
|
||||||
if (this.displayedStatus.visibility === 'direct') {
|
if (this.displayedStatus.visibility === 'direct') {
|
||||||
@ -94,11 +97,20 @@ export class ActionBarComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this.statusStateSub = this.statusStateService.stateNotification.subscribe((state: StatusState) => {
|
this.statusStateSub = this.statusStateService.stateNotification.subscribe((state: StatusState) => {
|
||||||
if (state && state.statusId === this.displayedStatus.url) {
|
if (state && state.statusId === this.displayedStatus.url) {
|
||||||
|
|
||||||
|
if (state.isFavorited) {
|
||||||
this.favoriteStatePerAccountId[state.accountId] = state.isFavorited;
|
this.favoriteStatePerAccountId[state.accountId] = state.isFavorited;
|
||||||
|
}
|
||||||
|
if (state.isRebloged) {
|
||||||
this.bootedStatePerAccountId[state.accountId] = state.isRebloged;
|
this.bootedStatePerAccountId[state.accountId] = state.isRebloged;
|
||||||
|
}
|
||||||
|
if (state.isBookmarked) {
|
||||||
|
this.bookmarkStatePerAccountId[state.accountId] = state.isBookmarked;
|
||||||
|
}
|
||||||
|
|
||||||
this.checkIfFavorited();
|
this.checkIfFavorited();
|
||||||
this.checkIfBoosted();
|
this.checkIfBoosted();
|
||||||
|
this.checkIfBookmarked();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -115,6 +127,7 @@ export class ActionBarComponent implements OnInit, OnDestroy {
|
|||||||
memoryStatusState.forEach((state: StatusState) => {
|
memoryStatusState.forEach((state: StatusState) => {
|
||||||
this.favoriteStatePerAccountId[state.accountId] = state.isFavorited;
|
this.favoriteStatePerAccountId[state.accountId] = state.isFavorited;
|
||||||
this.bootedStatePerAccountId[state.accountId] = state.isRebloged;
|
this.bootedStatePerAccountId[state.accountId] = state.isRebloged;
|
||||||
|
this.bookmarkStatePerAccountId[state.accountId] = state.isBookmarked;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,10 +153,13 @@ export class ActionBarComponent implements OnInit, OnDestroy {
|
|||||||
this.isContentWarningActive = true;
|
this.isContentWarningActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.checkIfBookmarksAreAvailable(this.selectedAccounts[0]);
|
||||||
this.checkIfFavorited();
|
this.checkIfFavorited();
|
||||||
this.checkIfBoosted();
|
this.checkIfBoosted();
|
||||||
|
this.checkIfBookmarked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
showContent(): boolean {
|
showContent(): boolean {
|
||||||
this.isContentWarningActive = false;
|
this.isContentWarningActive = false;
|
||||||
this.cwIsActiveEvent.next(false);
|
this.cwIsActiveEvent.next(false);
|
||||||
@ -236,6 +252,49 @@ export class ActionBarComponent implements OnInit, OnDestroy {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bookmark(): boolean {
|
||||||
|
if (this.bookmarkingIsLoading) return;
|
||||||
|
|
||||||
|
this.bookmarkingIsLoading = true;
|
||||||
|
|
||||||
|
const account = this.toolsService.getSelectedAccounts()[0];
|
||||||
|
const usableStatus = this.toolsService.getStatusUsableByAccount(account, this.statusWrapper);
|
||||||
|
usableStatus
|
||||||
|
.then((status: Status) => {
|
||||||
|
if (this.isBookmarked && status.bookmarked) {
|
||||||
|
return this.mastodonService.unbookmark(account, status);
|
||||||
|
} else if (!this.isBookmarked && !status.bookmarked) {
|
||||||
|
return this.mastodonService.bookmark(account, status);
|
||||||
|
} else {
|
||||||
|
return Promise.resolve(status);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((bookmarkedStatus: Status) => {
|
||||||
|
let bookmarked = bookmarkedStatus.bookmarked; //FIXME: when pixelfed will return the good status
|
||||||
|
if (bookmarked === null) {
|
||||||
|
bookmarked = !this.bookmarkStatePerAccountId[account.id];
|
||||||
|
}
|
||||||
|
this.bookmarkStatePerAccountId[account.id] = bookmarked;
|
||||||
|
this.checkIfBookmarked();
|
||||||
|
})
|
||||||
|
.catch((err: HttpErrorResponse) => {
|
||||||
|
this.notificationService.notifyHttpError(err, account);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.statusStateService.statusBookmarkStatusChanged(this.displayedStatus.url, account.id, this.bookmarkStatePerAccountId[account.id]);
|
||||||
|
this.bookmarkingIsLoading = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// setTimeout(() => {
|
||||||
|
// this.isBookmarked = !this.isBookmarked;
|
||||||
|
// this.bookmarkingIsLoading = false;
|
||||||
|
// }, 2000);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private checkIfBoosted() {
|
private checkIfBoosted() {
|
||||||
const selectedAccount = <AccountInfo>this.selectedAccounts[0];
|
const selectedAccount = <AccountInfo>this.selectedAccounts[0];
|
||||||
if (selectedAccount) {
|
if (selectedAccount) {
|
||||||
@ -255,6 +314,30 @@ export class ActionBarComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private checkIfBookmarked() {
|
||||||
|
const selectedAccount = <AccountInfo>this.selectedAccounts[0];
|
||||||
|
|
||||||
|
if (selectedAccount) {
|
||||||
|
this.isBookmarked = this.bookmarkStatePerAccountId[selectedAccount.id];
|
||||||
|
} else {
|
||||||
|
this.isBookmarked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private checkIfBookmarksAreAvailable(account: AccountInfo) {
|
||||||
|
this.toolsService.getInstanceInfo(account)
|
||||||
|
.then((instance: InstanceInfo) => {
|
||||||
|
if (instance.major >= 3 && instance.minor >= 1) {
|
||||||
|
this.isBookmarksAvailable = true;
|
||||||
|
} else {
|
||||||
|
this.isBookmarksAvailable = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
this.isBookmarksAvailable = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
browseThread(event: OpenThreadEvent) {
|
browseThread(event: OpenThreadEvent) {
|
||||||
this.browseThreadEvent.next(event);
|
this.browseThreadEvent.next(event);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import { Store } from '@ngxs/store';
|
|||||||
import { Account, Status, Results, Context, Relationship, Instance, Attachment, Notification, List, Poll, Emoji, Conversation, ScheduledStatus, TokenData } from "./models/mastodon.interfaces";
|
import { Account, Status, Results, Context, Relationship, Instance, Attachment, Notification, List, Poll, Emoji, Conversation, ScheduledStatus, TokenData } from "./models/mastodon.interfaces";
|
||||||
import { AccountInfo, UpdateAccount } from '../states/accounts.state';
|
import { AccountInfo, UpdateAccount } from '../states/accounts.state';
|
||||||
import { StreamTypeEnum, StreamElement } from '../states/streams.state';
|
import { StreamTypeEnum, StreamElement } from '../states/streams.state';
|
||||||
import { FavoriteResult, VisibilityEnum, PollParameters, MastodonService } from './mastodon.service';
|
import { FavoriteResult, VisibilityEnum, PollParameters, MastodonService, BookmarkResult } from './mastodon.service';
|
||||||
import { AuthService } from './auth.service';
|
import { AuthService } from './auth.service';
|
||||||
import { AppInfo, RegisteredAppsStateModel } from '../states/registered-apps.state';
|
import { AppInfo, RegisteredAppsStateModel } from '../states/registered-apps.state';
|
||||||
|
|
||||||
@ -148,6 +148,13 @@ export class MastodonWrapperService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getBookmarks(account: AccountInfo, maxId: string = null): Promise<BookmarkResult> {
|
||||||
|
return this.refreshAccountIfNeeded(account)
|
||||||
|
.then((refreshedAccount: AccountInfo) => {
|
||||||
|
return this.mastodonService.getBookmarks(refreshedAccount, maxId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
searchAccount(account: AccountInfo, query: string, limit: number = 40, following: boolean = false, resolve = true): Promise<Account[]> {
|
searchAccount(account: AccountInfo, query: string, limit: number = 40, following: boolean = false, resolve = true): Promise<Account[]> {
|
||||||
return this.refreshAccountIfNeeded(account)
|
return this.refreshAccountIfNeeded(account)
|
||||||
.then((refreshedAccount: AccountInfo) => {
|
.then((refreshedAccount: AccountInfo) => {
|
||||||
@ -183,6 +190,20 @@ export class MastodonWrapperService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bookmark(account: AccountInfo, status: Status): Promise<Status> {
|
||||||
|
return this.refreshAccountIfNeeded(account)
|
||||||
|
.then((refreshedAccount: AccountInfo) => {
|
||||||
|
return this.mastodonService.bookmark(refreshedAccount, status);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
unbookmark(account: AccountInfo, status: Status): Promise<Status> {
|
||||||
|
return this.refreshAccountIfNeeded(account)
|
||||||
|
.then((refreshedAccount: AccountInfo) => {
|
||||||
|
return this.mastodonService.unbookmark(refreshedAccount, status);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
getRelationships(account: AccountInfo, accountsToRetrieve: Account[]): Promise<Relationship[]> {
|
getRelationships(account: AccountInfo, accountsToRetrieve: Account[]): Promise<Relationship[]> {
|
||||||
return this.refreshAccountIfNeeded(account)
|
return this.refreshAccountIfNeeded(account)
|
||||||
.then((refreshedAccount: AccountInfo) => {
|
.then((refreshedAccount: AccountInfo) => {
|
||||||
|
@ -188,6 +188,26 @@ export class MastodonService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getBookmarks(account: AccountInfo, maxId: string = null): Promise<BookmarkResult> {
|
||||||
|
let route = `https://${account.instance}${this.apiRoutes.getBookmarks}`;
|
||||||
|
|
||||||
|
if (maxId) route += `?max_id=${maxId}`;
|
||||||
|
|
||||||
|
const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}` });
|
||||||
|
return this.httpClient.get(route, { headers: headers, observe: "response" }).toPromise()
|
||||||
|
.then((res: HttpResponse<Status[]>) => {
|
||||||
|
const link = res.headers.get('Link');
|
||||||
|
let lastId = null;
|
||||||
|
if(link){
|
||||||
|
const maxId = link.split('max_id=')[1];
|
||||||
|
if(maxId){
|
||||||
|
lastId = maxId.split('>;')[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new BookmarkResult(lastId, res.body);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
searchAccount(account: AccountInfo, query: string, limit: number = 40, following: boolean = false, resolve = true): Promise<Account[]> {
|
searchAccount(account: AccountInfo, query: string, limit: number = 40, following: boolean = false, resolve = true): Promise<Account[]> {
|
||||||
const route = `https://${account.instance}${this.apiRoutes.searchForAccounts}?q=${query}&limit=${limit}&following=${following}&resolve=${resolve}`;
|
const route = `https://${account.instance}${this.apiRoutes.searchForAccounts}?q=${query}&limit=${limit}&following=${following}&resolve=${resolve}`;
|
||||||
const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}` });
|
const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}` });
|
||||||
@ -218,6 +238,18 @@ export class MastodonService {
|
|||||||
return this.httpClient.post<Status>(route, null, { headers: headers }).toPromise()
|
return this.httpClient.post<Status>(route, null, { headers: headers }).toPromise()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bookmark(account: AccountInfo, status: Status): Promise<Status> {
|
||||||
|
const route = `https://${account.instance}${this.apiRoutes.bookmarkingStatus}`.replace('{0}', status.id);
|
||||||
|
const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}` });
|
||||||
|
return this.httpClient.post<Status>(route, null, { headers: headers }).toPromise()
|
||||||
|
}
|
||||||
|
|
||||||
|
unbookmark(account: AccountInfo, status: Status): Promise<Status> {
|
||||||
|
const route = `https://${account.instance}${this.apiRoutes.unbookmarkingStatus}`.replace('{0}', status.id);
|
||||||
|
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[]> {
|
getRelationships(account: AccountInfo, accountsToRetrieve: Account[]): Promise<Relationship[]> {
|
||||||
let params = `?${this.formatArray(accountsToRetrieve.map(x => x.id.toString()), 'id')}`;
|
let params = `?${this.formatArray(accountsToRetrieve.map(x => x.id.toString()), 'id')}`;
|
||||||
|
|
||||||
@ -452,3 +484,9 @@ export class FavoriteResult {
|
|||||||
public max_id: string,
|
public max_id: string,
|
||||||
public favorites: Status[]) {}
|
public favorites: Status[]) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class BookmarkResult {
|
||||||
|
constructor(
|
||||||
|
public max_id: string,
|
||||||
|
public bookmarked: Status[]) {}
|
||||||
|
}
|
@ -70,4 +70,7 @@ export class ApiRoutes {
|
|||||||
getScheduledStatuses = '/api/v1/scheduled_statuses';
|
getScheduledStatuses = '/api/v1/scheduled_statuses';
|
||||||
putScheduleStatus = '/api/v1/scheduled_statuses/{0}';
|
putScheduleStatus = '/api/v1/scheduled_statuses/{0}';
|
||||||
deleteScheduleStatus = '/api/v1/scheduled_statuses/{0}';
|
deleteScheduleStatus = '/api/v1/scheduled_statuses/{0}';
|
||||||
|
bookmarkingStatus = '/api/v1/statuses/{0}/bookmark';
|
||||||
|
unbookmarkingStatus = '/api/v1/statuses/{0}/unbookmark';
|
||||||
|
getBookmarks = '/api/v1/bookmarks';
|
||||||
}
|
}
|
||||||
|
@ -187,6 +187,7 @@ export interface Status {
|
|||||||
language: string;
|
language: string;
|
||||||
pinned: boolean;
|
pinned: boolean;
|
||||||
muted: boolean;
|
muted: boolean;
|
||||||
|
bookmarked: boolean;
|
||||||
card: Card;
|
card: Card;
|
||||||
poll: Poll;
|
poll: Poll;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ export class StatusesStateService {
|
|||||||
this.cachedStatusStates[statusId] = {};
|
this.cachedStatusStates[statusId] = {};
|
||||||
|
|
||||||
if (!this.cachedStatusStates[statusId][accountId]) {
|
if (!this.cachedStatusStates[statusId][accountId]) {
|
||||||
this.cachedStatusStates[statusId][accountId] = new StatusState(statusId, accountId, isFavorited, false);
|
this.cachedStatusStates[statusId][accountId] = new StatusState(statusId, accountId, isFavorited, null, null);
|
||||||
} else {
|
} else {
|
||||||
this.cachedStatusStates[statusId][accountId].isFavorited = isFavorited;
|
this.cachedStatusStates[statusId][accountId].isFavorited = isFavorited;
|
||||||
}
|
}
|
||||||
@ -42,20 +42,35 @@ export class StatusesStateService {
|
|||||||
this.cachedStatusStates[statusId] = {};
|
this.cachedStatusStates[statusId] = {};
|
||||||
|
|
||||||
if (!this.cachedStatusStates[statusId][accountId]) {
|
if (!this.cachedStatusStates[statusId][accountId]) {
|
||||||
this.cachedStatusStates[statusId][accountId] = new StatusState(statusId, accountId, false, isRebloged);
|
this.cachedStatusStates[statusId][accountId] = new StatusState(statusId, accountId, null, isRebloged, null);
|
||||||
} else {
|
} else {
|
||||||
this.cachedStatusStates[statusId][accountId].isRebloged = isRebloged;
|
this.cachedStatusStates[statusId][accountId].isRebloged = isRebloged;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stateNotification.next(this.cachedStatusStates[statusId][accountId]);
|
this.stateNotification.next(this.cachedStatusStates[statusId][accountId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statusBookmarkStatusChanged(statusId: string, accountId: string, isBookmarked: boolean) {
|
||||||
|
if (!this.cachedStatusStates[statusId])
|
||||||
|
this.cachedStatusStates[statusId] = {};
|
||||||
|
|
||||||
|
if (!this.cachedStatusStates[statusId][accountId]) {
|
||||||
|
this.cachedStatusStates[statusId][accountId] = new StatusState(statusId, accountId, null, null, isBookmarked);
|
||||||
|
} else {
|
||||||
|
this.cachedStatusStates[statusId][accountId].isBookmarked = isBookmarked;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stateNotification.next(this.cachedStatusStates[statusId][accountId]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StatusState {
|
export class StatusState {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public statusId: string,
|
public statusId: string,
|
||||||
public accountId: string,
|
public accountId: string,
|
||||||
public isFavorited: boolean,
|
public isFavorited: boolean,
|
||||||
public isRebloged: boolean) {
|
public isRebloged: boolean,
|
||||||
|
public isBookmarked: boolean) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ $status-secondary-color: #4e5572;
|
|||||||
$status-links-color: #d9e1e8;
|
$status-links-color: #d9e1e8;
|
||||||
$boost-color : #5098eb;
|
$boost-color : #5098eb;
|
||||||
$favorite-color: #ffc16f;
|
$favorite-color: #ffc16f;
|
||||||
|
$bookmarked-color: #ff5050;
|
||||||
|
|
||||||
// Block dispositions
|
// Block dispositions
|
||||||
$scroll-bar-width: 8px;
|
$scroll-bar-width: 8px;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user