package net.pterodactylus.rhynodge.filters.webpages.epicgames
+import kotlinx.html.body
+import kotlinx.html.div
+import kotlinx.html.dom.createHTMLDocument
+import kotlinx.html.dom.serialize
+import kotlinx.html.head
+import kotlinx.html.html
+import kotlinx.html.img
+import kotlinx.html.style
+import kotlinx.html.unsafe
import net.pterodactylus.rhynodge.states.AbstractState
+import java.time.ZoneId
+import java.util.Comparator.comparing
-class FreeGamesState(val games: Set<FreeGame>, private val triggered: Boolean = false) : AbstractState(true) {
+class FreeGamesState(val games: Set<FreeGame>, private val triggered: Boolean = false, private val timezone: ZoneId = ZoneId.systemDefault()) : AbstractState(true) {
- override fun plainText(): String {
- TODO("Not yet implemented")
- }
+ override fun plainText() = games
+ .sortedWith(comparing(FreeGame::startDate).thenBy(FreeGame::title))
+ .joinToString("\n") { game ->
+ "${game.title}: ${"%tF %<tT".format(game.startDate.atZone(timezone))} - ${"%tF %<tT".format(game.endDate.atZone(timezone))} (${game.imageUrl})"
+ }
+
+ override fun htmlText() = createHTMLDocument().html {
+ head {
+ style("text/css") {
+ unsafe {
+ raw(
+ """
+ .game { display: inline-grid; width: 200px; height: 350px; grid-template-rows: 0fr 1fr 0fr 0fr; font-family: 'Recursive Sans Linear Static', Roboto, serif; color: white; text-shadow: 2px 2px black; margin: 0 1ex 1ex 0; }
+ .game .game-image { grid-area: 1/1/5/2; }
+ .game .game-image img { object-fit: cover; width: 100%; height: 100%; }
+ .game .game-title { grid-area: 1/1/2/2; padding: 1ex; font-size: 150%; font-weight: bold; }
+ .game .game-start { grid-area: 3/1/4/2; padding: 1ex 1ex 0ex 1ex; }
+ .game .game-end { grid-area: 4/1/5/2; padding: 0ex 1ex 1ex 1ex; }
+ """
+ )
+ }
+ }
+ }
+ body {
+ div("games") {
+ games
+ .sortedWith(comparing(FreeGame::startDate).thenBy(FreeGame::title))
+ .forEach { game ->
+ div("game") {
+ div("game-image") {
+ img(src = game.imageUrl)
+ }
+ div("game-title") {
+ +game.title
+ }
+ div("game-start") {
+ +"%tF %<tT".format(game.startDate.atZone(timezone))
+ }
+ div("game-end") {
+ +"%tF %<tT".format(game.endDate.atZone(timezone))
+ }
+ }
+ }
+ }
+ }
+ }.serialize(prettyPrint = true)
override fun triggered() = triggered
--- /dev/null
+package net.pterodactylus.rhynodge.filters.webpages.epicgames
+
+import net.pterodactylus.rhynodge.Reaction
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.Matchers.contains
+import org.hamcrest.Matchers.equalTo
+import org.jsoup.Jsoup
+import org.junit.Test
+import java.time.Instant
+import java.time.ZoneOffset
+
+class FreeGamesStateTest {
+
+ @Test
+ fun `can create free games state`() {
+ FreeGamesState(emptySet())
+ }
+
+ @Test
+ fun `state lists all games in text output`() {
+ val output = state.output(Reaction("", null, null, null)).text("text/plain")
+ assertThat(
+ output, equalTo(
+ listOf(
+ "Good Game: 1970-01-01 00:16:40 - 1970-01-01 00:33:20 (https://good.game/image.jpg)",
+ "Best Game: 1970-01-01 00:33:20 - 1970-01-01 00:50:00 (https://best.game/image.webp)",
+ "Better Game: 1970-01-01 00:50:00 - 1970-01-01 01:06:40 (https://better.game/image.png)",
+ ).joinToString("\n")
+ )
+ )
+ }
+
+ @Test
+ fun `state lists all games in HTML output`() {
+ val output = state.output(Reaction("", null, null, null)).text("text/html")
+ val parsedOutput = Jsoup.parse(output)
+ assertThat(
+ parsedOutput.select(".game").map {
+ listOf(
+ it.select(".game-title").text(),
+ it.select(".game-image img").attr("src"),
+ it.select(".game-start").text(),
+ it.select(".game-end").text()
+ ).joinToString(", ")
+ }, contains(
+ "Good Game, https://good.game/image.jpg, 1970-01-01 00:16:40, 1970-01-01 00:33:20",
+ "Best Game, https://best.game/image.webp, 1970-01-01 00:33:20, 1970-01-01 00:50:00",
+ "Better Game, https://better.game/image.png, 1970-01-01 00:50:00, 1970-01-01 01:06:40",
+ )
+ )
+ }
+
+}
+
+private val freeGames = setOf(
+ FreeGame("Good Game", "https://good.game/image.jpg", Instant.ofEpochSecond(1000), Instant.ofEpochSecond(2000)),
+ FreeGame("Better Game", "https://better.game/image.png", Instant.ofEpochSecond(3000), Instant.ofEpochSecond(4000)),
+ FreeGame("Best Game", "https://best.game/image.webp", Instant.ofEpochSecond(2000), Instant.ofEpochSecond(3000)),
+)
+private val state = FreeGamesState(freeGames, timezone = ZoneOffset.UTC)