Merge pull request #144 from NicolasConstant/topic_emoji-picker

Topic emoji picker
This commit is contained in:
Nicolas Constant 2019-07-29 22:19:41 -04:00 committed by GitHub
commit 72cf69d9c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 87 additions and 24 deletions

View File

@ -1,8 +1,5 @@
<emoji-mart <emoji-mart
[showPreview]="false" *ngIf="loaded"
[perLine]="7" [showPreview]="false" [perLine]="7" [isNative]="true" [sheetSize]="16" [emojiTooltip]="true"
[isNative]="true" [custom]="customEmojis" (emojiSelect)="emojiSelected($event)" class="emojipicker" title="Pick your emoji…"
[sheetSize]="16" emoji="point_up"></emoji-mart>
[emojiTooltip]="true"
(emojiSelect)="emojiSelected($event)"
class="emojipicker" title="Pick your emoji…" emoji="point_up"></emoji-mart>

View File

@ -14,3 +14,9 @@
font-size: 19px !important; font-size: 19px !important;
cursor: pointer !important; cursor: pointer !important;
} }
::ng-deep .emoji-mart-emoji-custom span {
position: relative;
top: 0px;
left: 0px;
}

View File

@ -1,5 +1,9 @@
import { Component, OnInit, HostListener, ElementRef, Output, EventEmitter } from '@angular/core'; import { Component, OnInit, HostListener, ElementRef, Output, EventEmitter } from '@angular/core';
import { ToolsService } from '../../../services/tools.service';
import { NotificationService } from '../../../services/notification.service';
import { Emoji } from '../../../services/models/mastodon.interfaces';
@Component({ @Component({
selector: 'app-emoji-picker', selector: 'app-emoji-picker',
templateUrl: './emoji-picker.component.html', templateUrl: './emoji-picker.component.html',
@ -11,7 +15,13 @@ export class EmojiPickerComponent implements OnInit {
@Output('closed') public closedEvent = new EventEmitter(); @Output('closed') public closedEvent = new EventEmitter();
@Output('emojiSelected') public emojiSelectedEvent = new EventEmitter<string>(); @Output('emojiSelected') public emojiSelectedEvent = new EventEmitter<string>();
constructor(private eRef: ElementRef) { } customEmojis: PickerCustomEmoji[] = [];
loaded: boolean;
constructor(
private notificationService: NotificationService,
private toolsService: ToolsService,
private eRef: ElementRef) { }
@HostListener('document:click', ['$event']) @HostListener('document:click', ['$event'])
clickout(event) { clickout(event) {
@ -23,13 +33,44 @@ export class EmojiPickerComponent implements OnInit {
} }
ngOnInit() { ngOnInit() {
let currentAccount = this.toolsService.getSelectedAccounts()[0];
this.toolsService.getCustomEmojis(currentAccount)
.then(emojis => {
console.warn(emojis);
this.customEmojis = emojis.map(x => this.convertEmoji(x));
})
.catch(err => {
this.notificationService.notifyHttpError(err);
})
.then(() => {
this.loaded = true;
});
setTimeout(() => { setTimeout(() => {
this.init = true; this.init = true;
}, 0); }, 0);
} }
private convertEmoji(emoji: Emoji): PickerCustomEmoji {
return new PickerCustomEmoji(emoji.shortcode, [emoji.shortcode], emoji.shortcode, [emoji.shortcode], emoji.url);
}
emojiSelected(select: any): boolean { emojiSelected(select: any): boolean {
if (select.emoji.custom) {
this.emojiSelectedEvent.next(select.emoji.colons);
} else {
this.emojiSelectedEvent.next(select.emoji.native); this.emojiSelectedEvent.next(select.emoji.native);
}
return false; return false;
} }
} }
class PickerCustomEmoji {
constructor(
public name: string,
public shortNames: string[],
public text: string,
public keywords: string[],
public imageUrl: string) {
}
}

View File

@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { HttpHeaders, HttpClient, HttpResponse } from '@angular/common/http'; import { HttpHeaders, HttpClient, HttpResponse } from '@angular/common/http';
import { ApiRoutes } from './models/api.settings'; import { ApiRoutes } from './models/api.settings';
import { Account, Status, Results, Context, Relationship, Instance, Attachment, Notification, List, Poll } from "./models/mastodon.interfaces"; import { Account, Status, Results, Context, Relationship, Instance, Attachment, Notification, List, Poll, Emoji } from "./models/mastodon.interfaces";
import { AccountInfo } from '../states/accounts.state'; import { AccountInfo } from '../states/accounts.state';
import { StreamTypeEnum, StreamElement } from '../states/streams.state'; import { StreamTypeEnum, StreamElement } from '../states/streams.state';
@ -368,6 +368,11 @@ export class MastodonService {
const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}` }); const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}` });
return this.httpClient.delete<any>(route, { headers: headers }).toPromise(); return this.httpClient.delete<any>(route, { headers: headers }).toPromise();
} }
getCustomEmojis(account: AccountInfo): Promise<Emoji[]> {
let route = `https://${account.instance}${this.apiRoutes.getCustomEmojis}`;
return this.httpClient.get<Emoji[]>(route).toPromise();
}
} }
export enum VisibilityEnum { export enum VisibilityEnum {

View File

@ -3,6 +3,7 @@ export class ApiRoutes {
createApp = '/api/v1/apps'; createApp = '/api/v1/apps';
getToken = '/oauth/token'; getToken = '/oauth/token';
getAccount = '/api/v1/accounts/{0}'; getAccount = '/api/v1/accounts/{0}';
getCustomEmojis = '/api/v1/custom_emojis';
getCurrentAccount = '/api/v1/accounts/verify_credentials'; getCurrentAccount = '/api/v1/accounts/verify_credentials';
getAccountFollowers = '/api/v1/accounts/{0}/followers'; getAccountFollowers = '/api/v1/accounts/{0}/followers';
getAccountFollowing = '/api/v1/accounts/{0}/following'; getAccountFollowing = '/api/v1/accounts/{0}/following';

View File

@ -3,7 +3,7 @@ import { Store } from '@ngxs/store';
import { AccountInfo } from '../states/accounts.state'; import { AccountInfo } from '../states/accounts.state';
import { MastodonService } from './mastodon.service'; import { MastodonService } from './mastodon.service';
import { Account, Results, Status } from "./models/mastodon.interfaces"; import { Account, Results, Status, Emoji } from "./models/mastodon.interfaces";
import { StatusWrapper } from '../models/common.model'; import { StatusWrapper } from '../models/common.model';
import { AccountSettings, SaveAccountSettings } from '../states/settings.state'; import { AccountSettings, SaveAccountSettings } from '../states/settings.state';
@ -24,19 +24,19 @@ export class ToolsService {
getAccountSettings(account: AccountInfo): AccountSettings { getAccountSettings(account: AccountInfo): AccountSettings {
var accountsSettings = <AccountSettings[]>this.store.snapshot().globalsettings.settings.accountSettings; var accountsSettings = <AccountSettings[]>this.store.snapshot().globalsettings.settings.accountSettings;
let accountSettings = accountsSettings.find(x => x.accountId === account.id); let accountSettings = accountsSettings.find(x => x.accountId === account.id);
if(!accountSettings){ if (!accountSettings) {
accountSettings = new AccountSettings(); accountSettings = new AccountSettings();
accountSettings.accountId = account.id; accountSettings.accountId = account.id;
this.saveAccountSettings(accountSettings); this.saveAccountSettings(accountSettings);
} }
if(!accountSettings.customStatusCharLength){ if (!accountSettings.customStatusCharLength) {
accountSettings.customStatusCharLength = 500; accountSettings.customStatusCharLength = 500;
this.saveAccountSettings(accountSettings); this.saveAccountSettings(accountSettings);
} }
return accountSettings; return accountSettings;
} }
saveAccountSettings(accountSettings: AccountSettings){ saveAccountSettings(accountSettings: AccountSettings) {
this.store.dispatch([ this.store.dispatch([
new SaveAccountSettings(accountSettings) new SaveAccountSettings(accountSettings)
]) ])
@ -45,7 +45,7 @@ export class ToolsService {
findAccount(account: AccountInfo, accountName: string): Promise<Account> { findAccount(account: AccountInfo, accountName: string): Promise<Account> {
return this.mastodonService.search(account, accountName, true) return this.mastodonService.search(account, accountName, true)
.then((result: Results) => { .then((result: Results) => {
if(accountName[0] === '@') accountName = accountName.substr(1); if (accountName[0] === '@') accountName = accountName.substr(1);
const foundAccount = result.accounts.find( const foundAccount = result.accounts.find(
x => (x.acct.toLowerCase() === accountName.toLowerCase() x => (x.acct.toLowerCase() === accountName.toLowerCase()
@ -57,7 +57,7 @@ export class ToolsService {
}); });
} }
getStatusUsableByAccount(account: AccountInfo, originalStatus: StatusWrapper): Promise<Status>{ getStatusUsableByAccount(account: AccountInfo, originalStatus: StatusWrapper): Promise<Status> {
const isProvider = originalStatus.provider.id === account.id; const isProvider = originalStatus.provider.id === account.id;
let statusPromise: Promise<Status> = Promise.resolve(originalStatus.status); let statusPromise: Promise<Status> = Promise.resolve(originalStatus.status);
@ -82,6 +82,19 @@ export class ToolsService {
} }
return `@${fullHandle}`; return `@${fullHandle}`;
} }
private emojiCache: { [id: string]: Emoji[] } = {};
getCustomEmojis(account: AccountInfo): Promise<Emoji[]> {
if (this.emojiCache[account.id]) {
return Promise.resolve(this.emojiCache[account.id]);
} else {
return this.mastodonService.getCustomEmojis(account)
.then(emojis => {
this.emojiCache[account.id] = emojis.filter(x => x.visible_in_picker);
return this.emojiCache[account.id];
});
}
}
} }
export class OpenThreadEvent { export class OpenThreadEvent {