2019-08-10 01:08:18 +02:00
import { Component , OnInit , ViewChild , Output , EventEmitter , Input , OnDestroy } from '@angular/core' ;
import { faEllipsisH } from "@fortawesome/free-solid-svg-icons" ;
import { ContextMenuComponent , ContextMenuService } from 'ngx-contextmenu' ;
import { Observable , Subscription } from 'rxjs' ;
import { Store } from '@ngxs/store' ;
2023-04-24 01:21:54 +02:00
import { Status , Account , Results , Relationship } from '../../../../../services/models/mastodon.interfaces' ;
2022-11-19 18:16:31 +01:00
import { ToolsService , OpenThreadEvent , InstanceInfo } from '../../../../../services/tools.service' ;
2019-08-10 01:08:18 +02:00
import { StatusWrapper } from '../../../../../models/common.model' ;
import { NavigationService } from '../../../../../services/navigation.service' ;
import { AccountInfo } from '../../../../../states/accounts.state' ;
2019-10-02 06:14:40 +02:00
import { MastodonWrapperService } from '../../../../../services/mastodon-wrapper.service' ;
2019-08-10 01:08:18 +02:00
import { NotificationService } from '../../../../../services/notification.service' ;
@Component ( {
selector : 'app-status-user-context-menu' ,
templateUrl : './status-user-context-menu.component.html' ,
styleUrls : [ './status-user-context-menu.component.scss' ]
} )
2019-08-10 06:36:18 +02:00
export class StatusUserContextMenuComponent implements OnInit , OnDestroy {
2019-08-10 01:08:18 +02:00
faEllipsisH = faEllipsisH ;
private fullHandle : string ;
private loadedAccounts : AccountInfo [ ] ;
displayedStatus : Status ;
username : string ;
2023-08-20 02:02:37 +02:00
domain : string ;
2019-08-10 01:08:18 +02:00
isOwnerSelected : boolean ;
2022-11-19 18:16:31 +01:00
isEditingAvailable : boolean ;
2019-08-10 01:08:18 +02:00
@Input ( ) statusWrapper : StatusWrapper ;
2019-08-10 06:36:18 +02:00
@Input ( ) displayedAccount : Account ;
2023-04-24 01:21:54 +02:00
@Input ( ) relationship : Relationship ;
2019-08-10 01:08:18 +02:00
@Output ( ) browseThreadEvent = new EventEmitter < OpenThreadEvent > ( ) ;
2023-04-24 01:49:08 +02:00
@Output ( ) relationshipChanged = new EventEmitter < Relationship > ( ) ;
2019-08-10 01:08:18 +02:00
@ViewChild ( ContextMenuComponent ) public contextMenu : ContextMenuComponent ;
private accounts$ : Observable < AccountInfo [ ] > ;
private accountSub : Subscription ;
constructor (
private readonly store : Store ,
2019-10-02 06:14:40 +02:00
private readonly mastodonService : MastodonWrapperService ,
2019-08-10 01:08:18 +02:00
private readonly notificationService : NotificationService ,
private readonly navigationService : NavigationService ,
private readonly toolsService : ToolsService ,
2019-08-10 06:36:18 +02:00
private readonly contextMenuService : ContextMenuService ) {
this . accounts $ = this . store . select ( state = > state . registeredaccounts . accounts ) ;
}
2019-09-25 06:09:10 +02:00
ngOnInit() {
2019-08-10 06:36:18 +02:00
if ( this . statusWrapper ) {
const status = this . statusWrapper . status ;
if ( status . reblog ) {
this . displayedStatus = status . reblog ;
} else {
this . displayedStatus = status ;
2019-09-25 06:09:10 +02:00
}
2019-08-10 01:08:18 +02:00
}
2019-08-11 22:56:25 +02:00
this . accountSub = this . accounts $ . subscribe ( ( accounts : AccountInfo [ ] ) = > {
this . loadedAccounts = accounts ;
if ( this . statusWrapper ) this . checkStatus ( accounts ) ;
} ) ;
2019-08-10 06:36:18 +02:00
let account : Account ;
2019-09-25 06:09:10 +02:00
if ( this . statusWrapper ) {
2019-08-10 06:36:18 +02:00
account = this . displayedStatus . account ;
2019-08-10 01:08:18 +02:00
} else {
2019-08-10 06:36:18 +02:00
account = this . displayedAccount ;
2019-08-10 01:08:18 +02:00
}
2019-08-10 06:36:18 +02:00
this . username = account . acct . split ( '@' ) [ 0 ] ;
2023-08-20 02:02:37 +02:00
this . domain = account . acct . split ( '@' ) [ 1 ] ;
2019-08-10 06:36:18 +02:00
this . fullHandle = this . toolsService . getAccountFullHandle ( account ) ;
2019-08-10 01:08:18 +02:00
}
private checkStatus ( accounts : AccountInfo [ ] ) : void {
const selectedAccount = accounts . find ( x = > x . isSelected ) ;
2020-05-17 22:51:51 +02:00
2020-04-18 03:00:17 +02:00
this . isOwnerSelected = selectedAccount . username . toLowerCase ( ) === this . displayedStatus . account . username . toLowerCase ( )
&& selectedAccount . instance . toLowerCase ( ) === this . displayedStatus . account . url . replace ( 'https://' , '' ) . split ( '/' ) [ 0 ] . toLowerCase ( ) ;
2022-11-19 18:16:31 +01:00
this . toolsService . getInstanceInfo ( selectedAccount ) . then ( ( instanceInfo : InstanceInfo ) = > {
if ( instanceInfo . major >= 4 ) {
this . isEditingAvailable = true ;
} else {
this . isEditingAvailable = false ;
}
} ) ;
2019-08-10 01:08:18 +02:00
}
ngOnDestroy ( ) : void {
2019-09-25 06:09:10 +02:00
if ( this . accountSub ) this . accountSub . unsubscribe ( ) ;
2019-08-10 01:08:18 +02:00
}
public onContextMenu ( $event : MouseEvent ) : void {
this . contextMenuService . show . next ( {
// Optional - if unspecified, all context menu components will open
contextMenu : this.contextMenu ,
event : $event ,
item : null
} ) ;
$event . preventDefault ( ) ;
$event . stopPropagation ( ) ;
}
expandStatus ( ) : boolean {
const openThread = new OpenThreadEvent ( this . displayedStatus , this . statusWrapper . provider ) ;
this . browseThreadEvent . next ( openThread ) ;
return false ;
}
copyStatusLink ( ) : boolean {
let selBox = document . createElement ( 'textarea' ) ;
selBox . style . position = 'fixed' ;
selBox . style . left = '0' ;
selBox . style . top = '0' ;
selBox . style . opacity = '0' ;
selBox . value = this . displayedStatus . url ;
document . body . appendChild ( selBox ) ;
selBox . focus ( ) ;
selBox . select ( ) ;
document . execCommand ( 'copy' ) ;
document . body . removeChild ( selBox ) ;
return false ;
}
2020-05-17 22:51:51 +02:00
copyAllData ( ) : boolean {
const newLine = String . fromCharCode ( 13 , 10 ) ;
let selBox = document . createElement ( 'textarea' ) ;
selBox . style . position = 'fixed' ;
selBox . style . left = '0' ;
selBox . style . top = '0' ;
selBox . style . opacity = '0' ;
selBox . value = ` ${ this . displayedStatus . url } ${ newLine } ${ newLine } ${ this . displayedStatus . content } ${ newLine } ${ newLine } ` ;
let parser = new DOMParser ( ) ;
var dom = parser . parseFromString ( this . displayedStatus . content , 'text/html' )
selBox . value += ` ${ dom . body . textContent } ${ newLine } ${ newLine } ` ;
for ( const att of this . displayedStatus . media_attachments ) {
selBox . value += ` ${ att . url } ${ newLine } ${ newLine } ` ;
}
document . body . appendChild ( selBox ) ;
selBox . focus ( ) ;
selBox . select ( ) ;
document . execCommand ( 'copy' ) ;
document . body . removeChild ( selBox ) ;
return false ;
}
2019-08-10 01:08:18 +02:00
mentionAccount ( ) : boolean {
this . navigationService . replyToUser ( this . fullHandle , false ) ;
return false ;
}
dmAccount ( ) : boolean {
this . navigationService . replyToUser ( this . fullHandle , true ) ;
return false ;
}
2023-08-20 02:02:37 +02:00
hideBoosts ( ) : boolean {
const acc = this . toolsService . getSelectedAccounts ( ) [ 0 ] ;
this . toolsService . findAccount ( acc , this . fullHandle )
. then ( async ( target : Account ) = > {
const relationship = await this . mastodonService . hideBoosts ( acc , target ) ;
this . relationship = relationship ;
this . relationshipChanged . next ( relationship ) ;
} )
. catch ( err = > {
this . notificationService . notifyHttpError ( err , acc ) ;
} ) ;
return false ;
}
unhideBoosts ( ) : boolean {
const acc = this . toolsService . getSelectedAccounts ( ) [ 0 ] ;
this . toolsService . findAccount ( acc , this . fullHandle )
. then ( async ( target : Account ) = > {
const relationship = await this . mastodonService . unhideBoosts ( acc , target ) ;
this . relationship = relationship ;
this . relationshipChanged . next ( relationship ) ;
} )
. catch ( err = > {
this . notificationService . notifyHttpError ( err , acc ) ;
} ) ;
return false ;
}
2019-08-10 01:08:18 +02:00
muteAccount ( ) : boolean {
2023-04-24 01:49:08 +02:00
const acc = this . toolsService . getSelectedAccounts ( ) [ 0 ] ;
this . toolsService . findAccount ( acc , this . fullHandle )
. then ( async ( target : Account ) = > {
const relationship = await this . mastodonService . mute ( acc , target . id ) ;
this . relationship = relationship ;
this . relationshipChanged . next ( relationship ) ;
return target ;
} )
. then ( ( target : Account ) = > {
this . notificationService . hideAccount ( target ) ;
} )
. catch ( err = > {
this . notificationService . notifyHttpError ( err , acc ) ;
} ) ;
2019-08-10 01:08:18 +02:00
return false ;
}
2023-04-24 01:21:54 +02:00
unmuteAccount ( ) : boolean {
2023-04-24 01:49:08 +02:00
const acc = this . toolsService . getSelectedAccounts ( ) [ 0 ] ;
this . toolsService . findAccount ( acc , this . fullHandle )
. then ( async ( target : Account ) = > {
const relationship = await this . mastodonService . unmute ( acc , target . id ) ;
this . relationship = relationship ;
this . relationshipChanged . next ( relationship ) ;
return target ;
} )
. catch ( err = > {
this . notificationService . notifyHttpError ( err , acc ) ;
} ) ;
2023-04-24 01:21:54 +02:00
return false ;
}
2019-08-10 01:08:18 +02:00
blockAccount ( ) : boolean {
2023-04-24 01:49:08 +02:00
const acc = this . toolsService . getSelectedAccounts ( ) [ 0 ] ;
this . toolsService . findAccount ( acc , this . fullHandle )
. then ( async ( target : Account ) = > {
const relationship = await this . mastodonService . block ( acc , target . id ) ;
this . relationship = relationship ;
this . relationshipChanged . next ( relationship ) ;
return target ;
} )
. then ( ( target : Account ) = > {
this . notificationService . hideAccount ( target ) ;
} )
. catch ( err = > {
this . notificationService . notifyHttpError ( err , acc ) ;
} ) ;
2019-08-10 01:08:18 +02:00
return false ;
}
2023-04-24 01:21:54 +02:00
unblockAccount ( ) : boolean {
2023-04-24 01:49:08 +02:00
const acc = this . toolsService . getSelectedAccounts ( ) [ 0 ] ;
this . toolsService . findAccount ( acc , this . fullHandle )
. then ( async ( target : Account ) = > {
const relationship = await this . mastodonService . unblock ( acc , target . id ) ;
this . relationship = relationship ;
this . relationshipChanged . next ( relationship ) ;
return target ;
} )
. catch ( err = > {
this . notificationService . notifyHttpError ( err , acc ) ;
} ) ;
2023-04-24 01:21:54 +02:00
return false ;
}
2023-08-20 02:02:37 +02:00
blockDomain ( ) : boolean {
const response = confirm ( ` Are you really sure you want to block the entire ${ this . domain } domain? You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed. ` ) ;
if ( response ) {
const acc = this . toolsService . getSelectedAccounts ( ) [ 0 ] ;
this . mastodonService . blockDomain ( acc , this . domain )
. then ( _ = > {
this . relationship . domain_blocking = true ;
} )
. catch ( err = > {
this . notificationService . notifyHttpError ( err , acc ) ;
} ) ;
}
return false ;
}
unblockDomain ( ) : boolean {
const acc = this . toolsService . getSelectedAccounts ( ) [ 0 ] ;
this . mastodonService . blockDomain ( acc , this . domain )
. then ( _ = > {
this . relationship . domain_blocking = false ;
} )
. catch ( err = > {
this . notificationService . notifyHttpError ( err , acc ) ;
} ) ;
return false ;
}
2019-08-10 01:08:18 +02:00
muteConversation ( ) : boolean {
const selectedAccount = this . toolsService . getSelectedAccounts ( ) [ 0 ] ;
this . getStatus ( selectedAccount )
. then ( ( status : Status ) = > {
return this . mastodonService . muteConversation ( selectedAccount , status . id )
} )
. then ( ( status : Status ) = > {
this . displayedStatus . muted = status . muted ;
} )
. catch ( err = > {
2019-09-07 23:52:07 +02:00
this . notificationService . notifyHttpError ( err , selectedAccount ) ;
2019-08-10 01:08:18 +02:00
} ) ;
return false ;
}
unmuteConversation ( ) : boolean {
const selectedAccount = this . toolsService . getSelectedAccounts ( ) [ 0 ] ;
this . getStatus ( selectedAccount )
. then ( ( status : Status ) = > {
return this . mastodonService . unmuteConversation ( selectedAccount , status . id )
} )
. then ( ( status : Status ) = > {
this . displayedStatus . muted = status . muted ;
} )
. catch ( err = > {
2019-09-07 23:52:07 +02:00
this . notificationService . notifyHttpError ( err , selectedAccount ) ;
2019-08-10 01:08:18 +02:00
} ) ;
return false ;
}
pinOnProfile ( ) : boolean {
const selectedAccount = this . toolsService . getSelectedAccounts ( ) [ 0 ] ;
this . getStatus ( selectedAccount )
. then ( ( status : Status ) = > {
return this . mastodonService . pinOnProfile ( selectedAccount , status . id )
} )
. then ( ( status : Status ) = > {
this . displayedStatus . pinned = status . pinned ;
} )
. catch ( err = > {
2019-09-07 23:52:07 +02:00
this . notificationService . notifyHttpError ( err , selectedAccount ) ;
2019-08-10 01:08:18 +02:00
} ) ;
return false ;
}
unpinFromProfile ( ) : boolean {
const selectedAccount = this . toolsService . getSelectedAccounts ( ) [ 0 ] ;
this . getStatus ( selectedAccount )
. then ( ( status : Status ) = > {
return this . mastodonService . unpinFromProfile ( selectedAccount , status . id )
} )
. then ( ( status : Status ) = > {
this . displayedStatus . pinned = status . pinned ;
} )
. catch ( err = > {
2019-09-07 23:52:07 +02:00
this . notificationService . notifyHttpError ( err , selectedAccount ) ;
2019-08-10 01:08:18 +02:00
} ) ;
return false ;
}
delete ( redraft : boolean ) : boolean {
const selectedAccount = this . toolsService . getSelectedAccounts ( ) [ 0 ] ;
this . getStatus ( selectedAccount )
. then ( ( status : Status ) = > {
return this . mastodonService . deleteStatus ( selectedAccount , status . id ) ;
} )
. then ( ( ) = > {
if ( redraft ) {
this . navigationService . redraft ( this . statusWrapper )
}
2020-04-01 08:29:51 +02:00
let cwPolicy = this . toolsService . checkContentWarning ( this . displayedStatus ) ;
const deletedStatus = new StatusWrapper ( cwPolicy . status , selectedAccount , cwPolicy . applyCw , cwPolicy . hide ) ;
2019-08-10 01:08:18 +02:00
this . notificationService . deleteStatus ( deletedStatus ) ;
} )
. catch ( err = > {
2019-09-07 23:52:07 +02:00
this . notificationService . notifyHttpError ( err , selectedAccount ) ;
2019-08-10 01:08:18 +02:00
} ) ;
return false ;
}
2022-11-19 18:16:31 +01:00
edit ( ) : boolean {
const selectedAccount = this . toolsService . getSelectedAccounts ( ) [ 0 ] ;
this . getStatus ( selectedAccount )
. then ( ( ) = > {
this . navigationService . edit ( this . statusWrapper ) ;
} )
. catch ( err = > {
this . notificationService . notifyHttpError ( err , selectedAccount ) ;
} ) ;
return false ;
}
2019-08-10 01:08:18 +02:00
private getStatus ( account : AccountInfo ) : Promise < Status > {
let statusPromise : Promise < Status > = Promise . resolve ( this . statusWrapper . status ) ;
2019-08-10 06:36:18 +02:00
2019-08-10 01:08:18 +02:00
if ( account . id !== this . statusWrapper . provider . id ) {
2019-09-25 06:09:10 +02:00
statusPromise =
this . toolsService . getInstanceInfo ( account )
. then ( instance = > {
let version : 'v1' | 'v2' = 'v1' ;
if ( instance . major >= 3 ) version = 'v2' ;
return this . mastodonService . search ( account , this . statusWrapper . status . url , version , true ) ;
} )
. then ( ( result : Results ) = > {
return result . statuses [ 0 ] ;
} ) ;
2019-08-10 01:08:18 +02:00
}
return statusPromise ;
}
}