android doesn't support all emojis. use different lib that tells us which emojis are supported.

This commit is contained in:
Yonah Forst 2016-07-31 19:12:02 +02:00
parent ac6f870028
commit 3b1d561a66
2 changed files with 77 additions and 25 deletions

View File

@ -10,34 +10,78 @@ import {
TouchableOpacity,
TouchableWithoutFeedback,
View,
Platform,
} from 'react-native'
import emoji from 'emojilib'
import emoji from 'emoji-datasource'
import {
groupBy,
orderBy,
includes,
} from 'lodash/collection'
import {
mapValues,
} from 'lodash/object'
//polyfil for android
require('string.fromcodepoint');
// i dont understand ANY of this but there's somethign called codepoints and surrogate pairs
// and this converts utf16 to a charachter in javascript. see more here:
//https://mathiasbynens.be/notes/javascript-unicode
//https://mathiasbynens.be/notes/javascript-escapes#unicode-code-point
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint
const charFromUtf16 = utf16 => String.fromCodePoint(...utf16.split('-').map(u => '0x' + u))
const charFromEmojiObj = obj => charFromUtf16(obj.unified)
const blacklistedEmojis = ['white_frowning_face', 'keycap_star', 'eject']
const isAndroid = Platform.OS == 'android'
const letterSpacing = 10
const defaultEmojiSize = 30
const categories = ['People', 'Nature', 'Foods', 'Activity', 'Places', 'Objects', 'Symbols', 'Flags']
const filteredEmojis = emoji.filter(e => isAndroid ? !!e.google : !includes(blacklistedEmojis, e.short_name))
// sort emojis by 'sort_order' then group them into categories
const groupedAndSorted = groupBy(orderBy(filteredEmojis, 'sort_order'), 'category')
// convert the emoji object to a character
const emojisByCategory = mapValues(groupedAndSorted, group => group.map(charFromEmojiObj))
const EmojiPicker = (props) => {
let container = []
let rowCount = props.rows || 7
let ordered = emoji.ordered
for (var i = 0; i < rowCount; i++) {
let row = []
for (var n = 0; n < ordered.length/rowCount; n++) {
let index = i + n * rowCount + 1
if (index < ordered.length) {
row.push(ordered[index])
// instead listing emojis left-to-right we want to list them top-to-bottom.
// we split them in to rows by sequentially taking every Xth value, where X is the number of rows
function transposeEmojisVertically(emojis, rowCount = 7) {
let array = []
for (var i = 0; i < rowCount; i++) {
let row = []
for (var n = 0; n < emojis.length/rowCount; n++) {
let index = i + n * rowCount
if (index < emojis.length) {
row.push(emojis[index])
}
}
array.push(row)
}
container.push(row)
return array
}
function renderSectionForCategory(c) {
let emojis = transposeEmojisVertically(emojisByCategory[c])
return (
<View key={c} style={styles.innerContainer}>
<Text style={[styles.headerText, props.headerStyle]}>{c}</Text>
{emojis.map(array => <Row {...props} array={array} key={array[0]} />)}
</View>
)
}
return (
<View style={props.style}>
<ScrollView horizontal={true}>
<View style={styles.innerContainer}>
{container.map(array => <Row {...props} array={array} key={array[0]} />)}
</View>
{categories.map(renderSectionForCategory)}
</ScrollView>
{props.hideClearButton ? null : <ClearButon {...props} />}
</View>
@ -49,25 +93,28 @@ const Row = props => {
function handlePress(event) {
let i = Math.floor(event.nativeEvent.locationX/(size + 5 + letterSpacing/2))
let name = props.array[i]
props.onEmojiSelected(emoji.lib[name].char)
if (i < props.array.length) {
let emoji = props.array[i]
props.onEmojiSelected(emoji)
}
}
return (
<TouchableWithoutFeedback onPress={handlePress}>
<View>
<Text style={[styles.rowText, {fontSize: size}]} >
{props.array.map(name => emoji.lib[name].char)}
{props.array}
</Text>
</View>
</TouchableWithoutFeedback>
)
}
const ClearButon = props => {
return (
<TouchableOpacity
onPress={() => props.onEmojiSelected(null)}>
<Text style={styles.clearButton}>
<Text style={[styles.clearButton, props.clearButtonStyle]}>
{props.clearButtonText || 'Clear'}
</Text>
</TouchableOpacity>
@ -87,6 +134,7 @@ let styles = StyleSheet.create({
clearButton: {
padding: 15,
textAlign: 'center',
color: 'black',
},
absolute: {
position: 'absolute',
@ -116,6 +164,11 @@ let styles = StyleSheet.create({
rowText: {
letterSpacing: letterSpacing,
paddingHorizontal: 5,
color: 'black',
},
headerText: {
padding: 5,
color: 'black',
}
})

View File

@ -1,11 +1,8 @@
{
"name": "react-native-emoji-picker",
"version": "0.1.2",
"version": "0.2.0",
"description": "Simple emoji picker for react-native",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git@github.com:yonahforst/react-native-emoji-picker.git"
@ -18,11 +15,13 @@
"emoji-picker"
],
"devDependencies": {
"react": "^0.14.8",
"react-native": "^0.25.0"
"react": "^15.2.0",
"react-native": "^0.30.0"
},
"dependencies": {
"emojilib": "^2.0.2"
"emoji-datasource": "^2.4.4",
"lodash": "^4.11.1",
"string.fromcodepoint": "^0.2.1"
},
"author": "Yonah Forst <yonaforst@hotmail.com> (https://github.com/yonahforst)",
"license": "MIT",