From 8ae2edf1649f6d1a7e2ce065e9f427774c820feb Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Wed, 11 Mar 2020 20:54:32 -0400 Subject: [PATCH 01/21] added resilience in account retrieval --- .../user-profile/user-profile.component.html | 8 +++- .../user-profile/user-profile.component.scss | 5 ++ .../user-profile/user-profile.component.ts | 8 +++- src/app/services/tools.service.ts | 47 +++++++++++++------ 4 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/app/components/stream/user-profile/user-profile.component.html b/src/app/components/stream/user-profile/user-profile.component.html index 80be98c2..1c332ad8 100644 --- a/src/app/components/stream/user-profile/user-profile.component.html +++ b/src/app/components/stream/user-profile/user-profile.component.html @@ -1,6 +1,6 @@
-
@@ -41,6 +41,10 @@ +
+ account couldn't be found. +
+
has moved to
-
+
diff --git a/src/app/components/stream/user-profile/user-profile.component.scss b/src/app/components/stream/user-profile/user-profile.component.scss index 8dae963b..09cb7890 100644 --- a/src/app/components/stream/user-profile/user-profile.component.scss +++ b/src/app/components/stream/user-profile/user-profile.component.scss @@ -21,6 +21,11 @@ $floating-header-height: 60px; // width: $stream-column-width; overflow: auto; + &__not-found { + padding-top: 15px; + text-align: center; + } + &__floating-header { transition: all .2s; transition-timing-function: ease-in; diff --git a/src/app/components/stream/user-profile/user-profile.component.ts b/src/app/components/stream/user-profile/user-profile.component.ts index e4fe07db..e0701be3 100644 --- a/src/app/components/stream/user-profile/user-profile.component.ts +++ b/src/app/components/stream/user-profile/user-profile.component.ts @@ -153,6 +153,12 @@ export class UserProfileComponent implements OnInit { this.currentlyUsedAccount = this.toolsService.getSelectedAccounts()[0]; return this.toolsService.findAccount(this.currentlyUsedAccount, this.lastAccountName) + // .then((account: Account) => { + // if(account != null) return account; + + // let fullName = `https://${this.lastAccountName.split('@')[2]}/@${this.lastAccountName.split('@')[1]}`; + // return this.toolsService.findAccount(this.currentlyUsedAccount, fullName); + // }) .then((account: Account) => { this.isLoading = false; this.statusLoading = true; @@ -170,7 +176,7 @@ export class UserProfileComponent implements OnInit { return Promise.all([getFollowStatusPromise, getStatusesPromise, getPinnedStatusesPromise]); }) .catch((err: HttpErrorResponse) => { - this.notificationService.notifyHttpError(err, this.currentlyUsedAccount); + //this.notificationService.notifyHttpError(err, this.currentlyUsedAccount); }) .then(() => { this.isLoading = false; diff --git a/src/app/services/tools.service.ts b/src/app/services/tools.service.ts index 73e7bd69..bae15c27 100644 --- a/src/app/services/tools.service.ts +++ b/src/app/services/tools.service.ts @@ -11,7 +11,7 @@ import { AppInfo, RegisteredAppsStateModel } from '../states/registered-apps.sta @Injectable({ providedIn: 'root' }) -export class ToolsService { +export class ToolsService { private accountAvatar: { [id: string]: string; } = {}; private instanceInfos: { [id: string]: InstanceInfo } = {}; @@ -99,31 +99,48 @@ export class ToolsService { return settings; } - saveSettings(settings: GlobalSettings){ + saveSettings(settings: GlobalSettings) { this.store.dispatch([ new SaveSettings(settings) ]); } findAccount(account: AccountInfo, accountName: string): Promise { + let findAccountFunc = (result: Results) => { + if (accountName[0] === '@') accountName = accountName.substr(1); + + const foundAccount = result.accounts.find( + x => (x.acct.toLowerCase() === accountName.toLowerCase() + || + (x.acct.toLowerCase().split('@')[0] === accountName.toLowerCase().split('@')[0]) + && x.url.replace('https://', '').split('/')[0] === accountName.toLowerCase().split('@')[1]) + ); + return foundAccount; + }; + + let searchVersion: 'v1' | 'v2' = 'v1'; return this.getInstanceInfo(account) .then(instance => { - let version: 'v1' | 'v2' = 'v1'; - if (instance.major >= 3) version = 'v2'; - return this.mastodonService.search(account, accountName, version, true); + //let version: 'v1' | 'v2' = 'v1'; + if (instance.major >= 3) searchVersion = 'v2'; + return this.mastodonService.search(account, accountName, searchVersion, true); }) - .then((result: Results) => { - if (accountName[0] === '@') accountName = accountName.substr(1); + .then((results: Results) => { + return findAccountFunc(results); + }) + .then((foundAccount: Account) => { + console.warn(accountName); - const foundAccount = result.accounts.find( - x => (x.acct.toLowerCase() === accountName.toLowerCase() - || - (x.acct.toLowerCase().split('@')[0] === accountName.toLowerCase().split('@')[0]) - && x.url.replace('https://', '').split('/')[0] === accountName.toLowerCase().split('@')[1]) - ); - return foundAccount; + if (foundAccount != null) return Promise.resolve(foundAccount); + + console.error('tada'); + let fullName = `https://${accountName.split('@')[1]}/@${accountName.split('@')[0]}`; + return this.mastodonService.search(account, fullName, searchVersion, true) + .then((results: Results) => { + return findAccountFunc(results); + }); }); - } + } getStatusUsableByAccount(account: AccountInfo, originalStatus: StatusWrapper): Promise { const isProvider = originalStatus.provider.id === account.id; From d9c570a1bf592d8cf6e7166e653b6c6db85c3135 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Wed, 11 Mar 2020 21:07:57 -0400 Subject: [PATCH 02/21] display icon on relationship error --- .../user-profile/user-profile.component.html | 14 ++++++++++++-- .../user-profile/user-profile.component.ts | 16 +++++++--------- src/app/services/tools.service.ts | 3 --- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/app/components/stream/user-profile/user-profile.component.html b/src/app/components/stream/user-profile/user-profile.component.html index 1c332ad8..49d0528a 100644 --- a/src/app/components/stream/user-profile/user-profile.component.html +++ b/src/app/components/stream/user-profile/user-profile.component.html @@ -21,7 +21,7 @@ class="waiting-icon profile-header__follow--waiting"> -
@@ -68,7 +73,7 @@ class="waiting-icon profile-header__follow--waiting"> -
diff --git a/src/app/components/stream/user-profile/user-profile.component.ts b/src/app/components/stream/user-profile/user-profile.component.ts index e0701be3..4cbd9f6a 100644 --- a/src/app/components/stream/user-profile/user-profile.component.ts +++ b/src/app/components/stream/user-profile/user-profile.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit, Input, Output, EventEmitter, ViewChild, ElementRef } from '@angular/core'; import { HttpErrorResponse } from '@angular/common/http'; -import { faUser, faHourglassHalf, faUserCheck } from "@fortawesome/free-solid-svg-icons"; +import { faUser, faHourglassHalf, faUserCheck, faExclamationTriangle } from "@fortawesome/free-solid-svg-icons"; import { faUser as faUserRegular } from "@fortawesome/free-regular-svg-icons"; import { Observable, Subscription } from 'rxjs'; import { Store } from '@ngxs/store'; @@ -26,6 +26,7 @@ export class UserProfileComponent implements OnInit { faUserRegular = faUserRegular; faHourglassHalf = faHourglassHalf; faUserCheck = faUserCheck; + faExclamationTriangle = faExclamationTriangle; displayedAccount: Account; hasNote: boolean; @@ -34,6 +35,7 @@ export class UserProfileComponent implements OnInit { isLoading: boolean; loadingRelationShip = false; + relationShipError = false; showFloatingHeader = false; showFloatingStatusMenu = false; @@ -101,12 +103,14 @@ export class UserProfileComponent implements OnInit { const userAccount = accounts.filter(x => x.isSelected)[0]; this.loadingRelationShip = true; + this.relationShipError = false; this.toolsService.findAccount(userAccount, this.lastAccountName) .then((account: Account) => { return this.getFollowStatus(userAccount, account); }) .catch((err: HttpErrorResponse) => { - this.notificationService.notifyHttpError(err, userAccount); + console.error(err); + this.relationShipError = true; }) .then(() => { this.loadingRelationShip = false; @@ -153,12 +157,6 @@ export class UserProfileComponent implements OnInit { this.currentlyUsedAccount = this.toolsService.getSelectedAccounts()[0]; return this.toolsService.findAccount(this.currentlyUsedAccount, this.lastAccountName) - // .then((account: Account) => { - // if(account != null) return account; - - // let fullName = `https://${this.lastAccountName.split('@')[2]}/@${this.lastAccountName.split('@')[1]}`; - // return this.toolsService.findAccount(this.currentlyUsedAccount, fullName); - // }) .then((account: Account) => { this.isLoading = false; this.statusLoading = true; @@ -176,7 +174,7 @@ export class UserProfileComponent implements OnInit { return Promise.all([getFollowStatusPromise, getStatusesPromise, getPinnedStatusesPromise]); }) .catch((err: HttpErrorResponse) => { - //this.notificationService.notifyHttpError(err, this.currentlyUsedAccount); + console.error(err); }) .then(() => { this.isLoading = false; diff --git a/src/app/services/tools.service.ts b/src/app/services/tools.service.ts index bae15c27..4778dd3a 100644 --- a/src/app/services/tools.service.ts +++ b/src/app/services/tools.service.ts @@ -129,11 +129,8 @@ export class ToolsService { return findAccountFunc(results); }) .then((foundAccount: Account) => { - console.warn(accountName); - if (foundAccount != null) return Promise.resolve(foundAccount); - console.error('tada'); let fullName = `https://${accountName.split('@')[1]}/@${accountName.split('@')[0]}`; return this.mastodonService.search(account, fullName, searchVersion, true) .then((results: Results) => { From 2cb2e8770e9f7b152ac367df168591dfedaa7385 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Wed, 11 Mar 2020 21:28:16 -0400 Subject: [PATCH 03/21] fix exception not properly handled --- .../stream/user-profile/user-profile.component.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/components/stream/user-profile/user-profile.component.ts b/src/app/components/stream/user-profile/user-profile.component.ts index 4cbd9f6a..a969ae98 100644 --- a/src/app/components/stream/user-profile/user-profile.component.ts +++ b/src/app/components/stream/user-profile/user-profile.component.ts @@ -106,9 +106,11 @@ export class UserProfileComponent implements OnInit { this.relationShipError = false; this.toolsService.findAccount(userAccount, this.lastAccountName) .then((account: Account) => { + if(!account) throw Error(`Could not find ${this.lastAccountName}`); + return this.getFollowStatus(userAccount, account); }) - .catch((err: HttpErrorResponse) => { + .catch((err) => { console.error(err); this.relationShipError = true; }) @@ -161,6 +163,8 @@ export class UserProfileComponent implements OnInit { this.isLoading = false; this.statusLoading = true; + if(!account) throw Error(`Could not find ${this.lastAccountName}`); + this.displayedAccount = this.fixPleromaFieldsUrl(account); this.hasNote = account && account.note && account.note !== '

'; if (this.hasNote) { From 57b98e9e4f536c04ba0ae84ebe1d2ca39560c461 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Thu, 12 Mar 2020 19:54:52 -0400 Subject: [PATCH 04/21] added bookmarks in service and models --- src/app/services/mastodon-wrapper.service.ts | 14 ++++++++++++++ src/app/services/mastodon.service.ts | 12 ++++++++++++ src/app/services/models/api.settings.ts | 2 ++ src/app/services/models/mastodon.interfaces.ts | 1 + 4 files changed, 29 insertions(+) diff --git a/src/app/services/mastodon-wrapper.service.ts b/src/app/services/mastodon-wrapper.service.ts index f5262783..0d592055 100644 --- a/src/app/services/mastodon-wrapper.service.ts +++ b/src/app/services/mastodon-wrapper.service.ts @@ -183,6 +183,20 @@ export class MastodonWrapperService { }); } + bookmark(account: AccountInfo, status: Status): Promise { + return this.refreshAccountIfNeeded(account) + .then((refreshedAccount: AccountInfo) => { + return this.mastodonService.bookmark(refreshedAccount, status); + }); + } + + unbookmark(account: AccountInfo, status: Status): Promise { + return this.refreshAccountIfNeeded(account) + .then((refreshedAccount: AccountInfo) => { + return this.mastodonService.unbookmark(refreshedAccount, status); + }); + } + getRelationships(account: AccountInfo, accountsToRetrieve: Account[]): Promise { return this.refreshAccountIfNeeded(account) .then((refreshedAccount: AccountInfo) => { diff --git a/src/app/services/mastodon.service.ts b/src/app/services/mastodon.service.ts index 076e928c..bbddeeb1 100644 --- a/src/app/services/mastodon.service.ts +++ b/src/app/services/mastodon.service.ts @@ -218,6 +218,18 @@ export class MastodonService { return this.httpClient.post(route, null, { headers: headers }).toPromise() } + bookmark(account: AccountInfo, status: Status): Promise { + 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(route, null, { headers: headers }).toPromise() + } + + unbookmark(account: AccountInfo, status: Status): Promise { + 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(route, null, { headers: headers }).toPromise() + } + getRelationships(account: AccountInfo, accountsToRetrieve: Account[]): Promise { let params = `?${this.formatArray(accountsToRetrieve.map(x => x.id.toString()), 'id')}`; diff --git a/src/app/services/models/api.settings.ts b/src/app/services/models/api.settings.ts index 0b82ffc7..1b001c8f 100644 --- a/src/app/services/models/api.settings.ts +++ b/src/app/services/models/api.settings.ts @@ -70,4 +70,6 @@ export class ApiRoutes { getScheduledStatuses = '/api/v1/scheduled_statuses'; putScheduleStatus = '/api/v1/scheduled_statuses/{0}'; deleteScheduleStatus = '/api/v1/scheduled_statuses/{0}'; + bookmarkingStatus = '/api/v1/statuses/{0}/bookmark'; + unbookmarkingStatus = '/api/v1/statuses/{0}/unbookmark'; } diff --git a/src/app/services/models/mastodon.interfaces.ts b/src/app/services/models/mastodon.interfaces.ts index b5c8f476..844585e6 100644 --- a/src/app/services/models/mastodon.interfaces.ts +++ b/src/app/services/models/mastodon.interfaces.ts @@ -187,6 +187,7 @@ export interface Status { language: string; pinned: boolean; muted: boolean; + bookmarked: boolean; card: Card; poll: Poll; From 3b8448369d5a0eb15ddc62c63696c006fa22d42e Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Thu, 12 Mar 2020 20:23:53 -0400 Subject: [PATCH 05/21] added bookmark design --- .../action-bar/action-bar.component.html | 55 ++++--------------- .../action-bar/action-bar.component.scss | 13 +++++ .../status/action-bar/action-bar.component.ts | 17 +++++- src/sass/_variables.scss | 1 + 4 files changed, 40 insertions(+), 46 deletions(-) diff --git a/src/app/components/stream/status/action-bar/action-bar.component.html b/src/app/components/stream/status/action-bar/action-bar.component.html index f783c925..d4f00bb1 100644 --- a/src/app/components/stream/status/action-bar/action-bar.component.html +++ b/src/app/components/stream/status/action-bar/action-bar.component.html @@ -11,7 +11,8 @@ - + @@ -19,6 +20,12 @@ + + + + + @@ -28,48 +35,6 @@ - - +
\ No newline at end of file diff --git a/src/app/components/stream/status/action-bar/action-bar.component.scss b/src/app/components/stream/status/action-bar/action-bar.component.scss index e49a119d..0f1f22b9 100644 --- a/src/app/components/stream/status/action-bar/action-bar.component.scss +++ b/src/app/components/stream/status/action-bar/action-bar.component.scss @@ -34,6 +34,12 @@ &--fav { font-size: 17px; } + + &--bookmark { + position: relative; + // bottom: -1px; + font-size: 16px; + } &--cw { position: relative; @@ -86,6 +92,13 @@ } } +.bookmarked { + color: $bookmarked-color; + + &:hover { + color: darken($bookmarked-color, 10); + } +} @keyframes loadingAnimation { 0% { diff --git a/src/app/components/stream/status/action-bar/action-bar.component.ts b/src/app/components/stream/status/action-bar/action-bar.component.ts index 5b2f2f95..986f9727 100644 --- a/src/app/components/stream/status/action-bar/action-bar.component.ts +++ b/src/app/components/stream/status/action-bar/action-bar.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit, OnDestroy, Input, Output, EventEmitter } from '@angu import { HttpErrorResponse } from '@angular/common/http'; import { Store } from '@ngxs/store'; 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 { MastodonWrapperService } from '../../../../services/mastodon-wrapper.service'; @@ -27,6 +27,7 @@ export class ActionBarComponent implements OnInit, OnDestroy { faEllipsisH = faEllipsisH; faLock = faLock; faEnvelope = faEnvelope; + faBookmark = faBookmark; @Input() statusWrapper: StatusWrapper; @Output() replyEvent = new EventEmitter(); @@ -34,6 +35,7 @@ export class ActionBarComponent implements OnInit, OnDestroy { @Output() browseThreadEvent = new EventEmitter(); + isBookmarked: boolean; isFavorited: boolean; isBoosted: boolean; isDM: boolean; @@ -41,6 +43,7 @@ export class ActionBarComponent implements OnInit, OnDestroy { isBoostLocked: boolean; isLocked: boolean; + bookmarkingIsLoading: boolean; favoriteIsLoading: boolean; boostIsLoading: boolean; @@ -236,6 +239,18 @@ export class ActionBarComponent implements OnInit, OnDestroy { return false; } + bookmark(): boolean { + if (this.bookmarkingIsLoading) return; + + this.bookmarkingIsLoading = true; + setTimeout(() => { + this.isBookmarked = !this.isBookmarked; + this.bookmarkingIsLoading = false; + }, 2000); + + return false; + } + private checkIfBoosted() { const selectedAccount = this.selectedAccounts[0]; if (selectedAccount) { diff --git a/src/sass/_variables.scss b/src/sass/_variables.scss index 59a951ae..23905ab1 100644 --- a/src/sass/_variables.scss +++ b/src/sass/_variables.scss @@ -22,6 +22,7 @@ $status-secondary-color: #4e5572; $status-links-color: #d9e1e8; $boost-color : #5098eb; $favorite-color: #ffc16f; +$bookmarked-color: #ff5050; // Block dispositions $scroll-bar-width: 8px; From a9350ff31bd60213225969d23b0919a8cb9f866e Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Fri, 13 Mar 2020 20:20:51 -0400 Subject: [PATCH 06/21] wirering bookmarks to service --- .../status/action-bar/action-bar.component.ts | 56 +++++++++++++++++-- src/app/services/statuses-state.service.ts | 23 ++++++-- 2 files changed, 71 insertions(+), 8 deletions(-) diff --git a/src/app/components/stream/status/action-bar/action-bar.component.ts b/src/app/components/stream/status/action-bar/action-bar.component.ts index 986f9727..fc30c485 100644 --- a/src/app/components/stream/status/action-bar/action-bar.component.ts +++ b/src/app/components/stream/status/action-bar/action-bar.component.ts @@ -56,6 +56,7 @@ export class ActionBarComponent implements OnInit, OnDestroy { private favoriteStatePerAccountId: { [id: string]: boolean; } = {}; private bootedStatePerAccountId: { [id: string]: boolean; } = {}; + private bookmarkStatePerAccountId: { [id: string]: boolean; } = {}; private accounts$: Observable; private accountSub: Subscription; @@ -78,10 +79,12 @@ export class ActionBarComponent implements OnInit, OnDestroy { if (status.reblog) { this.favoriteStatePerAccountId[account.id] = status.reblog.favourited; this.bootedStatePerAccountId[account.id] = status.reblog.reblogged; + this.bookmarkStatePerAccountId[account.id] = status.reblog.bookmarked; this.displayedStatus = status.reblog; } else { this.favoriteStatePerAccountId[account.id] = status.favourited; this.bootedStatePerAccountId[account.id] = status.reblogged; + this.bookmarkStatePerAccountId[account.id] = status.bookmarked; this.displayedStatus = status; } @@ -99,9 +102,11 @@ export class ActionBarComponent implements OnInit, OnDestroy { if (state && state.statusId === this.displayedStatus.url) { this.favoriteStatePerAccountId[state.accountId] = state.isFavorited; this.bootedStatePerAccountId[state.accountId] = state.isRebloged; + this.bookmarkStatePerAccountId[state.accountId] = state.isBookmarked; this.checkIfFavorited(); this.checkIfBoosted(); + this.checkIfBookmarked(); } }); } @@ -118,6 +123,7 @@ export class ActionBarComponent implements OnInit, OnDestroy { memoryStatusState.forEach((state: StatusState) => { this.favoriteStatePerAccountId[state.accountId] = state.isFavorited; this.bootedStatePerAccountId[state.accountId] = state.isRebloged; + this.bookmarkStatePerAccountId[state.accountId] = state.isBookmarked; }); } @@ -145,6 +151,7 @@ export class ActionBarComponent implements OnInit, OnDestroy { this.checkIfFavorited(); this.checkIfBoosted(); + this.checkIfBookmarked(); } showContent(): boolean { @@ -243,10 +250,41 @@ export class ActionBarComponent implements OnInit, OnDestroy { if (this.bookmarkingIsLoading) return; this.bookmarkingIsLoading = true; - setTimeout(() => { - this.isBookmarked = !this.isBookmarked; - this.bookmarkingIsLoading = false; - }, 2000); + + 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; } @@ -270,6 +308,16 @@ export class ActionBarComponent implements OnInit, OnDestroy { } } + private checkIfBookmarked() { + const selectedAccount = this.selectedAccounts[0]; + + if (selectedAccount) { + this.isBookmarked = this.bookmarkStatePerAccountId[selectedAccount.id]; + } else { + this.isBookmarked = false; + } + } + browseThread(event: OpenThreadEvent) { this.browseThreadEvent.next(event); } diff --git a/src/app/services/statuses-state.service.ts b/src/app/services/statuses-state.service.ts index e8e67d99..5dcdd140 100644 --- a/src/app/services/statuses-state.service.ts +++ b/src/app/services/statuses-state.service.ts @@ -5,7 +5,7 @@ import { Subject } from 'rxjs'; @Injectable({ providedIn: 'root' }) -export class StatusesStateService { +export class StatusesStateService { private cachedStatusStates: { [statusId: string]: { [accountId: string]: StatusState } } = {}; public stateNotification = new Subject(); @@ -29,7 +29,7 @@ export class StatusesStateService { this.cachedStatusStates[statusId] = {}; if (!this.cachedStatusStates[statusId][accountId]) { - this.cachedStatusStates[statusId][accountId] = new StatusState(statusId, accountId, isFavorited, false); + this.cachedStatusStates[statusId][accountId] = new StatusState(statusId, accountId, isFavorited, false, false); } else { this.cachedStatusStates[statusId][accountId].isFavorited = isFavorited; } @@ -42,20 +42,35 @@ export class StatusesStateService { this.cachedStatusStates[statusId] = {}; if (!this.cachedStatusStates[statusId][accountId]) { - this.cachedStatusStates[statusId][accountId] = new StatusState(statusId, accountId, false, isRebloged); + this.cachedStatusStates[statusId][accountId] = new StatusState(statusId, accountId, false, isRebloged, false); } else { this.cachedStatusStates[statusId][accountId].isRebloged = isRebloged; } 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, false, false, isBookmarked); + } else { + this.cachedStatusStates[statusId][accountId].isBookmarked = isBookmarked; + } + + this.stateNotification.next(this.cachedStatusStates[statusId][accountId]); + } } export class StatusState { + constructor( public statusId: string, public accountId: string, public isFavorited: boolean, - public isRebloged: boolean) { + public isRebloged: boolean, + public isBookmarked: boolean) { } } From 9aefdbe870bb20fbfe3b2f52c6bde2e6b1eb2cfb Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Fri, 13 Mar 2020 20:25:51 -0400 Subject: [PATCH 07/21] refactoring --- .../status/action-bar/action-bar.component.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/app/components/stream/status/action-bar/action-bar.component.ts b/src/app/components/stream/status/action-bar/action-bar.component.ts index fc30c485..b15428a0 100644 --- a/src/app/components/stream/status/action-bar/action-bar.component.ts +++ b/src/app/components/stream/status/action-bar/action-bar.component.ts @@ -73,21 +73,17 @@ export class ActionBarComponent implements OnInit, OnDestroy { } ngOnInit() { - const status = this.statusWrapper.status; + this.displayedStatus = this.statusWrapper.status; const account = this.statusWrapper.provider; - if (status.reblog) { - this.favoriteStatePerAccountId[account.id] = status.reblog.favourited; - this.bootedStatePerAccountId[account.id] = status.reblog.reblogged; - this.bookmarkStatePerAccountId[account.id] = status.reblog.bookmarked; - this.displayedStatus = status.reblog; - } else { - this.favoriteStatePerAccountId[account.id] = status.favourited; - this.bootedStatePerAccountId[account.id] = status.reblogged; - this.bookmarkStatePerAccountId[account.id] = status.bookmarked; - this.displayedStatus = status; + if(this.displayedStatus.reblog){ + this.displayedStatus = this.displayedStatus.reblog; } + this.favoriteStatePerAccountId[account.id] = this.displayedStatus.favourited; + this.bootedStatePerAccountId[account.id] = this.displayedStatus.reblogged; + this.bookmarkStatePerAccountId[account.id] = this.displayedStatus.bookmarked; + this.analyseMemoryStatus(); if (this.displayedStatus.visibility === 'direct') { From 0aed10cbffbeeb8e8f524799961aa1ab354c1df5 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Fri, 13 Mar 2020 20:37:21 -0400 Subject: [PATCH 08/21] limit bookmarks to mastodon > 3.1 --- .../action-bar/action-bar.component.html | 4 ++-- .../status/action-bar/action-bar.component.ts | 21 +++++++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/app/components/stream/status/action-bar/action-bar.component.html b/src/app/components/stream/status/action-bar/action-bar.component.html index d4f00bb1..c84d7145 100644 --- a/src/app/components/stream/status/action-bar/action-bar.component.html +++ b/src/app/components/stream/status/action-bar/action-bar.component.html @@ -20,11 +20,11 @@ - - + diff --git a/src/app/components/stream/status/action-bar/action-bar.component.ts b/src/app/components/stream/status/action-bar/action-bar.component.ts index b15428a0..ed4952bd 100644 --- a/src/app/components/stream/status/action-bar/action-bar.component.ts +++ b/src/app/components/stream/status/action-bar/action-bar.component.ts @@ -8,7 +8,7 @@ import { faWindowClose as faWindowCloseRegular } from "@fortawesome/free-regular import { MastodonWrapperService } from '../../../../services/mastodon-wrapper.service'; import { AccountInfo } from '../../../../states/accounts.state'; 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 { StatusWrapper } from '../../../../models/common.model'; import { StatusesStateService, StatusState } from '../../../../services/statuses-state.service'; @@ -42,6 +42,7 @@ export class ActionBarComponent implements OnInit, OnDestroy { isBoostLocked: boolean; isLocked: boolean; + isBookmarksAvailable: boolean; bookmarkingIsLoading: boolean; favoriteIsLoading: boolean; @@ -144,11 +145,13 @@ export class ActionBarComponent implements OnInit, OnDestroy { if (status.sensitive || status.spoiler_text) { this.isContentWarningActive = true; } - + + this.checkIfBookmarksAreAvailable(this.selectedAccounts[0]); this.checkIfFavorited(); this.checkIfBoosted(); this.checkIfBookmarked(); } + showContent(): boolean { this.isContentWarningActive = false; @@ -314,6 +317,20 @@ export class ActionBarComponent implements OnInit, OnDestroy { } } + 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) { this.browseThreadEvent.next(event); } From a41a46168a29d3c015eeb2e804b3d41caa585b21 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Fri, 13 Mar 2020 20:49:54 -0400 Subject: [PATCH 09/21] action icon design fix --- .../stream/status/action-bar/action-bar.component.scss | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/app/components/stream/status/action-bar/action-bar.component.scss b/src/app/components/stream/status/action-bar/action-bar.component.scss index 0f1f22b9..1a5ffa57 100644 --- a/src/app/components/stream/status/action-bar/action-bar.component.scss +++ b/src/app/components/stream/status/action-bar/action-bar.component.scss @@ -1,7 +1,7 @@ @import "variables"; .action-bar { - // outline: 1px solid greenyellow; // height: 20px; + //outline: 1px solid greenyellow; // height: 20px; margin: 5px 0px 5px $avatar-column-space; padding: 0; font-size: 18px; @@ -10,17 +10,18 @@ // transform: rotate(0.03deg); &__link { + //outline: 1px solid greenyellow; color: $status-secondary-color; + padding: 0 4px; &:hover { color: $status-links-color; } &:not(:last-child) { - margin-right: 15px; + margin-right: 8px; } - &--reply { font-size: 20px; } @@ -35,7 +36,7 @@ font-size: 17px; } - &--bookmark { + &--bookmark { position: relative; // bottom: -1px; font-size: 16px; From fe9cb7fea1b12323aca5dee20ee0450303195f83 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Fri, 13 Mar 2020 21:02:37 -0400 Subject: [PATCH 10/21] fix status new state overrinding current state --- .../status/action-bar/action-bar.component.ts | 21 ++++++++++++------- src/app/services/statuses-state.service.ts | 6 +++--- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/app/components/stream/status/action-bar/action-bar.component.ts b/src/app/components/stream/status/action-bar/action-bar.component.ts index ed4952bd..05160c57 100644 --- a/src/app/components/stream/status/action-bar/action-bar.component.ts +++ b/src/app/components/stream/status/action-bar/action-bar.component.ts @@ -77,7 +77,7 @@ export class ActionBarComponent implements OnInit, OnDestroy { this.displayedStatus = this.statusWrapper.status; const account = this.statusWrapper.provider; - if(this.displayedStatus.reblog){ + if (this.displayedStatus.reblog) { this.displayedStatus = this.displayedStatus.reblog; } @@ -97,9 +97,16 @@ export class ActionBarComponent implements OnInit, OnDestroy { this.statusStateSub = this.statusStateService.stateNotification.subscribe((state: StatusState) => { if (state && state.statusId === this.displayedStatus.url) { - this.favoriteStatePerAccountId[state.accountId] = state.isFavorited; - this.bootedStatePerAccountId[state.accountId] = state.isRebloged; - this.bookmarkStatePerAccountId[state.accountId] = state.isBookmarked; + + if (state.isFavorited) { + this.favoriteStatePerAccountId[state.accountId] = state.isFavorited; + } + if (state.isRebloged) { + this.bootedStatePerAccountId[state.accountId] = state.isRebloged; + } + if (state.isBookmarked) { + this.bookmarkStatePerAccountId[state.accountId] = state.isBookmarked; + } this.checkIfFavorited(); this.checkIfBoosted(); @@ -145,13 +152,13 @@ export class ActionBarComponent implements OnInit, OnDestroy { if (status.sensitive || status.spoiler_text) { this.isContentWarningActive = true; } - + this.checkIfBookmarksAreAvailable(this.selectedAccounts[0]); this.checkIfFavorited(); this.checkIfBoosted(); this.checkIfBookmarked(); } - + showContent(): boolean { this.isContentWarningActive = false; @@ -320,7 +327,7 @@ export class ActionBarComponent implements OnInit, OnDestroy { private checkIfBookmarksAreAvailable(account: AccountInfo) { this.toolsService.getInstanceInfo(account) .then((instance: InstanceInfo) => { - if(instance.major >= 3 && instance.minor >= 1){ + if (instance.major >= 3 && instance.minor >= 1) { this.isBookmarksAvailable = true; } else { this.isBookmarksAvailable = false; diff --git a/src/app/services/statuses-state.service.ts b/src/app/services/statuses-state.service.ts index 5dcdd140..7982c7ec 100644 --- a/src/app/services/statuses-state.service.ts +++ b/src/app/services/statuses-state.service.ts @@ -29,7 +29,7 @@ export class StatusesStateService { this.cachedStatusStates[statusId] = {}; if (!this.cachedStatusStates[statusId][accountId]) { - this.cachedStatusStates[statusId][accountId] = new StatusState(statusId, accountId, isFavorited, false, false); + this.cachedStatusStates[statusId][accountId] = new StatusState(statusId, accountId, isFavorited, null, null); } else { this.cachedStatusStates[statusId][accountId].isFavorited = isFavorited; } @@ -42,7 +42,7 @@ export class StatusesStateService { this.cachedStatusStates[statusId] = {}; if (!this.cachedStatusStates[statusId][accountId]) { - this.cachedStatusStates[statusId][accountId] = new StatusState(statusId, accountId, false, isRebloged, false); + this.cachedStatusStates[statusId][accountId] = new StatusState(statusId, accountId, null, isRebloged, null); } else { this.cachedStatusStates[statusId][accountId].isRebloged = isRebloged; } @@ -55,7 +55,7 @@ export class StatusesStateService { this.cachedStatusStates[statusId] = {}; if (!this.cachedStatusStates[statusId][accountId]) { - this.cachedStatusStates[statusId][accountId] = new StatusState(statusId, accountId, false, false, isBookmarked); + this.cachedStatusStates[statusId][accountId] = new StatusState(statusId, accountId, null, null, isBookmarked); } else { this.cachedStatusStates[statusId][accountId].isBookmarked = isBookmarked; } From 3a2761eeb11baa4dc95031da0c6a5fe562c16421 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Fri, 13 Mar 2020 21:06:08 -0400 Subject: [PATCH 11/21] added menu to check bookmarks --- .../manage-account.component.html | 7 +++++- .../manage-account.component.ts | 25 ++++++++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/app/components/floating-column/manage-account/manage-account.component.html b/src/app/components/floating-column/manage-account/manage-account.component.html index b6e92d85..ddbc59ab 100644 --- a/src/app/components/floating-column/manage-account/manage-account.component.html +++ b/src/app/components/floating-column/manage-account/manage-account.component.html @@ -3,10 +3,15 @@ + diff --git a/src/app/services/mastodon-wrapper.service.ts b/src/app/services/mastodon-wrapper.service.ts index 0d592055..a4767175 100644 --- a/src/app/services/mastodon-wrapper.service.ts +++ b/src/app/services/mastodon-wrapper.service.ts @@ -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 { AccountInfo, UpdateAccount } from '../states/accounts.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 { AppInfo, RegisteredAppsStateModel } from '../states/registered-apps.state'; @@ -148,6 +148,13 @@ export class MastodonWrapperService { }); } + getBookmarks(account: AccountInfo, maxId: string = null): Promise { + 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 { return this.refreshAccountIfNeeded(account) .then((refreshedAccount: AccountInfo) => { diff --git a/src/app/services/mastodon.service.ts b/src/app/services/mastodon.service.ts index bbddeeb1..4c611b2e 100644 --- a/src/app/services/mastodon.service.ts +++ b/src/app/services/mastodon.service.ts @@ -188,6 +188,26 @@ export class MastodonService { }); } + getBookmarks(account: AccountInfo, maxId: string = null): Promise { + 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) => { + 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 { 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}` }); @@ -463,4 +483,10 @@ export class FavoriteResult { constructor( public max_id: string, public favorites: Status[]) {} +} + +export class BookmarkResult { + constructor( + public max_id: string, + public bookmarked: Status[]) {} } \ No newline at end of file diff --git a/src/app/services/models/api.settings.ts b/src/app/services/models/api.settings.ts index 1b001c8f..c2e9dfc0 100644 --- a/src/app/services/models/api.settings.ts +++ b/src/app/services/models/api.settings.ts @@ -72,4 +72,5 @@ export class ApiRoutes { deleteScheduleStatus = '/api/v1/scheduled_statuses/{0}'; bookmarkingStatus = '/api/v1/statuses/{0}/bookmark'; unbookmarkingStatus = '/api/v1/statuses/{0}/unbookmark'; + getBookmarks = '/api/v1/bookmarks'; } From 917564c067ae36b30fdc6f390c29f27e5a74198d Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Sat, 14 Mar 2020 03:26:37 -0400 Subject: [PATCH 14/21] fix #228 --- .../floating-column/floating-column.component.html | 9 ++++++--- .../floating-column/search/search.component.html | 6 ++++-- .../floating-column/search/search.component.ts | 9 +++++---- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/app/components/floating-column/floating-column.component.html b/src/app/components/floating-column/floating-column.component.html index d2672e09..330e49fd 100644 --- a/src/app/components/floating-column/floating-column.component.html +++ b/src/app/components/floating-column/floating-column.component.html @@ -15,13 +15,16 @@
- + diff --git a/src/app/components/floating-column/search/search.component.html b/src/app/components/floating-column/search/search.component.html index f00a4d4f..9ee3d86f 100644 --- a/src/app/components/floating-column/search/search.component.html +++ b/src/app/components/floating-column/search/search.component.html @@ -35,8 +35,10 @@

Statuses

- +
diff --git a/src/app/components/floating-column/search/search.component.ts b/src/app/components/floating-column/search/search.component.ts index 8a4ef587..ab3ade42 100644 --- a/src/app/components/floating-column/search/search.component.ts +++ b/src/app/components/floating-column/search/search.component.ts @@ -54,15 +54,16 @@ export class SearchComponent implements OnInit { return false; } - browseAccount(account: Account): boolean { - let accountName = this.toolsService.getAccountFullHandle(account); - this.browseAccountEvent.next(accountName); + browseAccount(account: string): boolean { + if (account) { + this.browseAccountEvent.next(account); + } return false; } private lastAccountUsed: AccountInfo; private search(data: string) { - if(!data) return; + if (!data) return; this.accounts.length = 0; this.statuses.length = 0; From e6de93276445e739d04f21bb4564f76c417d99c0 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Sat, 14 Mar 2020 12:46:40 -0400 Subject: [PATCH 15/21] fix link preview overflow bug --- src/app/components/stream/status/card/card.component.html | 2 +- src/app/components/stream/status/card/card.component.scss | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/app/components/stream/status/card/card.component.html b/src/app/components/stream/status/card/card.component.html index 7d402c28..3a816859 100644 --- a/src/app/components/stream/status/card/card.component.html +++ b/src/app/components/stream/status/card/card.component.html @@ -1,5 +1,5 @@
- +