Update custom emojis endpoint (#852)
* Update emoji endpoint * Use React.memo on Markdown * Support RC versions lower than 0.75.0 * Realm migration
This commit is contained in:
parent
c340829638
commit
5c1be71fa1
|
@ -14,98 +14,90 @@ const formatText = text => text.replace(
|
|||
(match, url, title) => `[${ title }](${ url })`
|
||||
);
|
||||
|
||||
export default class Markdown extends React.Component {
|
||||
shouldComponentUpdate(nextProps) {
|
||||
const { msg } = this.props;
|
||||
return nextProps.msg !== msg;
|
||||
const Markdown = React.memo(({
|
||||
msg, customEmojis, style, rules, baseUrl, username, edited, numberOfLines
|
||||
}) => {
|
||||
if (!msg) {
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
msg, customEmojis, style, rules, baseUrl, username, edited, numberOfLines
|
||||
} = this.props;
|
||||
if (!msg) {
|
||||
return null;
|
||||
}
|
||||
let m = formatText(msg);
|
||||
if (m) {
|
||||
m = emojify(m, { output: 'unicode' });
|
||||
}
|
||||
m = m.replace(/^\[([^\]]*)\]\(([^)]*)\)/, '').trim();
|
||||
if (numberOfLines > 0) {
|
||||
m = m.replace(/[\n]+/g, '\n').trim();
|
||||
}
|
||||
return (
|
||||
<MarkdownRenderer
|
||||
rules={{
|
||||
paragraph: (node, children) => (
|
||||
// eslint-disable-next-line
|
||||
<Text key={node.key} style={styles.paragraph} numberOfLines={numberOfLines}>
|
||||
{children}
|
||||
{edited ? <Text style={styles.edited}> (edited)</Text> : null}
|
||||
</Text>
|
||||
),
|
||||
mention: (node) => {
|
||||
const { content, key } = node;
|
||||
let mentionStyle = styles.mention;
|
||||
if (content === 'all' || content === 'here') {
|
||||
mentionStyle = {
|
||||
...mentionStyle,
|
||||
...styles.mentionAll
|
||||
};
|
||||
} else if (content === username) {
|
||||
mentionStyle = {
|
||||
...mentionStyle,
|
||||
...styles.mentionLoggedUser
|
||||
};
|
||||
}
|
||||
return (
|
||||
<Text style={mentionStyle} key={key}>
|
||||
{content}
|
||||
</Text>
|
||||
);
|
||||
},
|
||||
hashtag: node => (
|
||||
<Text key={node.key} style={styles.mention}>
|
||||
#{node.content}
|
||||
</Text>
|
||||
),
|
||||
emoji: (node) => {
|
||||
if (node.children && node.children.length && node.children[0].content) {
|
||||
const { content } = node.children[0];
|
||||
const emojiExtension = customEmojis[content];
|
||||
if (emojiExtension) {
|
||||
const emoji = { extension: emojiExtension, content };
|
||||
return <CustomEmoji key={node.key} baseUrl={baseUrl} style={styles.customEmoji} emoji={emoji} />;
|
||||
}
|
||||
return <Text key={node.key}>:{content}:</Text>;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
hardbreak: () => null,
|
||||
blocklink: () => null,
|
||||
image: node => (
|
||||
<Image key={node.key} style={styles.inlineImage} source={{ uri: node.attributes.src }} />
|
||||
),
|
||||
...rules
|
||||
}}
|
||||
style={{
|
||||
paragraph: styles.paragraph,
|
||||
text: styles.text,
|
||||
codeInline: styles.codeInline,
|
||||
codeBlock: styles.codeBlock,
|
||||
link: styles.link,
|
||||
...style
|
||||
}}
|
||||
plugins={[
|
||||
new PluginContainer(MarkdownFlowdock),
|
||||
new PluginContainer(MarkdownEmojiPlugin)
|
||||
]}
|
||||
>{m}
|
||||
</MarkdownRenderer>
|
||||
);
|
||||
let m = formatText(msg);
|
||||
if (m) {
|
||||
m = emojify(m, { output: 'unicode' });
|
||||
}
|
||||
}
|
||||
m = m.replace(/^\[([^\]]*)\]\(([^)]*)\)/, '').trim();
|
||||
if (numberOfLines > 0) {
|
||||
m = m.replace(/[\n]+/g, '\n').trim();
|
||||
}
|
||||
return (
|
||||
<MarkdownRenderer
|
||||
rules={{
|
||||
paragraph: (node, children) => (
|
||||
// eslint-disable-next-line
|
||||
<Text key={node.key} style={styles.paragraph} numberOfLines={numberOfLines}>
|
||||
{children}
|
||||
{edited ? <Text style={styles.edited}> (edited)</Text> : null}
|
||||
</Text>
|
||||
),
|
||||
mention: (node) => {
|
||||
const { content, key } = node;
|
||||
let mentionStyle = styles.mention;
|
||||
if (content === 'all' || content === 'here') {
|
||||
mentionStyle = {
|
||||
...mentionStyle,
|
||||
...styles.mentionAll
|
||||
};
|
||||
} else if (content === username) {
|
||||
mentionStyle = {
|
||||
...mentionStyle,
|
||||
...styles.mentionLoggedUser
|
||||
};
|
||||
}
|
||||
return (
|
||||
<Text style={mentionStyle} key={key}>
|
||||
{content}
|
||||
</Text>
|
||||
);
|
||||
},
|
||||
hashtag: node => (
|
||||
<Text key={node.key} style={styles.mention}>
|
||||
#{node.content}
|
||||
</Text>
|
||||
),
|
||||
emoji: (node) => {
|
||||
if (node.children && node.children.length && node.children[0].content) {
|
||||
const { content } = node.children[0];
|
||||
const emojiExtension = customEmojis[content];
|
||||
if (emojiExtension) {
|
||||
const emoji = { extension: emojiExtension, content };
|
||||
return <CustomEmoji key={node.key} baseUrl={baseUrl} style={styles.customEmoji} emoji={emoji} />;
|
||||
}
|
||||
return <Text key={node.key}>:{content}:</Text>;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
hardbreak: () => null,
|
||||
blocklink: () => null,
|
||||
image: node => (
|
||||
<Image key={node.key} style={styles.inlineImage} source={{ uri: node.attributes.src }} />
|
||||
),
|
||||
...rules
|
||||
}}
|
||||
style={{
|
||||
paragraph: styles.paragraph,
|
||||
text: styles.text,
|
||||
codeInline: styles.codeInline,
|
||||
codeBlock: styles.codeBlock,
|
||||
link: styles.link,
|
||||
...style
|
||||
}}
|
||||
plugins={[
|
||||
new PluginContainer(MarkdownFlowdock),
|
||||
new PluginContainer(MarkdownEmojiPlugin)
|
||||
]}
|
||||
>{m}
|
||||
</MarkdownRenderer>
|
||||
);
|
||||
}, (prevProps, nextProps) => prevProps.msg === nextProps.msg);
|
||||
|
||||
Markdown.propTypes = {
|
||||
msg: PropTypes.string,
|
||||
|
@ -117,3 +109,5 @@ Markdown.propTypes = {
|
|||
edited: PropTypes.bool,
|
||||
numberOfLines: PropTypes.number
|
||||
};
|
||||
|
||||
export default Markdown;
|
||||
|
|
|
@ -1,39 +1,83 @@
|
|||
import { InteractionManager } from 'react-native';
|
||||
import semver from 'semver';
|
||||
|
||||
import reduxStore from '../createStore';
|
||||
import database from '../realm';
|
||||
import * as actions from '../../actions';
|
||||
import log from '../../utils/log';
|
||||
|
||||
const getLastMessage = () => {
|
||||
const setting = database.objects('customEmojis').sorted('_updatedAt', true)[0];
|
||||
return setting && setting._updatedAt;
|
||||
const getUpdatedSince = () => {
|
||||
const emoji = database.objects('customEmojis').sorted('_updatedAt', true)[0];
|
||||
return emoji && emoji._updatedAt.toISOString();
|
||||
};
|
||||
|
||||
// TODO: fix api (get emojis by date/version....)
|
||||
const create = (customEmojis) => {
|
||||
if (customEmojis && customEmojis.length) {
|
||||
customEmojis.forEach((emoji) => {
|
||||
try {
|
||||
database.create('customEmojis', emoji, true);
|
||||
} catch (e) {
|
||||
log('getEmojis create', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export default async function() {
|
||||
try {
|
||||
const lastMessage = getLastMessage();
|
||||
// RC 0.61.0
|
||||
const result = await this.sdk.get('emoji-custom');
|
||||
let { emojis } = result;
|
||||
emojis = emojis.filter(emoji => !lastMessage || emoji._updatedAt > lastMessage);
|
||||
if (emojis.length === 0) {
|
||||
return;
|
||||
}
|
||||
emojis = this._prepareEmojis(emojis);
|
||||
InteractionManager.runAfterInteractions(() => {
|
||||
database.write(() => {
|
||||
emojis.forEach((emoji) => {
|
||||
try {
|
||||
database.create('customEmojis', emoji, true);
|
||||
} catch (e) {
|
||||
log('create custom emojis', e);
|
||||
}
|
||||
const serverVersion = reduxStore.getState().server.version;
|
||||
const updatedSince = getUpdatedSince();
|
||||
|
||||
// if server version is lower than 0.75.0, fetches from old api
|
||||
if (semver.lt(serverVersion, '0.75.0')) {
|
||||
// RC 0.61.0
|
||||
const result = await this.sdk.get('emoji-custom');
|
||||
|
||||
InteractionManager.runAfterInteractions(() => {
|
||||
let { emojis } = result;
|
||||
emojis = emojis.filter(emoji => !updatedSince || emoji._updatedAt > updatedSince);
|
||||
database.write(() => {
|
||||
create(emojis);
|
||||
});
|
||||
reduxStore.dispatch(actions.setCustomEmojis(this.parseEmojis(result.emojis)));
|
||||
});
|
||||
});
|
||||
reduxStore.dispatch(actions.setCustomEmojis(this.parseEmojis(emojis)));
|
||||
} else {
|
||||
const params = {};
|
||||
if (updatedSince) {
|
||||
params.updatedSince = updatedSince;
|
||||
}
|
||||
|
||||
// RC 0.75.0
|
||||
const result = await this.sdk.get('emoji-custom.list', params);
|
||||
|
||||
if (!result.success) {
|
||||
return;
|
||||
}
|
||||
|
||||
InteractionManager.runAfterInteractions(
|
||||
() => database.write(() => {
|
||||
const { emojis } = result;
|
||||
create(emojis.update);
|
||||
|
||||
if (emojis.delete && emojis.delete.length) {
|
||||
emojis.delete.forEach((emoji) => {
|
||||
try {
|
||||
const emojiRecord = database.objectForPrimaryKey('customEmojis', emoji._id);
|
||||
if (emojiRecord) {
|
||||
database.delete(emojiRecord);
|
||||
}
|
||||
} catch (e) {
|
||||
log('getEmojis delete', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const allEmojis = database.objects('customEmojis');
|
||||
reduxStore.dispatch(actions.setCustomEmojis(this.parseEmojis(allEmojis)));
|
||||
})
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
log('getCustomEmojis', e);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@ export const merge = (subscription, room) => {
|
|||
subscription.archived = room.archived;
|
||||
subscription.joinCodeRequired = room.joinCodeRequired;
|
||||
subscription.broadcast = room.broadcast;
|
||||
if (!subscription.roles || !subscription.roles.length) {
|
||||
subscription.roles = [];
|
||||
}
|
||||
|
||||
if (room.muted && room.muted.length) {
|
||||
subscription.muted = room.muted.filter(user => user).map(user => ({ value: user }));
|
||||
|
|
|
@ -286,21 +286,13 @@ const frequentlyUsedEmojiSchema = {
|
|||
}
|
||||
};
|
||||
|
||||
const customEmojiAliasesSchema = {
|
||||
name: 'customEmojiAliases',
|
||||
primaryKey: 'value',
|
||||
properties: {
|
||||
value: 'string'
|
||||
}
|
||||
};
|
||||
|
||||
const customEmojisSchema = {
|
||||
name: 'customEmojis',
|
||||
primaryKey: '_id',
|
||||
properties: {
|
||||
_id: 'string',
|
||||
name: 'string',
|
||||
aliases: { type: 'list', objectType: 'customEmojiAliases' },
|
||||
aliases: 'string[]',
|
||||
extension: 'string',
|
||||
_updatedAt: { type: 'date', optional: true }
|
||||
}
|
||||
|
@ -353,7 +345,6 @@ const schema = [
|
|||
permissionsSchema,
|
||||
url,
|
||||
frequentlyUsedEmojiSchema,
|
||||
customEmojiAliasesSchema,
|
||||
customEmojisSchema,
|
||||
messagesReactionsSchema,
|
||||
messagesReactionsUsernamesSchema,
|
||||
|
@ -428,7 +419,7 @@ class DB {
|
|||
return this.databases.activeDB = new Realm({
|
||||
path: `${ path }.realm`,
|
||||
schema,
|
||||
schemaVersion: 8,
|
||||
schemaVersion: 9,
|
||||
migration: (oldRealm, newRealm) => {
|
||||
if (oldRealm.schemaVersion >= 3 && newRealm.schemaVersion <= 8) {
|
||||
const newSubs = newRealm.objects('subscriptions');
|
||||
|
@ -445,6 +436,14 @@ class DB {
|
|||
const newThreadMessages = newRealm.objects('threadMessages');
|
||||
newRealm.delete(newThreadMessages);
|
||||
}
|
||||
if (newRealm.schemaVersion === 9) {
|
||||
const newSubs = newRealm.objects('subscriptions');
|
||||
newRealm.delete(newSubs);
|
||||
const newEmojis = newRealm.objects('customEmojis');
|
||||
newRealm.delete(newEmojis);
|
||||
const newSettings = newRealm.objects('settings');
|
||||
newRealm.delete(newSettings);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue