Skip to content

Commit

Permalink
Support emojis (#433)
Browse files Browse the repository at this point in the history
* "enrich" messages

* display text and placeholder-emoji

* download emoji-archive and unpack

* display correct images

* display emoji with the correct size

* start multi-unit emoji decoding

* support standard (looking at you, VS16) encoded multi-unit emojis

* remove optional characters from emoji sequences and save them as new file

* use removeAllSuchThat to filter optional characters

* filter optional character from messages as well

* prompt user to download emojis at startup

* please linter

* support notifications and massage-list-item

* tests emojis are present

* test correct creation of unicode runs

* test emoji string has two emojis next to eachother

* begin of decodeUnicodeRun test

* test decodeUnicodeRun

* test embedEmojisInto

* please linter again

* remove unneccessary asString

* use local variable to convert runOrChar

* test wether message display emojis correctly

* test wether notifications display emojis correctly

* refactoring

* download emojis in background

* please linter

* assure emojis are present during testing

* optimize findLongestRun by size cap

* please linter + remove todo comment (loggedIn) + ci hashes

* last ci hashes

* please 5.2

* Credit OpenMoji

* Update README.md

* make screenshot tests expected failures

* synchronous downloading and filename cache

* Fix PR annotations

* fixes for performance on mac, no more magic values, some formatting

* please linter -.-

* initialize filenames of TCUEmojiHelper to deal with asynchronous messages to filenames on first app start

* fix areEmojisPresent

* do not call super initialize in TCUEmojiHelper>>Initialize

* load filenames on initialization to work across commits

* properly load filenames on init

* address remarks from PR, rename runs to something more specific

* address hidden PR remarks

* please linter

* refactoring for PR

* final PR fixes + comments + loading bar

* fix typo

* merge emoji changes together

* force all emojis to be present

* update filename cache after downloading

Co-authored-by: Raphael Kunert <[email protected]>
Co-authored-by: rsommerfeld <[email protected]>
  • Loading branch information
3 people authored Jul 17, 2021
1 parent 9b337de commit 4276f5b
Show file tree
Hide file tree
Showing 85 changed files with 509 additions and 23 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,8 @@ Pre-Releases are created automatically whenever a commit is added to the develop
## Our Group

Group 13 of the 2020 SWT I module included [Rohan Sawahn](https://github.com/rohansaw), [Jonas Schmidt](https://github.com/schmidtjonas), [Frederik Wollny](https://github.com/Freddy200), [Stefan Spangenberg](https://github.com/sspangenberg), [Lukas Laskowski](https://github.com/lasklu), and [Niklas Schilli](https://github.com/Mrnikbobjeff). Feel free to add your names to the list.

## Acknowledgements
This project uses assets from https://openmoji.org/ for Emoji support. These are downloaded when the client starts for the first time and not hosted in this repository.
Each file is resized before being displayed and filenames are stripped of certain Unicode units after download. The contents of the files is not changed.
OpenMoji is published under the Creative Commons Share Alike License 4.0 [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/#). Their project is also hosted on [GitHub](https://github.com/hfg-gmuend/openmoji).
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ event handling
handlePendingEvent: anEvent

| extra |
extra := (anEvent at: '@extra') asString.
extra := anEvent at: '@extra'.
(self pendingRequests at: extra) value: anEvent.
self pendingRequests removeKey: extra ifAbsent: []
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"getOwnProfile" : "RS 6/24/2021 09:18",
"handleEvent:" : "pk 6/19/2021 17:45",
"handleMessageEvent:" : "pk 5/28/2021 09:41",
"handlePendingEvent:" : "5/30/2021 12:11:04",
"handlePendingEvent:" : "pk 7/5/2021 17:33",
"imageStore" : "pk 6/19/2021 17:15",
"imageStore:" : "TR 6/22/2021 09:33",
"initialize" : "pk 6/29/2021 09:26",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ downloadArchive
response := WebClient httpGet: self downloadUrl.
stream
binary;
nextPutAll: response content.
intermediatePath := FileDirectory default / 'archive.zip'].
nextPutAll: response content].
archive := ZipArchive new readFrom: intermediatePath fullName.
archive extractAllTo: FileDirectory default.
archive close.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"class" : {
"downloadArchive" : "ct 10/7/2020 21:09",
"downloadArchive" : "RK 7/9/2021 15:30",
"downloadUrl" : "N.S. 7/23/2020 12:45",
"fileName" : "f.w. 7/15/2020 22:04",
"moduleName" : "js 8/2/2020 13:21" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ drawing
addLastMessage

self addMorph: (TextMorph new
contents: (self chat lastMessage condensedIntoOneLine truncateWithElipsisTo: self class defaultMessagePreviewLength) asText;
contents: self lastMessageText;
bottomLeft: self bottomLeft + self class defaultLastMessageOffset;
lock).
lock).
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
accessing
lastMessageText

^ TCUEmojiHelper embedEmojisInto:
(self chat lastMessage condensedIntoOneLine
truncateWithElipsisTo: self class defaultMessagePreviewLength)
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
"defaultHeight" : "rs 7/4/2020 18:54",
"defaultLastMessageOffset" : "JB 6/11/2021 15:17",
"defaultMessagePreviewLength" : "JB 6/11/2021 15:17",
"defaultTitleLength" : "JB 6/11/2021 15:18",
"defaultTitleLength" : "RK 7/4/2021 13:30",
"defaultTitleOffset" : "JB 6/11/2021 15:18",
"newWithChat:width:" : "js 7/31/2020 18:48" },
"instance" : {
"addBorder" : "JB 6/11/2021 18:35",
"addLastMessage" : "JB 6/11/2021 15:18",
"addLastMessage" : "RK 7/9/2021 10:34",
"addTitle" : "JB 6/11/2021 15:18",
"chat" : "rs 6/17/2020 21:45",
"chat:" : "rs 6/17/2020 21:45",
"chatID" : "rs 6/17/2020 23:05",
"chatName" : "rs 6/17/2020 21:45",
"deselect" : "rs 6/13/2020 09:02",
"initialize" : "r.s 7/31/2020 14:43",
"lastMessageText" : "RK 7/9/2021 16:07",
"select" : "TR 6/13/2021 16:02" } }
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
A TCUEmojiHelper is a helper class for downloading emojis and decoding a string into a Text with embedded emojis.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
unicode matching
add: aCharacter to: aCharAndEmojiCollection

(aCharacter isOctetCharacter) ifTrue: [
aCharAndEmojiCollection add: aCharacter.
] ifFalse: [
self addEmojiCodePoint: aCharacter codePoint printStringHex to: aCharAndEmojiCollection.
].
^ aCharAndEmojiCollection
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
unicode matching
addEmojiCodePoint: aHexString to: aCharAndEmojisCollection

(aCharAndEmojisCollection isEmpty or: [aCharAndEmojisCollection last isCharacter]) ifTrue: [
aCharAndEmojisCollection add: OrderedCollection new
].
aCharAndEmojisCollection last add: aHexString.
^ aCharAndEmojisCollection
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
downloading
areEmojisPresent

^ self defaultDirectory exists
and: [self defaultDirectory hasFiles]
and: [self defaultDirectory fileNames size >= self defaultMinimumEmojiAmount]
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
default values
defaultDirectory

^ FileDirectory default directoryNamed: self defaultFolderName
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
default values
defaultEmojiFileExtension

^ '.png'
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
default values
defaultFolderName

^ 'emojis'
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
default values
defaultMaxEmojiLength

^ 10
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
default values
defaultMinimumEmojiAmount

^ 3678
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
default values
defaultOptionalCharacters

"Emoji are encoded differently, by different devices, applications and operating systems.
The ground truth though lies close to an encoding without VARIATION SELECTOR-16 characters.
Thats why we collect them here as optional characters."
^ OrderedCollection newFrom: {'FE0F'}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
default values
defaultTextHeight

^ TextStyle defaultFont pointSize * 2
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
downloading
downloadArchive

| intermediatePath response |
intermediatePath := FileDirectory default / 'emoji.zip'.
FileStream fileNamed: intermediatePath fullName do: [ :stream |
response := WebClient httpGet: self downloadUrl.
stream
binary;
nextPutAll: response content.
].
self defaultDirectory assureExistence.
(ZipArchive new readFrom: intermediatePath fullName)
extractAllTo: self defaultDirectory;
close.
(FileDirectory default / 'emoji.zip') delete.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
downloading
downloadUrl

"Credits to OpenEmoji (https://openmoji.org)"
^ 'https://github.com/hfg-gmuend/openmoji/releases/download/13.0.0/openmoji-72x72-color.zip'
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
utility
embedEmojisInto: aString

| charsAndEmojis |
charsAndEmojis := self splitCharsAndEmojisIn: (self reencodeString: aString).
^ charsAndEmojis
inject: Text new
into: [:aggregatedText :charOrEmojis |
(charOrEmojis isCharacter) ifTrue: [
aggregatedText , charOrEmojis asText.
] ifFalse: [
aggregatedText , (self textFrom: (self removeOptionalCharactersFrom: charOrEmojis))
]
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
utility
emojiExists: aString

^ self fileNames includes: aString , self defaultEmojiFileExtension
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
downloading
ensureEmojisArePresent

self areEmojisPresent ifFalse: [
'Downloading Emojis'
displayProgressAt: Display center
from: 0
to: 3
during: [ :bar |
self downloadArchive.
bar value: 1.
self removeOptionalCharacters.
bar value: 2.
self loadFileNames.
bar value: 3.
]
].
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
utility
fileNameFor: anEmoji

^ (anEmoji
inject: String new
into: [:name :unit | name , unit , '-'])
allButLast
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
accessing
fileNames: aCollection

fileNames := aCollection
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
accessing
fileNames

^ fileNames
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
utility
findFirstEmojiLengthIn: anEmojiSequence

anEmojiSequence size > self defaultMaxEmojiLength ifTrue: [
^ self findFirstEmojiLengthIn: (anEmojiSequence first: self defaultMaxEmojiLength)
].
(anEmojiSequence size <= 1 or: [self emojiExists: (self fileNameFor: anEmojiSequence)]) ifTrue: [
^ anEmojiSequence size
].
^ self findFirstEmojiLengthIn: anEmojiSequence allButLast
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
utility
formFor: aString

| fileName form |
fileName := aString , self defaultEmojiFileExtension.

(self defaultDirectory
fileExists: fileName)
ifTrue: [
form := Form fromBinaryStream: (self defaultDirectory fileNamed: fileName).
] ifFalse: [
form := MenuIcons squeakLogoIcon.
].
form := form scaledToHeight: self defaultTextHeight.
^ form
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class initialization
initialize

self
fileNames: OrderedCollection new;
loadFileNames.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
downloading
loadFileNames

self fileNames: self defaultDirectory fileNames
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
downloading
promptDownload

UIManager default inform: 'Emojis are not present in this image. They will be downloaded now.'.
self ensureEmojisArePresent.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
utility
reencodeString: aString

"The Json library does not handle UTF-16 correctly. Reencode to work around this"
"Note how JSON>>unescapeUnicode only looks at the next 4 characters after \u"
^ (aString convertToEncoding: 'UTF-16') convertFromEncoding: 'UTF-16'
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
downloading
removeOptionalCharacters

"remove characters not sent by every client from all filenames"
| filenames |
filenames := self defaultDirectory fileNames.

filenames do: [ :filename |
| newFileName splitCollection |
splitCollection := self removeOptionalCharactersFrom: (self splitFileName: filename).
newFileName := (self fileNameFor: splitCollection) , self defaultEmojiFileExtension.
(self defaultDirectory fileExists: newFileName) ifFalse: [
self defaultDirectory copyFileNamed: filename toFileNamed: newFileName.
self defaultDirectory deleteFileNamed: filename.
].
].
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
utility
removeOptionalCharactersFrom: aCollection

"OpenMoji includes some optional characters in their filenames"
"not all clients send them, so we remove them to ease matching"
^ aCollection removeAllSuchThat: [ :code | self defaultOptionalCharacters includes: code]
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
unicode matching
splitCharsAndEmojisIn: aString

^ aString
inject: OrderedCollection new
into: [ :charsAndEmojis :char |
self add: char to: charsAndEmojis.
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
downloading
splitFileName: aString

^ ((aString subStrings: '.') first subStrings: '-') asOrderedCollection
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
utility
textFor: aString

"we are using value: 1 here as the method 'startOfHeader' isn't available on 5.2"
^ Text
string: (Character value: 1) asString
attribute: (TextAnchor new anchoredMorph: (self formFor: aString))
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
utility
textFrom: anEmojiSequence

| emojiLength |
emojiLength := self findFirstEmojiLengthIn: anEmojiSequence.
^ emojiLength > 0 ifTrue: [
(self textFor: (self fileNameFor: (anEmojiSequence first: emojiLength))) ,
(self textFrom: (anEmojiSequence allButFirst: emojiLength))
] ifFalse: [
Text new
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"class" : {
"add:to:" : "pk 7/11/2021 19:13",
"addEmojiCodePoint:to:" : "pk 7/17/2021 09:51",
"areEmojisPresent" : "pk 7/17/2021 10:18",
"defaultDirectory" : "pk 7/9/2021 16:10",
"defaultEmojiFileExtension" : "pk 7/10/2021 16:01",
"defaultFolderName" : "RK 6/29/2021 11:44",
"defaultMaxEmojiLength" : "pk 7/9/2021 16:03",
"defaultMinimumEmojiAmount" : "pk 7/17/2021 10:18",
"defaultOptionalCharacters" : "pk 7/6/2021 09:49",
"defaultTextHeight" : " 7/17/2021 09:37:29",
"downloadArchive" : "pk 7/17/2021 09:49",
"downloadUrl" : "RK 6/29/2021 11:30",
"embedEmojisInto:" : "pk 7/11/2021 19:17",
"emojiExists:" : "pk 7/11/2021 19:20",
"ensureEmojisArePresent" : "pk 7/17/2021 10:54",
"fileNameFor:" : "pk 7/10/2021 16:33",
"fileNames" : "pk 7/10/2021 15:35",
"fileNames:" : "pk 7/10/2021 15:35",
"findFirstEmojiLengthIn:" : "pk 7/17/2021 09:54",
"formFor:" : "pk 7/10/2021 16:01",
"initialize" : "pk 7/10/2021 16:34",
"loadFileNames" : "pk 7/10/2021 15:36",
"promptDownload" : "pk 7/17/2021 09:47",
"reencodeString:" : "pk 7/11/2021 19:19",
"removeOptionalCharacters" : "pk 7/10/2021 16:23",
"removeOptionalCharactersFrom:" : "pk 7/17/2021 09:55",
"splitCharsAndEmojisIn:" : "pk 7/17/2021 09:52",
"splitFileName:" : "pk 7/10/2021 16:12",
"textFor:" : "pk 7/10/2021 16:34",
"textFrom:" : "pk 7/17/2021 09:58" },
"instance" : {
} }
Loading

0 comments on commit 4276f5b

Please sign in to comment.