mattermost-mobile/app/utils/emoji/helpers.ts
Avinash Lingaloo 7f91a6a78a
Gekidou - Account Screen (#5708)
* Added DrawerItem component

* WIP Account Screen

* Added react-native-paper

* Added StatusLabel Component

* Extracted i18n

* TS fix DrawerItem component

* WIP Account Screen

* Added server name label under log out

* Updated translation

* WIP

* Fixes the Offline text style

* Added Metropolis fonts

* WIP

* Typo clean up

* WIP

* WIP

* WIP

* Added server display name

* Writing OpenSans properly

* WIP

* WIP

* Added OptionsModal

* Opening OptionsModal

* Added translation keys

* Writes status to local db

* Fix missing translation

* Fix OptionModal not dismissing

* Pushing status to server

* Refactored

* Added CustomStatusExpiry component

* Added sub components

* Added CustomLabel

* CustomStatus WIP

* Added Custom Status screen WIP

* WIP - unsetCustomStatus and CustomStatus constant

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* Retrieving RecentCustomStatuses from Preferences table

* WIP

* WIP

* WIP

* Added Clear After Modal

* WIP - Transations

* WIP

* Done with showing modal cst

* wip

* Clear After Modal - DONE

* fix

* Added missing API calls

* wip

* Causing screen refresh

* wip

* WIP

* WIP

* WIP

* Code clean up

* Added OOO alert box

* Refactored Options-Item

* Refactored OptionsModalList component

* Opening 'status' in BottomSheet instead of OptionsModal

* AddReaction screen - WIP

* Add Reaction screen - WIP

* Added EmojiPickerRow

* Added @components/emoji_picker - WIP

* Emoji Picker - WIP

* WIP

* WIP

* WIP

* SectionList - WIP

* Installed react-native-section_list_get_item_layout

* Adding API calls - WIP

* WIP

* Search Bar component - WIP

* WIP

* WIP

* WIP

* Rendering Emoticons now - have to tackle some fixmes

* Code clean up

* Code clean up - WIP

* Code clean up

* WIP

* Major clean up

* wip

* WIP

* Fix rendering issue with SectionIcons and SearchBar

* Tackled the CustomEmojiPage

* Code clean up

* WIP

* Done with loading User Profiles for Custom Emoji

* Code clean up

* Code Clean up

* Fix screen Account

* Added missing sql file for IOS Pod

* Updated Podfile.lock

* Using queryConfig instead of queryCommonSystemValues

* Fix - Custom status

* Fix - Custom Status - Error

* Fix - Clear Pass Status - WIP

* Fix - Custom Status Clear

* Need to fix CST clear

* WIP

* Status clear - working

* Using catchError operator

* remove unnecessary prop

* Status  BottomSheet now has colored indicators

* Added KeyboardTrackingView from 'react-native-keyboard-tracking-view'

* Code clean up

* WIP

* code clean up

* Added a safety check

* Fix - Display suggestions

* Code clean up based on PR Review

* Code clean up

* Code clean up

* Code clean up

* Corrections

* Fix tsc

* TS fix

* Removed unnecessary prop

* Fix SearchBar Ts

* Updated tests

* Delete search_bar.test.js.snap

* Merge branch 'gekidou' into gekidou_account_screen

* Revert "Merge branch 'gekidou' into gekidou_account_screen"

This reverts commit 5defc313212478a55abf2f92cb4bd64dc7877342.

* Fix fonts

* Refactor home account screen

* fix theme provider

* refactor bottom sheet

* remove paper provider

* update drawer item snapshots

* Remove options modal screen

* remove react-native-ui-lib dependency

* Refactor & fix custom status & navigation (including tablet)

* Refactor emoji picker

Co-authored-by: Avinash Lingaloo <>
Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
2021-10-12 19:24:24 +04:00

219 lines
6.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import emojiRegex from 'emoji-regex';
import SystemModel from '@database/models/server/system';
import {Emojis, EmojiIndicesByAlias} from './';
const RE_NAMED_EMOJI = /(:([a-zA-Z0-9_+-]+):)/g;
const RE_UNICODE_EMOJI = emojiRegex();
const RE_EMOTICON: Record<string, RegExp> = {
slightly_smiling_face: /(^|\s)(:-?\))(?=$|\s)/g, // :)
wink: /(^|\s)(;-?\))(?=$|\s)/g, // ;)
open_mouth: /(^|\s)(:o)(?=$|\s)/gi, // :o
scream: /(^|\s)(:-o)(?=$|\s)/gi, // :-o
smirk: /(^|\s)(:-?])(?=$|\s)/g, // :]
smile: /(^|\s)(:-?d)(?=$|\s)/gi, // :D
stuck_out_tongue_closed_eyes: /(^|\s)(x-d)(?=$|\s)/gi, // x-d
stuck_out_tongue: /(^|\s)(:-?p)(?=$|\s)/gi, // :p
rage: /(^|\s)(:-?[[@])(?=$|\s)/g, // :@
slightly_frowning_face: /(^|\s)(:-?\()(?=$|\s)/g, // :(
cry: /(^|\s)(:[`']-?\(|:&#x27;\(|:&#39;\()(?=$|\s)/g, // :`(
confused: /(^|\s)(:-?\/)(?=$|\s)/g, // :/
confounded: /(^|\s)(:-?s)(?=$|\s)/gi, // :s
neutral_face: /(^|\s)(:-?\|)(?=$|\s)/g, // :|
flushed: /(^|\s)(:-?\$)(?=$|\s)/g, // :$
mask: /(^|\s)(:-x)(?=$|\s)/gi, // :-x
heart: /(^|\s)(<3|&lt;3)(?=$|\s)/g, // <3
broken_heart: /(^|\s)(<\/3|&lt;&#x2F;3)(?=$|\s)/g, // </3
};
const MAX_JUMBO_EMOJIS = 4;
function isEmoticon(text: string) {
for (const emoticon of Object.keys(RE_EMOTICON)) {
const reEmoticon = RE_EMOTICON[emoticon];
const matchEmoticon = text.match(reEmoticon);
if (matchEmoticon && matchEmoticon[0] === text) {
return true;
}
}
return false;
}
export function getEmoticonName(value: string) {
return Object.keys(RE_EMOTICON).find((key) => value.match(RE_EMOTICON[key]) !== null);
}
export function hasJumboEmojiOnly(message: string, customEmojis: string[]) {
let emojiCount = 0;
const chunks = message.trim().replace(/\n/g, ' ').split(' ').filter((m) => m && m.length > 0);
if (chunks.length === 0) {
return false;
}
for (const chunk of chunks) {
if (doesMatchNamedEmoji(chunk)) {
const emojiName = chunk.substring(1, chunk.length - 1);
if (EmojiIndicesByAlias.has(emojiName)) {
emojiCount++;
continue;
}
if (customEmojis && customEmojis.includes(emojiName)) {
emojiCount++;
continue;
}
}
const matchUnicodeEmoji = chunk.match(RE_UNICODE_EMOJI);
if (matchUnicodeEmoji && matchUnicodeEmoji.join('') === chunk) {
emojiCount += matchUnicodeEmoji.length;
continue;
}
if (isEmoticon(chunk)) {
emojiCount++;
continue;
}
return false;
}
return emojiCount > 0 && emojiCount <= MAX_JUMBO_EMOJIS;
}
export function doesMatchNamedEmoji(emojiName: string) {
const match = emojiName.match(RE_NAMED_EMOJI);
if (match && match[0] === emojiName) {
return true;
}
return false;
}
export function getEmojiByName(emojiName: string) {
if (EmojiIndicesByAlias.has(emojiName)) {
return Emojis[EmojiIndicesByAlias.get(emojiName)!];
}
return null;
}
// Since there is no shared logic between the web and mobile app
// this is copied from the webapp as custom sorting logic for emojis
const defaultComparisonRule = (aName: string, bName: string) => {
return aName.localeCompare(bName);
};
const thumbsDownComparisonRule = (other: string) => (other.startsWith('thumbsup') || other.startsWith('+1') ? 1 : 0);
const thumbsUpComparisonRule = (other: string) => (other.startsWith('thumbsdown') || other.startsWith('-1') ? -1 : 0);
type Comparators = Record<string, ((other: string) => number)>;
const customComparisonRules: Comparators = {
thumbsdown: thumbsDownComparisonRule,
'-1': thumbsDownComparisonRule,
thumbsup: thumbsUpComparisonRule,
'+1': thumbsUpComparisonRule,
};
function doDefaultComparison(aName: string, bName: string) {
const rule = aName.split('_')[0];
if (customComparisonRules[rule]) {
return customComparisonRules[rule](bName) || defaultComparisonRule(aName, bName);
}
return defaultComparisonRule(aName, bName);
}
type EmojiType = {
short_name: string;
name: string;
}
export function compareEmojis(emojiA: string | Partial<EmojiType>, emojiB: string | Partial<EmojiType>, searchedName: string) {
if (!emojiA) {
return 1;
}
if (!emojiB) {
return -1;
}
let aName;
if (typeof emojiA === 'string') {
aName = emojiA;
} else {
aName = 'short_name' in emojiA ? emojiA.short_name : emojiA.name;
}
let bName;
if (typeof emojiB === 'string') {
bName = emojiB;
} else {
bName = 'short_name' in emojiB ? emojiB.short_name : emojiB.name;
}
if (!searchedName) {
return doDefaultComparison(aName!, bName!);
}
// Have the emojis that start with the search appear first
const aPrefix = aName!.startsWith(searchedName);
const bPrefix = bName!.startsWith(searchedName);
if (aPrefix && bPrefix) {
return doDefaultComparison(aName!, bName!);
} else if (aPrefix) {
return -1;
} else if (bPrefix) {
return 1;
}
// Have the emojis that contain the search appear next
const aIncludes = aName!.includes(searchedName);
const bIncludes = bName!.includes(searchedName);
if (aIncludes && bIncludes) {
return doDefaultComparison(aName!, bName!);
} else if (aIncludes) {
return -1;
} else if (bIncludes) {
return 1;
}
return doDefaultComparison(aName!, bName!);
}
export const isCustomEmojiEnabled = (config: ClientConfig | SystemModel) => {
if (config instanceof SystemModel) {
return config?.value?.EnableCustomEmoji === 'true';
}
return config?.EnableCustomEmoji === 'true';
};
export function fillEmoji(index: number) {
const emoji = Emojis[index];
return {
name: 'short_name' in emoji ? emoji.short_name : emoji.name,
aliases: 'short_names' in emoji ? emoji.short_names : [],
};
}
export function getSkin(emoji: any) {
if ('skin_variations' in emoji) {
return 'default';
}
if ('skins' in emoji) {
return emoji.skins && emoji.skins[0];
}
return null;
}