From d94cfa939cd5654984009a4cb0d03bfcfa141708 Mon Sep 17 00:00:00 2001 From: Patrick Reinhart Date: Fri, 16 Feb 2024 15:16:17 +0100 Subject: [PATCH 1/2] Initial post step version --- .../stepengine/steps/ShowPosts.java | 248 ++++++++++++++++++ .../stepengine/steps/ShowSchedule.java | 8 +- ...rg.tweetwallfx.stepengine.api.Step$Factory | 1 + .../google/vision/ImageContentFilterStep.java | 11 +- .../dataproviders/PhotoImageCache.java | 10 +- .../tweet/api/entry/MediaTweetEntry.java | 9 +- .../tweet/impl/mastodon4j/MastodonStatus.java | 41 ++- .../impl/mastodon4j/MastodonStatusTest.java | 12 +- .../tweet/impl/mock/MockPostMedia.java | 6 +- .../tweet/impl/mock/MockTweeter.java | 3 +- .../twitter4j/TwitterMediaTweetEntry.java | 14 +- 11 files changed, 331 insertions(+), 32 deletions(-) create mode 100644 conference-stepengine/src/main/java/org/tweetwallfx/conference/stepengine/steps/ShowPosts.java diff --git a/conference-stepengine/src/main/java/org/tweetwallfx/conference/stepengine/steps/ShowPosts.java b/conference-stepengine/src/main/java/org/tweetwallfx/conference/stepengine/steps/ShowPosts.java new file mode 100644 index 000000000..6df685a9a --- /dev/null +++ b/conference-stepengine/src/main/java/org/tweetwallfx/conference/stepengine/steps/ShowPosts.java @@ -0,0 +1,248 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024-2025 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.conference.stepengine.steps; + +import java.util.Arrays; +import java.util.Collection; + +import javafx.application.Platform; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.Pane; +import javafx.scene.shape.Circle; +import javafx.scene.shape.Rectangle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.tweetwallfx.controls.WordleSkin; +import org.tweetwallfx.emoji.control.EmojiFlow; +import org.tweetwallfx.stepengine.api.DataProvider; +import org.tweetwallfx.stepengine.api.Step; +import org.tweetwallfx.stepengine.api.StepEngine.MachineContext; +import org.tweetwallfx.stepengine.api.config.AbstractConfig; +import org.tweetwallfx.stepengine.api.config.StepEngineSettings; +import org.tweetwallfx.stepengine.dataproviders.TweetStreamDataProvider; +import org.tweetwallfx.stepengine.dataproviders.TweetUserProfileImageDataProvider; +import org.tweetwallfx.tweet.api.Tweet; + +import javafx.animation.FadeTransition; +import javafx.geometry.Insets; +import javafx.scene.CacheHint; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.util.Duration; + +public class ShowPosts implements Step { + private static final Logger LOGGER = LoggerFactory.getLogger(ShowPosts.class); + private final Config config; + + private ShowPosts(Config config) { + this.config = config; + } + + @Override + public void doStep(MachineContext context) { + final var wordleSkin = (WordleSkin) context.get("WordleSkin"); + final var dataProvider = context.getDataProvider(TweetStreamDataProvider.class); + + var existingPostsNode = (Pane)wordleSkin.getNode().lookup("#postsNode"); + if (null == existingPostsNode) { + LOGGER.debug("Initializing posts node"); + + var postsNode = new Pane(); + postsNode.getStyleClass().add("posts"); + postsNode.setId("postsNode"); + postsNode.setOpacity(0); + + var title = new Label("Latest Posts"); + + title.setPrefWidth(config.width); + title.getStyleClass().add("title"); + title.setPrefHeight(config.titleHeight); + title.setAlignment(Pos.CENTER); + + postsNode.getChildren().add(title); + + final var fadeIn = new FadeTransition(Duration.millis(500), postsNode); + fadeIn.setFromValue(0); + fadeIn.setToValue(1); + fadeIn.setOnFinished(e -> { + LOGGER.info("Calling proceed from ShowPosts"); + context.proceed(); + }); + postsNode.setLayoutX(config.layoutX); + postsNode.setLayoutY(config.layoutY); + postsNode.setMinWidth(config.width); + postsNode.setMaxWidth(config.width); + postsNode.setPrefWidth(config.width); + postsNode.setCacheHint(CacheHint.SPEED); + postsNode.setCache(true); + int col = 0; + int row = 0; + + for (Tweet post : dataProvider.getTweets()) { + Pane postPane = createPostNode(context, post); + double postWidth = (config.width - (config.columns - 1) * config.postHGap) / config.columns; + postPane.setMinWidth(postWidth); + postPane.setMaxWidth(postWidth); + postPane.setPrefWidth(postWidth); + postPane.setMinHeight(config.postHeight); + postPane.setMaxHeight(config.postHeight); + postPane.setPrefHeight(config.postHeight); + postPane.setLayoutX(col * (postWidth + config.postHGap)); + postPane.setLayoutY(config.titleHeight + config.postVGap + (config.postHeight + config.postVGap) * row); + postsNode.getChildren().add(postPane); + col++; + if (col == config.columns) { + row++; + col = 0; + } + if (row >= config.rows) { + break; + } + } + + Platform.runLater(() -> { + wordleSkin.getPane().getChildren().add(postsNode); + fadeIn.play(); + }); + } + } + + private Pane createPostNode(MachineContext context, Tweet post) { + final var userImageProvider = context.getDataProvider(TweetUserProfileImageDataProvider.class); + final var bpPostPane = new BorderPane(); + bpPostPane.getStyleClass().add("postDisplay"); + bpPostPane.setCenter(createSinglePostDisplay(post, userImageProvider)); + return bpPostPane; + } + + private HBox createSinglePostDisplay(final Tweet post, + final TweetUserProfileImageDataProvider userImageProvider) { + var postFlow = new EmojiFlow(); + postFlow.setText(post.getDisplayEnhancedText()); + postFlow.setEmojiFitWidth(config.postFontSize); + postFlow.setEmojiFitHeight(config.postFontSize); + postFlow.getStyleClass().add("postFlow"); + postFlow.setMaxHeight(Double.MAX_VALUE); + + var postUser = new EmojiFlow(); + postUser.setText(post.getUser().getName()); + postUser.setEmojiFitWidth(config.postUserFontSize); + postUser.setEmojiFitHeight(config.postFontSize); + postUser.getStyleClass().add("postUserName"); + postUser.setMaxHeight(Double.MAX_VALUE); + + VBox imageBox = new VBox(createPostUserImage(userImageProvider, post)); + imageBox.setPadding(new Insets(10, 0, 10, 10)); + + VBox postContentBox = new VBox(postUser, postFlow); + postContentBox.setSpacing(10); + postContentBox.setPadding(new Insets(10, 10, 10, 0)); + + HBox postBox = new HBox(imageBox, postContentBox); + postBox.setCacheHint(CacheHint.QUALITY); + postBox.setSpacing(10); + + return postBox; + } + + private Node createPostUserImage(TweetUserProfileImageDataProvider postImageProvider, Tweet post) { + var image = postImageProvider.getImageBig(post.getUser()); + var postUserImage = new ImageView(image); + postUserImage.getStyleClass().add("postUserImage"); + postUserImage.setPreserveRatio(true); + if (image.getWidth() > image.getHeight()) { + postUserImage.setFitHeight(config.avatarSize); + } else { + postUserImage.setFitWidth(config.avatarSize); + } + + // avatar image clipping + if (config.circularAvatar) { + Circle circle = new Circle(config.avatarSize / 2f, config.avatarSize / 2f, config.avatarSize / 2f); + postUserImage.setClip(circle); + } else { + Rectangle clip = new Rectangle(config.avatarSize, config.avatarSize); + clip.setArcWidth(config.avatarArcSize); + clip.setArcHeight(config.avatarArcSize); + postUserImage.setClip(clip); + } + return postUserImage; + } + + static String fixup(String source) { + return source.replaceAll("[\n\r]+", "|").replaceAll("[\u200D]",""); + } + + @Override + public boolean requiresPlatformThread() { + return false; + } + + @Override + public java.time.Duration preferredStepDuration(final MachineContext context) { + return java.time.Duration.ofMillis(config.getStepDuration()); + } + + /** + * Implementation of {@link Step.Factory} as Service implementation creating + * {@link ShowPosts}. + */ + public static final class FactoryImpl implements Step.Factory { + @Override + public Step create(final StepEngineSettings.StepDefinition stepDefinition) { + return new ShowPosts(stepDefinition.getConfig(ShowPosts.Config.class)); + } + + @Override + public Class getStepClass() { + return ShowPosts.class; + } + + @Override + public Collection> getRequiredDataProviders(final StepEngineSettings.StepDefinition stepSettings) { + return Arrays.asList(TweetStreamDataProvider.class, TweetUserProfileImageDataProvider.class); + } + } + + public static class Config extends AbstractConfig { + public double layoutX = 0; + public double layoutY = 0; + public double width = 800; + public double titleHeight = 60; + public double postVGap = 10; + public double postHGap = 10; + public double postHeight = 150; + public int postFontSize = 13; + public int postUserFontSize = 13; + public int columns = 1; + public int rows = 1; + public int avatarSize = 64; + public int avatarArcSize = 20; + public boolean circularAvatar = true; + } +} diff --git a/conference-stepengine/src/main/java/org/tweetwallfx/conference/stepengine/steps/ShowSchedule.java b/conference-stepengine/src/main/java/org/tweetwallfx/conference/stepengine/steps/ShowSchedule.java index 6a69747c3..3601403ef 100644 --- a/conference-stepengine/src/main/java/org/tweetwallfx/conference/stepengine/steps/ShowSchedule.java +++ b/conference-stepengine/src/main/java/org/tweetwallfx/conference/stepengine/steps/ShowSchedule.java @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2022-2024 TweetWallFX + * Copyright (c) 2022-2025 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 @@ -116,10 +116,8 @@ public void doStep(final MachineContext context) { int col = 0; int row = 0; - Iterator iterator = dataProvider.getFilteredSessionData().iterator(); String oldRoom = null; - while (iterator.hasNext()) { - var sessionData = iterator.next(); + for (SessionData sessionData : dataProvider.getFilteredSessionData()) { if (null == oldRoom) { oldRoom = sessionData.room.getName(); } @@ -266,7 +264,7 @@ private Pane createSessionNode(final MachineContext context, final SessionData s if (config.showTags) { var tags = new FlowPane(); tags.getStyleClass().add("tags"); - sessionData.tags.stream().forEach(tag -> { + sessionData.tags.forEach(tag -> { var tagLabel = new Label(tag); tagLabel.getStyleClass().add("tagLabel"); tags.getChildren().add(tagLabel); diff --git a/conference-stepengine/src/main/resources/META-INF/services/org.tweetwallfx.stepengine.api.Step$Factory b/conference-stepengine/src/main/resources/META-INF/services/org.tweetwallfx.stepengine.api.Step$Factory index b2d590e05..5c076b11a 100644 --- a/conference-stepengine/src/main/resources/META-INF/services/org.tweetwallfx.stepengine.api.Step$Factory +++ b/conference-stepengine/src/main/resources/META-INF/services/org.tweetwallfx.stepengine.api.Step$Factory @@ -1,3 +1,4 @@ +org.tweetwallfx.conference.stepengine.steps.ShowPosts$FactoryImpl org.tweetwallfx.conference.stepengine.steps.ShowSchedule$FactoryImpl org.tweetwallfx.conference.stepengine.steps.ShowTopRated$FactoryImpl org.tweetwallfx.conference.stepengine.steps.SpeakerImageMosaicStep$FactoryImpl \ No newline at end of file diff --git a/google-cloud/src/main/java/org/tweetwallfx/google/vision/ImageContentFilterStep.java b/google-cloud/src/main/java/org/tweetwallfx/google/vision/ImageContentFilterStep.java index abbd6fb2b..7769b3362 100644 --- a/google-cloud/src/main/java/org/tweetwallfx/google/vision/ImageContentFilterStep.java +++ b/google-cloud/src/main/java/org/tweetwallfx/google/vision/ImageContentFilterStep.java @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2018-2023 TweetWallFX + * Copyright (c) 2018-2025 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 @@ -53,10 +53,11 @@ public class ImageContentFilterStep implements FilterStep { private static final Logger LOG = LoggerFactory.getLogger(ImageContentFilterStep.class); private static final Map> MTE_SIZE_TO_URL_FUNCTIONS = Map.of( - 0, mte -> mte.getMediaUrl() + ":thumb", - 1, mte -> mte.getMediaUrl() + ":small", - 2, mte -> mte.getMediaUrl() + ":medium", - 3, mte -> mte.getMediaUrl() + ":large"); + 0, mte -> mte.getMediaUrl(MediaTweetEntry.SizeHint.THUMB), + 1, mte -> mte.getMediaUrl(MediaTweetEntry.SizeHint.SMALL), + 2, mte -> mte.getMediaUrl(MediaTweetEntry.SizeHint.MEDIUM), + 3, mte -> mte.getMediaUrl(MediaTweetEntry.SizeHint.LARGE) + ); private final Config config; private final ImageContentAnalysis.SafeSearch requiredSafeSearch; diff --git a/stepengine-dataproviders/src/main/java/org/tweetwallfx/stepengine/dataproviders/PhotoImageCache.java b/stepengine-dataproviders/src/main/java/org/tweetwallfx/stepengine/dataproviders/PhotoImageCache.java index bff774bcd..79b155372 100644 --- a/stepengine-dataproviders/src/main/java/org/tweetwallfx/stepengine/dataproviders/PhotoImageCache.java +++ b/stepengine-dataproviders/src/main/java/org/tweetwallfx/stepengine/dataproviders/PhotoImageCache.java @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2018-2022 TweetWallFX + * Copyright (c) 2018-2025 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 @@ -48,10 +48,10 @@ public final class PhotoImageCache extends URLContentCacheBase { static { final Map> tmp = new HashMap<>(); - tmp.put(0, mte -> mte.getMediaUrl() + ":thumb"); - tmp.put(1, mte -> mte.getMediaUrl() + ":small"); - tmp.put(2, mte -> mte.getMediaUrl() + ":medium"); - tmp.put(3, mte -> mte.getMediaUrl() + ":large"); + tmp.put(0, mte -> mte.getMediaUrl(MediaTweetEntry.SizeHint.THUMB)); + tmp.put(1, mte -> mte.getMediaUrl(MediaTweetEntry.SizeHint.SMALL)); + tmp.put(2, mte -> mte.getMediaUrl(MediaTweetEntry.SizeHint.MEDIUM)); + tmp.put(3, mte -> mte.getMediaUrl(MediaTweetEntry.SizeHint.LARGE)); MTE_SIZE_TO_URL_FUNCTIONS = Collections.unmodifiableMap(tmp); } diff --git a/tweet-api/src/main/java/org/tweetwallfx/tweet/api/entry/MediaTweetEntry.java b/tweet-api/src/main/java/org/tweetwallfx/tweet/api/entry/MediaTweetEntry.java index a7017151e..b6fa1a5a5 100644 --- a/tweet-api/src/main/java/org/tweetwallfx/tweet/api/entry/MediaTweetEntry.java +++ b/tweet-api/src/main/java/org/tweetwallfx/tweet/api/entry/MediaTweetEntry.java @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2019 TweetWallFX + * Copyright (c) 2015-2025 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 @@ -37,9 +37,10 @@ public interface MediaTweetEntry extends TweetEntry { /** * Returns the media URL. * + * @param sizeHint optional size hint * @return the media URL */ - String getMediaUrl(); + String getMediaUrl(SizeHint sizeHint); /** * Returns size variations of the media. @@ -48,6 +49,10 @@ public interface MediaTweetEntry extends TweetEntry { */ Map getSizes(); + enum SizeHint { + THUMB, SMALL, MEDIUM, LARGE + } + interface Size extends java.io.Serializable { Integer THUMB = 0; diff --git a/tweet-impl-mastodon4j/src/main/java/org/tweetwallfx/tweet/impl/mastodon4j/MastodonStatus.java b/tweet-impl-mastodon4j/src/main/java/org/tweetwallfx/tweet/impl/mastodon4j/MastodonStatus.java index 5d97b75da..d5b7884f5 100644 --- a/tweet-impl-mastodon4j/src/main/java/org/tweetwallfx/tweet/impl/mastodon4j/MastodonStatus.java +++ b/tweet-impl-mastodon4j/src/main/java/org/tweetwallfx/tweet/impl/mastodon4j/MastodonStatus.java @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2023 TweetWallFX + * Copyright (c) 2015-2025 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 @@ -24,8 +24,14 @@ package org.tweetwallfx.tweet.impl.mastodon4j; import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.nodes.Node; +import org.jsoup.nodes.TextNode; import org.jsoup.safety.Cleaner; import org.jsoup.safety.Safelist; +import org.jsoup.select.NodeTraversor; +import org.jsoup.select.NodeVisitor; import org.mastodon4j.core.api.entities.Status; import org.tweetwallfx.tweet.api.Tweet; import org.tweetwallfx.tweet.api.User; @@ -36,14 +42,42 @@ import org.tweetwallfx.tweet.api.entry.UserMentionTweetEntry; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; +import java.util.StringJoiner; final class MastodonStatus implements Tweet { - private final Status status; + private final String text; + private final List hashtagTweetEntryList; public MastodonStatus(Status status) { this.status = status; + Cleaner cleaner = new Cleaner(Safelist.none().addTags("img", "movie", "a")); + Document document = cleaner.clean(Jsoup.parse(status.content())); + hashtagTweetEntryList = new ArrayList<>(); + NodeTraversor.traverse(new NodeVisitor() { + @Override + public void head(Node node, int i) { + if (node instanceof TextNode textNode) { + //String wholeText = textNode.getWholeText(); + hashtagTweetEntryList.add(null); + } else if (node instanceof Element element) { + switch (element.nodeName()) { + case "a" -> { + } + case "img" -> { + } + case "movie" -> { + } + default -> { + } + } + } + } + }, document); + this.text = document.text(); } @Override @@ -106,8 +140,7 @@ public Tweet getOriginTweet() { @Override public String getText() { - Cleaner cleaner = new Cleaner(Safelist.none()); - return cleaner.clean(Jsoup.parse(status.content())).text(); + return text; } @Override diff --git a/tweet-impl-mastodon4j/src/test/java/org/tweetwallfx/tweet/impl/mastodon4j/MastodonStatusTest.java b/tweet-impl-mastodon4j/src/test/java/org/tweetwallfx/tweet/impl/mastodon4j/MastodonStatusTest.java index d1783300f..e43a5256b 100644 --- a/tweet-impl-mastodon4j/src/test/java/org/tweetwallfx/tweet/impl/mastodon4j/MastodonStatusTest.java +++ b/tweet-impl-mastodon4j/src/test/java/org/tweetwallfx/tweet/impl/mastodon4j/MastodonStatusTest.java @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2023 TweetWallFX + * Copyright (c) 2023-2025 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 @@ -32,9 +32,13 @@ import static org.assertj.core.api.Assertions.assertThat; class MastodonStatusTest { + public static final String STATUS_CONTENT = """ +

the status #message html to @TweetwallFX, a new line: + some nice image + and a #special link to some content for @reinhapa

"""; ZonedDateTime createdAt = ZonedDateTime.now(ZoneId.systemDefault()); MastodonStatus status = new MastodonStatus(new Status("42", null, createdAt, null, - "

the status message html

", null, null, null, null, + STATUS_CONTENT, null, null, null, null, null, null, null, null, 33, 22, null, null, null, null, null, null, null, "german", null, null, null, true, null, null, null, null)); @@ -107,7 +111,9 @@ void getOriginTweet() { @Test void getText() { - assertThat(status.getText()).isEqualTo("the status message html"); + assertThat(status.getText()).isEqualTo(""" + the status #message html to @TweetwallFX, a new line: \ + some nice image and a #special link to some content for @reinhapa"""); assertThat(statusWithoutOptionals.getText()).isEmpty(); } diff --git a/tweet-impl-mock/src/main/java/org/tweetwallfx/tweet/impl/mock/MockPostMedia.java b/tweet-impl-mock/src/main/java/org/tweetwallfx/tweet/impl/mock/MockPostMedia.java index c6f90bf64..90623880d 100644 --- a/tweet-impl-mock/src/main/java/org/tweetwallfx/tweet/impl/mock/MockPostMedia.java +++ b/tweet-impl-mock/src/main/java/org/tweetwallfx/tweet/impl/mock/MockPostMedia.java @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2024 TweetWallFX + * Copyright (c) 2024-2025 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 @@ -35,7 +35,7 @@ public long getId() { } @Override - public String getMediaUrl() { + public String getMediaUrl(SizeHint sizeHint) { return "https://picsum.photos/id/%s/%s/%s".formatted(id, height, with); } @@ -55,7 +55,7 @@ public MediaTweetEntryType getType() { @Override public String getText() { - return getMediaUrl(); + return getMediaUrl(null); } @Override diff --git a/tweet-impl-mock/src/main/java/org/tweetwallfx/tweet/impl/mock/MockTweeter.java b/tweet-impl-mock/src/main/java/org/tweetwallfx/tweet/impl/mock/MockTweeter.java index 0e6bbaf81..a071b2ae3 100644 --- a/tweet-impl-mock/src/main/java/org/tweetwallfx/tweet/impl/mock/MockTweeter.java +++ b/tweet-impl-mock/src/main/java/org/tweetwallfx/tweet/impl/mock/MockTweeter.java @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2024 TweetWallFX + * Copyright (c) 2024-2025 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 @@ -69,6 +69,7 @@ public class MockTweeter implements Tweeter { private final List> postConsumers; private final Set posts; private final Map users; + private ScheduledFuture postTask; /** diff --git a/tweet-impl-twitter4j/src/main/java/org/tweetwallfx/tweet/impl/twitter4j/TwitterMediaTweetEntry.java b/tweet-impl-twitter4j/src/main/java/org/tweetwallfx/tweet/impl/twitter4j/TwitterMediaTweetEntry.java index 111625825..566433414 100644 --- a/tweet-impl-twitter4j/src/main/java/org/tweetwallfx/tweet/impl/twitter4j/TwitterMediaTweetEntry.java +++ b/tweet-impl-twitter4j/src/main/java/org/tweetwallfx/tweet/impl/twitter4j/TwitterMediaTweetEntry.java @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2023 TweetWallFX + * Copyright (c) 2015-2025 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 @@ -45,8 +45,14 @@ public long getId() { } @Override - public String getMediaUrl() { - return getT().getMediaURL(); + public String getMediaUrl(SizeHint sizeHint) { + return switch (sizeHint) { + case THUMB -> "%s:thumb".formatted(getT().getMediaURL()); + case SMALL -> "%s:small".formatted(getT().getMediaURL()); + case MEDIUM -> "%s:medium".formatted(getT().getMediaURL()); + case LARGE -> "%s:large".formatted(getT().getMediaURL()); + case null -> getT().getMediaURL(); + }; } @Override @@ -72,7 +78,7 @@ public MediaTweetEntryType getType() { public String toString() { return createToString(this, map( "id", getId(), - "mediaUrl", getMediaUrl(), + "mediaUrl", getMediaUrl(null), "sizes", getSizes() ), super.toString()); } From b148037a01c32aaccfec9d9ef9a84c2cd2eabdd1 Mon Sep 17 00:00:00 2001 From: Patrick Reinhart Date: Thu, 27 Feb 2025 12:06:20 +0100 Subject: [PATCH 2/2] Fixes gradle warning --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 0332b3392..790bd8a99 100644 --- a/build.gradle +++ b/build.gradle @@ -104,14 +104,14 @@ allprojects { ) trimTrailingWhitespace() - indentWithSpaces(4) + leadingTabsToSpaces(4) endWithNewline() replaceRegex 'noMultipleEmptyLines', '\n{3,}', '\n\n' } def closure = { trimTrailingWhitespace() - indentWithSpaces(4) + leadingTabsToSpaces(4) endWithNewline() // importOrder( // '\\#', // static imports