added reply/dm capability

This commit is contained in:
Nicolas Constant 2019-07-03 19:55:33 -04:00
parent b2632e981d
commit a2e0789a9c
No known key found for this signature in database
GPG Key ID: 1E9F677FB01A5688
8 changed files with 126 additions and 40 deletions

View File

@ -4,7 +4,7 @@ import { debounceTime, map } from 'rxjs/operators';
import { Select } from '@ngxs/store'; import { Select } from '@ngxs/store';
// import { ElectronService } from 'ngx-electron'; // import { ElectronService } from 'ngx-electron';
import { NavigationService, LeftPanelType } from './services/navigation.service'; import { NavigationService, LeftPanelType, OpenLeftPanelEvent } from './services/navigation.service';
import { StreamElement } from './states/streams.state'; import { StreamElement } from './states/streams.state';
import { OpenMediaEvent } from './models/common.model'; import { OpenMediaEvent } from './models/common.model';
import { ToolsService } from './services/tools.service'; import { ToolsService } from './services/tools.service';
@ -44,8 +44,8 @@ export class AppComponent implements OnInit, OnDestroy {
} }
}); });
this.columnEditorSub = this.navigationService.activatedPanelSubject.subscribe((type: LeftPanelType) => { this.columnEditorSub = this.navigationService.activatedPanelSubject.subscribe((event: OpenLeftPanelEvent) => {
if (type === LeftPanelType.Closed) { if (event.type === LeftPanelType.Closed) {
this.floatingColumnActive = false; this.floatingColumnActive = false;
} else { } else {
this.floatingColumnActive = true; this.floatingColumnActive = true;

View File

@ -21,7 +21,7 @@ import { identifierModuleUrl } from '@angular/compiler';
}) })
export class CreateStatusComponent implements OnInit, OnDestroy { export class CreateStatusComponent implements OnInit, OnDestroy {
private _title: string; private _title: string;
set title(value: string){ set title(value: string) {
this._title = value; this._title = value;
this.countStatusChar(this.status); this.countStatusChar(this.status);
} }
@ -48,6 +48,26 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
@Output() onClose = new EventEmitter(); @Output() onClose = new EventEmitter();
@ViewChild('reply') replyElement: ElementRef; @ViewChild('reply') replyElement: ElementRef;
private _isDirectMention: boolean;
@Input('isDirectMention')
set isDirectMention(value: boolean) {
this._isDirectMention = value;
this.initMention();
}
get isDirectMention(): boolean {
return this._isDirectMention;
}
private _replyingUserHandle: string;
@Input('replyingUserHandle')
set replyingUserHandle(value: string) {
this._replyingUserHandle = value;
this.initMention();
}
get replyingUserHandle(): string {
return this._replyingUserHandle;
}
private statusReplyingTo: Status; private statusReplyingTo: Status;
selectedPrivacy = 'Public'; selectedPrivacy = 'Public';
@ -55,6 +75,7 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
private accounts$: Observable<AccountInfo[]>; private accounts$: Observable<AccountInfo[]>;
private accountSub: Subscription; private accountSub: Subscription;
private selectedAccount: AccountInfo;
constructor( constructor(
private readonly store: Store, private readonly store: Store,
@ -70,7 +91,8 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
this.accountSub = this.accounts$.subscribe((accounts: AccountInfo[]) => { this.accountSub = this.accounts$.subscribe((accounts: AccountInfo[]) => {
this.accountChanged(accounts); this.accountChanged(accounts);
}); });
this.selectedAccount = this.toolsService.getSelectedAccounts()[0];
if (this.statusReplyingToWrapper) { if (this.statusReplyingToWrapper) {
if (this.statusReplyingToWrapper.status.reblog) { if (this.statusReplyingToWrapper.status.reblog) {
this.statusReplyingTo = this.statusReplyingToWrapper.status.reblog; this.statusReplyingTo = this.statusReplyingToWrapper.status.reblog;
@ -99,27 +121,49 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
} }
this.title = this.statusReplyingTo.spoiler_text; this.title = this.statusReplyingTo.spoiler_text;
} else if (this.replyingUserHandle) {
this.initMention();
} }
setTimeout(() => { this.focus();
this.replyElement.nativeElement.focus();
}, 0);
} }
ngOnDestroy() { ngOnDestroy() {
this.accountSub.unsubscribe(); this.accountSub.unsubscribe();
} }
private focus() {
setTimeout(() => {
this.replyElement.nativeElement.focus();
}, 0);
}
private initMention() {
if (!this.selectedAccount) {
this.selectedAccount = this.toolsService.getSelectedAccounts()[0];
}
if (this.isDirectMention) {
this.setVisibility(VisibilityEnum.Direct);
} else {
this.getDefaultPrivacy();
}
this.status = `@${this.replyingUserHandle} `;
this.countStatusChar(this.status);
this.focus();
}
private accountChanged(accounts: AccountInfo[]): void { private accountChanged(accounts: AccountInfo[]): void {
if (accounts && accounts.length > 0) { if (accounts && accounts.length > 0) {
const selectedAccount = accounts.filter(x => x.isSelected)[0]; this.selectedAccount = accounts.filter(x => x.isSelected)[0];
const settings = this.toolsService.getAccountSettings(selectedAccount); const settings = this.toolsService.getAccountSettings(this.selectedAccount);
if (settings.customStatusCharLengthEnabled) { if (settings.customStatusCharLengthEnabled) {
this.maxCharLength = settings.customStatusCharLength; this.maxCharLength = settings.customStatusCharLength;
this.countStatusChar(this.status); this.countStatusChar(this.status);
} else { } else {
this.instancesInfoService.getMaxStatusChars(selectedAccount.instance) this.instancesInfoService.getMaxStatusChars(this.selectedAccount.instance)
.then((maxChars: number) => { .then((maxChars: number) => {
this.maxCharLength = maxChars; this.maxCharLength = maxChars;
this.countStatusChar(this.status); this.countStatusChar(this.status);
@ -129,18 +173,22 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
}); });
} }
if (!this.statusReplyingToWrapper) { if (!this.statusReplyingToWrapper && !this.replyingUserHandle) {
this.instancesInfoService.getDefaultPrivacy(selectedAccount) this.getDefaultPrivacy();
.then((defaultPrivacy: VisibilityEnum) => {
this.setVisibility(defaultPrivacy);
})
.catch((err: HttpErrorResponse) => {
this.notificationService.notifyHttpError(err);
});
} }
} }
} }
private getDefaultPrivacy() {
this.instancesInfoService.getDefaultPrivacy(this.selectedAccount)
.then((defaultPrivacy: VisibilityEnum) => {
this.setVisibility(defaultPrivacy);
})
.catch((err: HttpErrorResponse) => {
this.notificationService.notifyHttpError(err);
});
}
private setVisibility(defaultPrivacy: VisibilityEnum) { private setVisibility(defaultPrivacy: VisibilityEnum) {
switch (defaultPrivacy) { switch (defaultPrivacy) {
case VisibilityEnum.Public: case VisibilityEnum.Public:

View File

@ -1,5 +1,7 @@
<div class="panel"> <div class="panel">
<h3 class="panel__title">new message</h3> <h3 class="panel__title">new message</h3>
<app-create-status (onClose)="closeColumn()"></app-create-status> <app-create-status (onClose)="closeColumn()"
[isDirectMention]="isDirectMention"
[replyingUserHandle]="userHandle"></app-create-status>
</div> </div>

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, Input } from '@angular/core';
import { NavigationService } from '../../../services/navigation.service'; import { NavigationService } from '../../../services/navigation.service';
@ -8,10 +8,14 @@ import { NavigationService } from '../../../services/navigation.service';
styleUrls: ['./add-new-status.component.scss'] styleUrls: ['./add-new-status.component.scss']
}) })
export class AddNewStatusComponent implements OnInit { export class AddNewStatusComponent implements OnInit {
constructor(
private readonly navigationService: NavigationService) { }
ngOnInit() { @Input() isDirectMention: boolean;
@Input() userHandle: string;
constructor(private readonly navigationService: NavigationService) {
}
ngOnInit() {
} }
closeColumn() { closeColumn() {

View File

@ -15,7 +15,9 @@
(browseAccountEvent)="browseAccount($event)" (browseAccountEvent)="browseAccount($event)"
(browseHashtagEvent)="browseHashtag($event)" (browseHashtagEvent)="browseHashtag($event)"
(browseThreadEvent)="browseThread($event)"></app-manage-account> (browseThreadEvent)="browseThread($event)"></app-manage-account>
<app-add-new-status *ngIf="openPanel === 'createNewStatus'"></app-add-new-status> <app-add-new-status *ngIf="openPanel === 'createNewStatus'"
[isDirectMention]="isDirectMention"
[userHandle]="userHandle"></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'" <app-search *ngIf="openPanel === 'search'"
(browseAccountEvent)="browseAccount($event)" (browseAccountEvent)="browseAccount($event)"

View File

@ -1,7 +1,7 @@
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { faTimes } from "@fortawesome/free-solid-svg-icons"; import { faTimes } from "@fortawesome/free-solid-svg-icons";
import { NavigationService, LeftPanelType } from '../../services/navigation.service'; import { NavigationService, LeftPanelType, OpenLeftPanelEvent, LeftPanelAction } from '../../services/navigation.service';
import { AccountWrapper } from '../../models/account.models'; import { AccountWrapper } from '../../models/account.models';
import { OpenThreadEvent } from '../../services/tools.service'; import { OpenThreadEvent } from '../../services/tools.service';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
@ -21,6 +21,9 @@ export class FloatingColumnComponent implements OnInit, OnDestroy {
userAccountUsed: AccountWrapper; userAccountUsed: AccountWrapper;
isDirectMention: boolean;
userHandle: string;
openPanel: string = ''; openPanel: string = '';
private activatedPanelSub: Subscription; private activatedPanelSub: Subscription;
@ -28,9 +31,11 @@ export class FloatingColumnComponent implements OnInit, OnDestroy {
constructor(private readonly navigationService: NavigationService) { } constructor(private readonly navigationService: NavigationService) { }
ngOnInit() { ngOnInit() {
this.activatedPanelSub = this.navigationService.activatedPanelSubject.subscribe((type: LeftPanelType) => { this.activatedPanelSub = this.navigationService.activatedPanelSubject.subscribe((event: OpenLeftPanelEvent) => {
this.isDirectMention = false;
this.userHandle = null;
this.overlayActive = false; this.overlayActive = false;
switch (type) { switch (event.type) {
case LeftPanelType.Closed: case LeftPanelType.Closed:
this.openPanel = ''; this.openPanel = '';
break; break;
@ -42,9 +47,11 @@ export class FloatingColumnComponent implements OnInit, OnDestroy {
} }
break; break;
case LeftPanelType.CreateNewStatus: case LeftPanelType.CreateNewStatus:
if (this.openPanel === 'createNewStatus') { if (this.openPanel === 'createNewStatus' && !event.userHandle) {
this.closePanel(); this.closePanel();
} else { } else {
this.isDirectMention = event.action === LeftPanelAction.DM;
this.userHandle = event.userHandle;
this.openPanel = 'createNewStatus'; this.openPanel = 'createNewStatus';
} }
break; break;

View File

@ -4,6 +4,7 @@ import { Store } from '@ngxs/store';
import { Observable, Subscription } from 'rxjs'; import { Observable, Subscription } from 'rxjs';
import { faWindowClose, faReply, faRetweet, faStar, faEllipsisH, faLock } from "@fortawesome/free-solid-svg-icons"; import { faWindowClose, faReply, faRetweet, faStar, faEllipsisH, faLock } 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 { ContextMenuComponent, ContextMenuService } from 'ngx-contextmenu';
import { MastodonService } from '../../../../services/mastodon.service'; import { MastodonService } from '../../../../services/mastodon.service';
import { AccountInfo } from '../../../../states/accounts.state'; import { AccountInfo } from '../../../../states/accounts.state';
@ -11,8 +12,7 @@ import { Status, Account } from '../../../../services/models/mastodon.interfaces
import { ToolsService } from '../../../../services/tools.service'; import { ToolsService } 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 { NavigationService } from '../../../../services/navigation.service';
import { ContextMenuComponent, ContextMenuService } from 'ngx-contextmenu';
@Component({ @Component({
selector: 'app-action-bar', selector: 'app-action-bar',
@ -59,7 +59,8 @@ export class ActionBarComponent implements OnInit, OnDestroy {
private accountSub: Subscription; private accountSub: Subscription;
constructor( constructor(
private contextMenuService: ContextMenuService, private readonly navigationService: NavigationService,
private readonly contextMenuService: ContextMenuService,
private readonly store: Store, private readonly store: Store,
private readonly toolsService: ToolsService, private readonly toolsService: ToolsService,
private readonly mastodonService: MastodonService, private readonly mastodonService: MastodonService,
@ -97,7 +98,7 @@ export class ActionBarComponent implements OnInit, OnDestroy {
private extractHandle(account: Account) { private extractHandle(account: Account) {
this.username = account.acct.split('@')[0]; this.username = account.acct.split('@')[0];
this.fullHandle = account.acct; this.fullHandle = account.acct.toLowerCase();
if (!this.fullHandle.includes('@')) { if (!this.fullHandle.includes('@')) {
this.fullHandle += `@${account.url.replace('https://', '').split('/')[0]}`; this.fullHandle += `@${account.url.replace('https://', '').split('/')[0]}`;
} }
@ -273,13 +274,12 @@ export class ActionBarComponent implements OnInit, OnDestroy {
} }
mentionAccount(): boolean { mentionAccount(): boolean {
this.navigationService.replyToUser(this.fullHandle, false);
return false; return false;
} }
dmAccount(): boolean { dmAccount(): boolean {
this.navigationService.replyToUser(this.fullHandle, true);
return false; return false;
} }

View File

@ -7,7 +7,7 @@ import { OpenMediaEvent } from '../models/common.model';
@Injectable() @Injectable()
export class NavigationService { export class NavigationService {
private accountToManage: AccountWrapper; private accountToManage: AccountWrapper;
activatedPanelSubject = new BehaviorSubject<LeftPanelType>(LeftPanelType.Closed); activatedPanelSubject = new BehaviorSubject<OpenLeftPanelEvent>(new OpenLeftPanelEvent(LeftPanelType.Closed));
activatedMediaSubject: Subject<OpenMediaEvent> = new Subject<OpenMediaEvent>(); activatedMediaSubject: Subject<OpenMediaEvent> = new Subject<OpenMediaEvent>();
columnSelectedSubject = new BehaviorSubject<number>(-1); columnSelectedSubject = new BehaviorSubject<number>(-1);
@ -15,18 +15,27 @@ export class NavigationService {
openColumnEditor(acc: AccountWrapper) { openColumnEditor(acc: AccountWrapper) {
this.accountToManage = acc; this.accountToManage = acc;
this.activatedPanelSubject.next(LeftPanelType.ManageAccount); const newEvent = new OpenLeftPanelEvent(LeftPanelType.ManageAccount);
this.activatedPanelSubject.next(newEvent);
} }
openPanel(type: LeftPanelType){ openPanel(type: LeftPanelType){
this.activatedPanelSubject.next(type); const newEvent = new OpenLeftPanelEvent(type);
this.activatedPanelSubject.next(newEvent);
} }
closePanel() { closePanel() {
this.activatedPanelSubject.next(LeftPanelType.Closed); const newEvent = new OpenLeftPanelEvent(LeftPanelType.Closed);
this.activatedPanelSubject.next(newEvent);
this.accountToManage = null; this.accountToManage = null;
} }
replyToUser(userHandle: string, isDirectMessage: boolean = false) {
const action = isDirectMessage ? LeftPanelAction.DM : LeftPanelAction.Mention;
const newEvent = new OpenLeftPanelEvent(LeftPanelType.CreateNewStatus, action, userHandle);
this.activatedPanelSubject.next(newEvent);
}
columnSelected(index: number): void { columnSelected(index: number): void {
this.columnSelectedSubject.next(index); this.columnSelectedSubject.next(index);
} }
@ -40,6 +49,20 @@ export class NavigationService {
} }
} }
export class OpenLeftPanelEvent {
constructor(
public type: LeftPanelType,
public action: LeftPanelAction = LeftPanelAction.None,
public userHandle: string = null ) {
}
}
export enum LeftPanelAction {
None = 0,
DM = 1,
Mention = 2
}
export enum LeftPanelType { export enum LeftPanelType {
Closed = 0, Closed = 0,
ManageAccount = 1, ManageAccount = 1,