From 2103d03611adc0811c966b055d32682576754e2e Mon Sep 17 00:00:00 2001 From: Ruslan Penkrat Date: Sun, 12 Sep 2021 01:35:23 +0300 Subject: [PATCH] #1 initial sending media files support --- .../main/java/ru/penkrat/stbf/api/Media.java | 28 +++++++++ .../java/ru/penkrat/stbf/api/MediaType.java | 9 +++ .../main/java/ru/penkrat/stbf/api/Screen.java | 18 +++--- .../stbf/common/screen/MediaScreen.java | 23 ++++++++ stbf-demo/src/main/resources/flow.xml | 48 +++++++++++++-- .../stbf/impl/pengrad/BotResponseImpl.java | 7 +-- .../stbf/impl/pengrad/SendMethodUtils.java | 58 +++++++++++++++++++ stbf-templates/README.MD | 24 +++++++- .../penkrat/stbf/templates/MediaResolver.java | 9 +++ .../stbf/templates/xml/CommandItem.java | 3 + .../xml/FlowCommandResolverDelegate.java | 9 ++- .../xml/FlowMediaResolverDelegate.java | 58 +++++++++++++++++++ .../penkrat/stbf/templates/xml/FlowRoot.java | 4 ++ .../xml/FlowScreenResolverDelegate.java | 19 +++++- .../penkrat/stbf/templates/xml/MediaItem.java | 14 +++++ .../penkrat/stbf/templates/xml/MediaRoot.java | 21 +++++++ .../stbf/templates/xml/NamedItemResolver.java | 19 ++++++ .../stbf/templates/xml/ScreenItem.java | 4 ++ .../stbf/templates/xml/XmlFlowResolver.java | 7 ++- .../stbf/templates/xml/XmlWriterTest.java | 12 ++++ 20 files changed, 369 insertions(+), 25 deletions(-) create mode 100644 stbf-api/src/main/java/ru/penkrat/stbf/api/Media.java create mode 100644 stbf-api/src/main/java/ru/penkrat/stbf/api/MediaType.java create mode 100644 stbf-common/src/main/java/ru/penkrat/stbf/common/screen/MediaScreen.java create mode 100644 stbf-pengrad/src/main/java/ru/penkrat/stbf/impl/pengrad/SendMethodUtils.java create mode 100644 stbf-templates/src/main/java/ru/penkrat/stbf/templates/MediaResolver.java create mode 100644 stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowMediaResolverDelegate.java create mode 100644 stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/MediaItem.java create mode 100644 stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/MediaRoot.java diff --git a/stbf-api/src/main/java/ru/penkrat/stbf/api/Media.java b/stbf-api/src/main/java/ru/penkrat/stbf/api/Media.java new file mode 100644 index 0000000..34cbaba --- /dev/null +++ b/stbf-api/src/main/java/ru/penkrat/stbf/api/Media.java @@ -0,0 +1,28 @@ +package ru.penkrat.stbf.api; + +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; + +import java.util.function.Supplier; + +@Getter +@Builder +@ToString(of = {"mediaType", "url"}) +public class Media { + + private MediaType mediaType; + + private String url; + + private String fileId; + + private Supplier data; + + private Integer duration; + + private Integer width; + + private Integer height; + +} diff --git a/stbf-api/src/main/java/ru/penkrat/stbf/api/MediaType.java b/stbf-api/src/main/java/ru/penkrat/stbf/api/MediaType.java new file mode 100644 index 0000000..d25bce2 --- /dev/null +++ b/stbf-api/src/main/java/ru/penkrat/stbf/api/MediaType.java @@ -0,0 +1,9 @@ +package ru.penkrat.stbf.api; + +public enum MediaType { + ANIMATION, + AUDIO, + PHOTO, + VIDEO, + VOICE +} diff --git a/stbf-api/src/main/java/ru/penkrat/stbf/api/Screen.java b/stbf-api/src/main/java/ru/penkrat/stbf/api/Screen.java index c4b7a33..631a49b 100644 --- a/stbf-api/src/main/java/ru/penkrat/stbf/api/Screen.java +++ b/stbf-api/src/main/java/ru/penkrat/stbf/api/Screen.java @@ -2,13 +2,17 @@ package ru.penkrat.stbf.api; public interface Screen { - String getText(); + String getText(); - default Keyboard getKeyboard() { - return null; - } + default Media getMedia() { + return null; + } - default ScreenProperties getScreenProperties() { - return ScreenProperties.DEFAULT; - } + default Keyboard getKeyboard() { + return null; + } + + default ScreenProperties getScreenProperties() { + return ScreenProperties.DEFAULT; + } } diff --git a/stbf-common/src/main/java/ru/penkrat/stbf/common/screen/MediaScreen.java b/stbf-common/src/main/java/ru/penkrat/stbf/common/screen/MediaScreen.java new file mode 100644 index 0000000..7d8fb85 --- /dev/null +++ b/stbf-common/src/main/java/ru/penkrat/stbf/common/screen/MediaScreen.java @@ -0,0 +1,23 @@ +package ru.penkrat.stbf.common.screen; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import ru.penkrat.stbf.api.Keyboard; +import ru.penkrat.stbf.api.Media; +import ru.penkrat.stbf.api.Screen; + +@Getter +@RequiredArgsConstructor +public class MediaScreen implements Screen { + + private final String text; + + private final Media media; + + private final Keyboard keyboard; + + public MediaScreen(String text, Media media) { + this(text, media, null); + } + +} diff --git a/stbf-demo/src/main/resources/flow.xml b/stbf-demo/src/main/resources/flow.xml index ac2d8d7..f62d0e0 100644 --- a/stbf-demo/src/main/resources/flow.xml +++ b/stbf-demo/src/main/resources/flow.xml @@ -1,11 +1,18 @@ + + Start Help Inline - Inline button #1 - Inline button #2 - Git repo + πŸ”ž Inline button #1 + 🐱 Inline button #2 + πŸ’» Git repo + πŸ–Ό My photo + 🎞 My video + πŸ”™ Back @@ -35,6 +42,10 @@ + + + + @@ -47,6 +58,10 @@ + + + + @@ -59,17 +74,40 @@ + + + + + + My photo + + + + + + + + My Video + + + + + + - - + + + + + \ No newline at end of file diff --git a/stbf-pengrad/src/main/java/ru/penkrat/stbf/impl/pengrad/BotResponseImpl.java b/stbf-pengrad/src/main/java/ru/penkrat/stbf/impl/pengrad/BotResponseImpl.java index e90c931..fd7fb4e 100644 --- a/stbf-pengrad/src/main/java/ru/penkrat/stbf/impl/pengrad/BotResponseImpl.java +++ b/stbf-pengrad/src/main/java/ru/penkrat/stbf/impl/pengrad/BotResponseImpl.java @@ -7,10 +7,10 @@ import com.pengrad.telegrambot.model.request.InlineKeyboardMarkup; import com.pengrad.telegrambot.model.request.KeyboardButton; import com.pengrad.telegrambot.model.request.ParseMode; import com.pengrad.telegrambot.model.request.ReplyKeyboardMarkup; +import com.pengrad.telegrambot.request.AbstractSendRequest; import com.pengrad.telegrambot.request.DeleteMessage; import com.pengrad.telegrambot.request.EditMessageText; import com.pengrad.telegrambot.request.SendDocument; -import com.pengrad.telegrambot.request.SendMessage; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import ru.penkrat.stbf.api.BotResponse; @@ -28,10 +28,7 @@ public class BotResponseImpl implements BotResponse { public void send(Screen screen) { log.debug("Send message: \n============\n{}\n============", screen.getText().trim()); - SendMessage sendMessage = new SendMessage(chatId(), screen.getText().trim()) - .parseMode(screen.getScreenProperties().isParseModeHtml() ? ParseMode.HTML : ParseMode.MarkdownV2) - .disableWebPagePreview(screen.getScreenProperties().isDisableWebPagePreview()) - .disableNotification(screen.getScreenProperties().isDisableNotification()); + AbstractSendRequest sendMessage= SendMethodUtils.createFromScreen(chatId(), screen); if (screen.getKeyboard() instanceof KeyboardImpl) { KeyboardImpl kk = (KeyboardImpl) screen.getKeyboard(); diff --git a/stbf-pengrad/src/main/java/ru/penkrat/stbf/impl/pengrad/SendMethodUtils.java b/stbf-pengrad/src/main/java/ru/penkrat/stbf/impl/pengrad/SendMethodUtils.java new file mode 100644 index 0000000..85b8836 --- /dev/null +++ b/stbf-pengrad/src/main/java/ru/penkrat/stbf/impl/pengrad/SendMethodUtils.java @@ -0,0 +1,58 @@ +package ru.penkrat.stbf.impl.pengrad; + +import com.pengrad.telegrambot.model.request.ParseMode; +import com.pengrad.telegrambot.request.AbstractSendRequest; +import com.pengrad.telegrambot.request.SendMessage; +import com.pengrad.telegrambot.request.SendPhoto; +import com.pengrad.telegrambot.request.SendVideo; +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import ru.penkrat.stbf.api.Media; +import ru.penkrat.stbf.api.Screen; + +import java.util.function.Function; + +@UtilityClass +class SendMethodUtils { + + public AbstractSendRequest createFromScreen(@NonNull Object chatId, @NonNull Screen screen) { + if (isMedia(screen)) { + final Media media = screen.getMedia(); + switch (media.getMediaType()) { + case PHOTO: + final SendPhoto sendPhoto = new SendPhoto(chatId, media.getUrl()); + apply(sendPhoto, sendPhoto::caption, screen.getText()); + sendPhoto.parseMode(screen.getScreenProperties().isParseModeHtml() + ? ParseMode.HTML + : ParseMode.MarkdownV2); + return sendPhoto; + case VIDEO: + final SendVideo sendVideo = new SendVideo(chatId, media.getUrl()); + apply(sendVideo, sendVideo::caption, screen.getText()); + apply(sendVideo, sendVideo::width, media.getWidth()); + apply(sendVideo, sendVideo::height, media.getHeight()); + apply(sendVideo, sendVideo::duration, media.getDuration()); + sendVideo.parseMode(screen.getScreenProperties().isParseModeHtml() + ? ParseMode.HTML + : ParseMode.MarkdownV2); + return sendVideo; + } + } + + return new SendMessage(chatId, screen.getText().trim()) + .parseMode(screen.getScreenProperties().isParseModeHtml() ? ParseMode.HTML : ParseMode.MarkdownV2) + .disableWebPagePreview(screen.getScreenProperties().isDisableWebPagePreview()) + .disableNotification(screen.getScreenProperties().isDisableNotification()); + } + + private boolean isMedia(Screen screen) { + return screen.getMedia() != null; + } + + private T apply(T target, Function setter, V value) { + if (value != null) { + setter.apply(value); + } + return target; + } +} diff --git a/stbf-templates/README.MD b/stbf-templates/README.MD index 4348d6e..1b4445d 100644 --- a/stbf-templates/README.MD +++ b/stbf-templates/README.MD @@ -7,6 +7,7 @@ + ``` @@ -51,6 +52,8 @@ Screen - Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ Π±ΠΎΡ‚ ΠΎΡ‚Π²Π΅Ρ‚ΠΈΡ‚ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ, ΠΎΠ±Ρ‹Ρ‡Π½ ``` +`mediaRef` - ссылка Π½Π° элСмСнт ΠΌΠ΅Π΄ΠΈΠ°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠΏΡ€Π°Π²Π»Π΅Π½ Π±ΠΎΡ‚ΠΎΠΌ + `text` - Π²Ρ‹Π²ΠΎΠ΄ΠΈΠΌΡ‹ΠΉ тСкст `keyboard` - описаниС ΠΊΠ»Π°Π²ΠΈΠ°Ρ‚ΡƒΡ€Ρ‹ @@ -65,7 +68,7 @@ Screen - Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ Π±ΠΎΡ‚ ΠΎΡ‚Π²Π΅Ρ‚ΠΈΡ‚ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ, ΠΎΠ±Ρ‹Ρ‡Π½ #### Button -`if` - Π²ΠΈΠ΄ΠΎΠΌΠΎΡΡ‚ΡŒ ΠΊΠ½ΠΎΠΏΠΊΠΈ, Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ `true`, `false` ΠΈΠ»ΠΈ имя ΠΌΠ΅Ρ‚ΠΎΠ΄Π° ΠΈΠ· контСкста экрана (для ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½ΠΎΠΉ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ) +`if` - Π²ΠΈΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ ΠΊΠ½ΠΎΠΏΠΊΠΈ, Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ `true`, `false` ΠΈΠ»ΠΈ имя ΠΌΠ΅Ρ‚ΠΎΠ΄Π° ΠΈΠ· контСкста экрана (для ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½ΠΎΠΉ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ) `actionRef` - `id` ΠΈΠ»ΠΈ `name` action, описанный Π² ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΠ²ΡƒΡŽΡ‰Π΅ΠΉ сСкции @@ -89,4 +92,21 @@ Screen - Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ Π±ΠΎΡ‚ ΠΎΡ‚Π²Π΅Ρ‚ΠΈΡ‚ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ, ΠΎΠ±Ρ‹Ρ‡Π½ ``` `actionRef` - ссылка Π½Π° action, ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ id ΠΈΠ»ΠΈ name -`screenRef` - ссылка Π½Π° screen, ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ id ΠΈΠ»ΠΈ name \ No newline at end of file + +`screenRef` - ссылка Π½Π° screen, ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ id ΠΈΠ»ΠΈ name + +`edit` = `true|false`- исходноС сообщСниС Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΎ (Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½ΠΎ для callback) + +`replace` = `true|false`- исходноС сообщСниС Π±ΡƒΠ΄Π΅Ρ‚ ΡƒΠ΄Π°Π»Π΅Π½ΠΎ, ΠΈ ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½ΠΎ Π½ΠΎΠ²ΠΎΠ΅ (Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½ΠΎ для callback, +Ссли мСняСтся Ρ‚ΠΈΠΏ сообщСния Ρ‚.Π΅. сообщСниС с Ρ„ΠΎΡ‚ΠΎ, Π²ΠΈΠ΄Π΅ΠΎ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ Π·Π°ΠΌΠ΅Π½Π΅Π½ΠΎ Π½Π° тСкстовоС ΠΈ Π½Π°ΠΎΠ±ΠΎΡ€ΠΎΡ‚) + +### Media + +ΠžΠΏΠΈΡΡ‹Π²Π°Π΅Ρ‚ ΠΌΠ΅Π΄ΠΈΠ°-рСсурсы, доступныС для ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠΈ Π±ΠΎΡ‚ΠΎΠΌ + +```xml + + +``` \ No newline at end of file diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/MediaResolver.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/MediaResolver.java new file mode 100644 index 0000000..e76d869 --- /dev/null +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/MediaResolver.java @@ -0,0 +1,9 @@ +package ru.penkrat.stbf.templates; + +import ru.penkrat.stbf.api.Media; + +public interface MediaResolver { + + Media getMedia(String name); + +} diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/CommandItem.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/CommandItem.java index 43d511d..bcd90b5 100644 --- a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/CommandItem.java +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/CommandItem.java @@ -24,4 +24,7 @@ public class CommandItem extends NamedItem { @JacksonXmlProperty(isAttribute = true) private boolean edit; + @JacksonXmlProperty(isAttribute = true) + private boolean replace; + } diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowCommandResolverDelegate.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowCommandResolverDelegate.java index d6d3663..ebe8e39 100644 --- a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowCommandResolverDelegate.java +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowCommandResolverDelegate.java @@ -62,19 +62,22 @@ public class FlowCommandResolverDelegate implements CommandResolver { screenFactory = screenResolver.getScreenFactory(commandItem.getScreenRef()); } if (actionMatcher != null && screen != null) { - return simpleCommand(actionMatcher, screen, commandItem.isEdit(), commandItem.getId(), commandItem.getName()); + return simpleCommand(actionMatcher, screen, commandItem.isEdit(), commandItem.isReplace(), commandItem.getId(), commandItem.getName()); } return null; } - private Command simpleCommand(RequestMatcher matcher, Screen screen, boolean edit, String id, String name) { + private Command simpleCommand(RequestMatcher matcher, Screen screen, boolean edit, boolean replace, String id, String name) { return new Command() { @Override public void process(BotRequest botRequest, BotResponse botResponse, CommandChain chain) { if (matcher.match(botRequest)) { - if (edit) { + if (replace) { + botResponse.deleteMessage(); + } + if (edit && !replace) { botResponse.edit(screen); } else { botResponse.send(screen); diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowMediaResolverDelegate.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowMediaResolverDelegate.java new file mode 100644 index 0000000..a8e8ed9 --- /dev/null +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowMediaResolverDelegate.java @@ -0,0 +1,58 @@ +package ru.penkrat.stbf.templates.xml; + +import ru.penkrat.stbf.api.Media; +import ru.penkrat.stbf.api.MediaType; +import ru.penkrat.stbf.templates.MediaResolver; + +import java.util.Collection; +import java.util.Optional; + +class FlowMediaResolverDelegate implements MediaResolver { + + private final NamedItemResolver videosResolver; + private final NamedItemResolver photosResolver; + + FlowMediaResolverDelegate(FlowRoot src) { + videosResolver = new NamedItemResolver<>(Traversal.traverse(src, FlowMediaResolverDelegate::videos)); + photosResolver = new NamedItemResolver<>(Traversal.traverse(src, FlowMediaResolverDelegate::photos)); + } + + @Override + public Media getMedia(String name) { + Optional media = videosResolver.getOpt(name) + .map(FlowMediaResolverDelegate::toVideo); + if(media.isPresent()){ + return media.get(); + } + + media = photosResolver.getOpt(name) + .map(FlowMediaResolverDelegate::toPhoto); + if(media.isPresent()){ + return media.get(); + } + + throw new IllegalStateException("MediaElement not found by 'id' or 'name' " + name); + } + + private static Media toVideo(MediaItem item) { + return Media.builder() + .mediaType(MediaType.VIDEO) + .url(item.getUrl()) + .build(); + } + + private static Media toPhoto(MediaItem item) { + return Media.builder() + .mediaType(MediaType.PHOTO) + .url(item.getUrl()) + .build(); + } + + private static Collection videos(FlowRoot root) { + return root.getMedia().getVideos(); + } + + private static Collection photos(FlowRoot root) { + return root.getMedia().getPhotos(); + } +} diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowRoot.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowRoot.java index 16aeeb0..5ad43fa 100644 --- a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowRoot.java +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowRoot.java @@ -31,6 +31,10 @@ class FlowRoot { @JsonProperty("command") private List commands = new ArrayList<>(); + @Getter + @JsonProperty("media") + private MediaRoot media = new MediaRoot(); + @Getter private transient List included = new ArrayList<>(); } diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowScreenResolverDelegate.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowScreenResolverDelegate.java index f0c595c..94bce15 100644 --- a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowScreenResolverDelegate.java +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/FlowScreenResolverDelegate.java @@ -6,10 +6,13 @@ import lombok.val; import ru.penkrat.stbf.api.Action; import ru.penkrat.stbf.api.Keyboard; import ru.penkrat.stbf.api.KeyboardBuilder; +import ru.penkrat.stbf.api.Media; import ru.penkrat.stbf.api.Screen; +import ru.penkrat.stbf.common.screen.MediaScreen; import ru.penkrat.stbf.common.screen.TextScreen; import ru.penkrat.stbf.templates.ActionResolver; import ru.penkrat.stbf.templates.KeyboardProvider; +import ru.penkrat.stbf.templates.MediaResolver; import ru.penkrat.stbf.templates.ScreenResolver; import ru.penkrat.stbf.templates.TemplateRenderer; import ru.penkrat.stbf.templates.utils.ReflectionUtils; @@ -25,11 +28,14 @@ class FlowScreenResolverDelegate implements ScreenResolver { private final ActionResolver actionResolver; + private final MediaResolver mediaResolver; + @Setter private TemplateRenderer templateRenderer = new NoopTemplateRenderer(); - FlowScreenResolverDelegate(FlowRoot src, ActionResolver actionResolver) { + FlowScreenResolverDelegate(FlowRoot src, ActionResolver actionResolver, MediaResolver mediaResolver) { this.actionResolver = actionResolver; + this.mediaResolver = mediaResolver; resolver = new NamedItemResolver<>(Traversal.traverse(src, FlowRoot::getScreens)); } @@ -37,6 +43,11 @@ class FlowScreenResolverDelegate implements ScreenResolver { public Screen getScreen(String name) { ScreenItem item = resolver.get(name); + if (StringUtils.isNotEmpty(item.getMediaRef())) { + final Media media = mediaResolver.getMedia(item.getMediaRef()); + return new MediaScreen(item.getText(), media, buildKeyboard(item.getKeyboard(), null)); + } + return new TextScreen(item.getText(), buildKeyboard(item.getKeyboard(), null)); } @@ -44,6 +55,12 @@ class FlowScreenResolverDelegate implements ScreenResolver { public Screen getScreen(String name, Object context) { ScreenItem item = resolver.get(name); + if (StringUtils.isNotEmpty(item.getMediaRef())) { + final Media media = mediaResolver.getMedia(item.getMediaRef()); + return new MediaScreen(templateRenderer.render(item.getText(), context), media, + resolveKeyboard(item.getKeyboard(), context)); + } + return new TextScreen(templateRenderer.render(item.getText(), context), resolveKeyboard(item.getKeyboard(), context)); } diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/MediaItem.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/MediaItem.java new file mode 100644 index 0000000..55fe7e9 --- /dev/null +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/MediaItem.java @@ -0,0 +1,14 @@ +package ru.penkrat.stbf.templates.xml; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class MediaItem extends NamedItem { + + @JacksonXmlProperty(isAttribute = true) + private String url; + +} diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/MediaRoot.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/MediaRoot.java new file mode 100644 index 0000000..7c27c89 --- /dev/null +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/MediaRoot.java @@ -0,0 +1,21 @@ +package ru.penkrat.stbf.templates.xml; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.List; + +public class MediaRoot { + + @Getter + @JacksonXmlElementWrapper(useWrapping = false) + @JsonProperty("video") + private List videos = new ArrayList<>(); + + @Getter + @JacksonXmlElementWrapper(useWrapping = false) + @JsonProperty("photo") + private List photos = new ArrayList<>(); +} diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/NamedItemResolver.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/NamedItemResolver.java index d10418a..509bc45 100644 --- a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/NamedItemResolver.java +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/NamedItemResolver.java @@ -5,6 +5,7 @@ import ru.penkrat.stbf.templates.utils.StringUtils; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; class NamedItemResolver { @@ -39,4 +40,22 @@ class NamedItemResolver { throw new IllegalStateException("Element not found by 'id' or 'name' " + key); } + Optional getOpt(String key) { + List list = byId.get(key); + if (list != null) { + if (list.size() > 1) { + throw new IllegalStateException("Non unique 'id' " + key); + } + return Optional.of(list.get(0)); + } + list = byName.get(key); + if (list != null) { + if (list.size() > 1) { + throw new IllegalStateException("Non unique 'name' " + key); + } + return Optional.of(list.get(0)); + } + return Optional.empty(); + } + } diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/ScreenItem.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/ScreenItem.java index 26a2674..23840af 100644 --- a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/ScreenItem.java +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/ScreenItem.java @@ -1,5 +1,6 @@ package ru.penkrat.stbf.templates.xml; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import lombok.Getter; import lombok.Setter; @@ -9,6 +10,9 @@ class ScreenItem extends NamedItem { private String text; + @JacksonXmlProperty(isAttribute = true) + private String mediaRef; + private KeyboardWrapper keyboard = new KeyboardWrapper(); } diff --git a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/XmlFlowResolver.java b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/XmlFlowResolver.java index 8230b93..bcd1247 100644 --- a/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/XmlFlowResolver.java +++ b/stbf-templates/src/main/java/ru/penkrat/stbf/templates/xml/XmlFlowResolver.java @@ -18,18 +18,21 @@ public class XmlFlowResolver implements FlowResolver { private final FlowActionResolverDelegate actionDelegate; private final FlowScreenResolverDelegate screenDelegate; private final FlowCommandResolverDelegate commandResolver; + private final FlowMediaResolverDelegate mediaResolver; public XmlFlowResolver(String filename) { FlowRoot flow = reader.read(filename); actionDelegate = new FlowActionResolverDelegate(flow); - screenDelegate = new FlowScreenResolverDelegate(flow, this); + mediaResolver = new FlowMediaResolverDelegate(flow); + screenDelegate = new FlowScreenResolverDelegate(flow, this, mediaResolver); commandResolver = new FlowCommandResolverDelegate(flow, actionDelegate, screenDelegate); } public XmlFlowResolver(InputStream is) { FlowRoot flow = reader.read(is); actionDelegate = new FlowActionResolverDelegate(flow); - screenDelegate = new FlowScreenResolverDelegate(flow, this); + mediaResolver = new FlowMediaResolverDelegate(flow); + screenDelegate = new FlowScreenResolverDelegate(flow, this, mediaResolver); commandResolver = new FlowCommandResolverDelegate(flow, actionDelegate, screenDelegate); } diff --git a/stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/XmlWriterTest.java b/stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/XmlWriterTest.java index 2c1f86b..f5e21a9 100644 --- a/stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/XmlWriterTest.java +++ b/stbf-templates/src/test/java/ru/penkrat/stbf/templates/xml/XmlWriterTest.java @@ -2,6 +2,7 @@ package ru.penkrat.stbf.templates.xml; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import lombok.val; import org.junit.Before; import org.junit.Test; import ru.penkrat.stbf.api.Command; @@ -42,6 +43,7 @@ public class XmlWriterTest { item2.setId("2"); item2.setName("screen-2"); item2.setText("Hello, {{ name }}"); + item2.setMediaRef("12"); item2.getKeyboard().setFactoryMethod("getKeyboard"); @@ -58,6 +60,16 @@ public class XmlWriterTest { commandItem.setClazz(Command.class.getCanonicalName()); root.getCommands().add(commandItem); + + MediaItem video1 = new MediaItem(); + video1.setId("11"); + video1.setUrl("https://example.com/test.mpg"); + MediaItem photo1 = new MediaItem(); + photo1.setId("12"); + photo1.setUrl("https://example.com/test.jpg"); + root.getMedia().getVideos().add(video1); + root.getMedia().getPhotos().add(photo1); + String xml = mapper.writeValueAsString(root); System.out.println(xml);