Skip to content

Commit

Permalink
TweetWallFX#1288 Emojify the tweet stream
Browse files Browse the repository at this point in the history
  • Loading branch information
svenreimers committed Oct 10, 2022
1 parent f51b458 commit 97696c9
Show file tree
Hide file tree
Showing 9 changed files with 405 additions and 27 deletions.
1 change: 1 addition & 0 deletions controls/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies {
implementation 'de.jensd:fontawesomefx-fontawesome:4.7.0-11'
implementation 'org.apache.logging.log4j:log4j-api:2.19.0'
implementation project(':tweetwallfx-core')
implementation project(':tweetwallfx-emoji')
implementation project(':tweetwallfx-stepengine-dataproviders')
implementation project(':tweetwallfx-transitions')
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import org.tweetwallfx.tweet.api.Tweet;
import org.tweetwallfx.tweet.api.entry.MediaTweetEntry;
import org.tweetwallfx.tweet.api.entry.MediaTweetEntryType;
import org.tweetwallfx.emoji.control.EmojiFlow;

/**
* Infinite TweetStream Animation Step
Expand Down Expand Up @@ -251,23 +252,20 @@ private Pane createSingleTweetDisplay(
final Tweet displayTweet) {

String textWithoutMediaUrls = displayTweet.getDisplayEnhancedText();
Text text = new Text(textWithoutMediaUrls.replaceAll("[\n\r]+", config.respectLineFeeds ? "\n": "|"));
text.setCache(config.tweetTextNode.isCacheEnabled);
text.setCacheHint(config.tweetTextNode.cacheHint);
text.getStyleClass().add("tweetText");
String text = textWithoutMediaUrls.replaceAll("[\n\r]+", config.respectLineFeeds ? "\n": "|");
Node profileImageView = createProfileImageView(displayTweet);
TextFlow flow = new TextFlow(text);
EmojiFlow flow = new EmojiFlow();
flow.setText(text);
flow.getStyleClass().add("tweetFlow");
flow.setCache(config.tweetFlowNode.isCacheEnabled);
flow.setCacheHint(config.tweetFlowNode.cacheHint);
flow.setMinWidth(config.tweetWidth);
flow.setMaxWidth(config.tweetWidth);
flow.setPrefWidth(config.tweetWidth);
Text name = new Text(displayTweet.getUser().getName());
name.getStyleClass().add("tweetUsername");
name.setCache(config.speakerNameNode.isCacheEnabled);
name.setCacheHint(config.speakerNameNode.cacheHint);
TextFlow nameFlow = new TextFlow(name);

String name = displayTweet.getUser().getName();
EmojiFlow nameFlow = new EmojiFlow();
nameFlow.setText(name);
nameFlow.setCache(config.tweetFlowNode.isCacheEnabled);
nameFlow.setCacheHint(config.tweetFlowNode.cacheHint);
Label naturalTime = new Label(Humanize.naturalTime(displayTweet.getCreatedAt(), Locale.ENGLISH));
Expand Down Expand Up @@ -334,23 +332,28 @@ public void shutdown() {
shutdownCountdown = new CountDownLatch(2);
this.isTerminated = true;
Platform.runLater(() -> {
wordleSkin.getPane().getChildren().stream().map(p -> (Pane) p).filter(p -> p.getId() != null && p.getId().startsWith("infiniteStream")).forEach(pane -> {
LOG.info("Shutting down " + pane.getId());
for (Node nodeToFadeOut : pane.getChildren()) {
var fadeOut = new FadeTransition(Duration.millis(1500), nodeToFadeOut);
fadeOut.setFromValue(1);
fadeOut.setToValue(0);
fadeOut.setOnFinished(e -> {
pane.getChildren().remove(nodeToFadeOut);
if (pane.getChildren().isEmpty()) {
wordleSkin.getPane().getChildren().remove(pane);
LOG.info("Shutting down - removed " + pane.getId() + " from wordle");
shutdownCountdown.countDown();
}
});
fadeOut.play();
}
});
wordleSkin.getPane().getChildren()
.stream()
.filter(p -> p instanceof Pane)
.map(p -> (Pane) p)
.filter(p -> p.getId() != null && p.getId().startsWith("infiniteStream"))
.forEach(pane -> {
LOG.info("Shutting down " + pane.getId());
for (Node nodeToFadeOut : pane.getChildren()) {
var fadeOut = new FadeTransition(Duration.millis(1500), nodeToFadeOut);
fadeOut.setFromValue(1);
fadeOut.setToValue(0);
fadeOut.setOnFinished(e -> {
pane.getChildren().remove(nodeToFadeOut);
if (pane.getChildren().isEmpty()) {
wordleSkin.getPane().getChildren().remove(pane);
LOG.info("Shutting down - removed " + pane.getId() + " from wordle");
shutdownCountdown.countDown();
}
});
fadeOut.play();
}
});
});
try {
shutdownCountdown.await();
Expand Down
29 changes: 29 additions & 0 deletions emoji/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-2022 TweetWallFX
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

dependencies {
api project(':tweetwallfx-cache')
implementation 'org.apache.logging.log4j:log4j-api:2.19.0'
implementation 'com.vdurmont:emoji-java:5.1.1'
}
46 changes: 46 additions & 0 deletions emoji/src/main/java/org/tweetwallfx/emoji/EmojiImageCache.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2022 TweetWallFX
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.tweetwallfx.emoji;

import org.tweetwallfx.cache.URLContent;
import org.tweetwallfx.cache.URLContentCacheBase;

/**
* Cache used to provide the avatar image of a User.
*/
public final class EmojiImageCache extends URLContentCacheBase {

/**
* Cache instance.
*/
public static final EmojiImageCache INSTANCE = new EmojiImageCache();

private EmojiImageCache() {
super("emojiImage");
}

public URLContent get(String hex) {
return EmojiImageCache.INSTANCE.getCachedOrLoad("https://twemoji.maxcdn.com/v/latest/72x72/"+ hex + ".png");
}
}
81 changes: 81 additions & 0 deletions emoji/src/main/java/org/tweetwallfx/emoji/Emojify.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2022 TweetWallFX
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package org.tweetwallfx.emoji;

import com.vdurmont.emoji.EmojiParser;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class Emojify {

@SuppressWarnings({"NarrowCalculation","StringSplitter"})
private static String convert(String unicodeStr) {
if (unicodeStr.isEmpty()) return unicodeStr;
List<String> parts = new ArrayList<String>();
int c = 0;
int p = 0;
for (int i=0; i<unicodeStr.length(); i++) {
c = unicodeStr.charAt(i);
if (p > 0) {
parts.add(Integer.toString(0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00), 16));
p = 0;
} else if (0xD800 <= c && c <= 0xDBFF) {
p = c;
} else {
parts.add(Integer.toString(c,16));
p=0;
}
}
String dashedLogic = parts.stream().collect(Collectors.joining("-"));
return dashedLogic;
}


public static List<Object> tokenizeStringToTextAndEmoji(final String message) {
var emojiCandidates = new ArrayList<EmojiParser.UnicodeCandidate>();
EmojiParser.parseFromUnicode(message, new EmojiParser.EmojiTransformer() {
@Override
public String transform(EmojiParser.UnicodeCandidate unicodeCandidate) {
emojiCandidates.add(unicodeCandidate);
return "";
}
});
var objects = new ArrayList<Object>();
int startIndex = 0;
for (com.vdurmont.emoji.EmojiParser.UnicodeCandidate unicodeCandidate : emojiCandidates) {
String text = message.substring(startIndex, unicodeCandidate.getEmojiStartIndex());
if (!text.isEmpty()) {
objects.add(text);
}
startIndex = unicodeCandidate.getFitzpatrickEndIndex();
String hex = convert(unicodeCandidate.getEmoji().getUnicode());
objects.add(new Twemoji(hex));
}
objects.add(message.substring(startIndex, message.length()));
return objects;
}
}

29 changes: 29 additions & 0 deletions emoji/src/main/java/org/tweetwallfx/emoji/Twemoji.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2022 TweetWallFX
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package org.tweetwallfx.emoji;

public record Twemoji(String hex) {

}
Loading

0 comments on commit 97696c9

Please sign in to comment.