Skip to content

Commit 58d0b9c

Browse files
committed
begin moving to js based timer countdown
1 parent 15858b6 commit 58d0b9c

File tree

3 files changed

+127
-53
lines changed

3 files changed

+127
-53
lines changed

assets/js/app.js

+63-4
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,74 @@
1818
// Include phoenix_html to handle method=PUT/DELETE in forms and buttons.
1919
import "phoenix_html"
2020
// Establish Phoenix Socket and LiveView configuration.
21-
import {Socket} from "phoenix"
22-
import {LiveSocket} from "phoenix_live_view"
21+
import { Socket } from "phoenix"
22+
import { LiveSocket } from "phoenix_live_view"
2323
import topbar from "../vendor/topbar"
2424

25+
// if the duration is zero, return "done"
26+
// if the duration is less than a minute, return "{seconds}s"
27+
// if the duration is less than an hour, return "{minutes}m {seconds}s"
28+
// if the duration is less than a day, return "{hours}h {minutes}m {seconds}s"
29+
// if the duration is less than a year, return "{days}d {hours}h {minutes}m {seconds}s"
30+
function formatDuration(seconds) {
31+
if (seconds === 0) {
32+
return "done"
33+
}
34+
35+
let minutes = Math.floor(seconds / 60)
36+
let hours = Math.floor(minutes / 60)
37+
let days = Math.floor(hours / 24)
38+
let years = Math.floor(days / 365)
39+
40+
if (years > 0) {
41+
return `${years}y ${days % 365}d ${hours % 24}h ${minutes % 60}m ${seconds % 60}s`
42+
} else if (days > 0) {
43+
return `${days}d ${hours % 24}h ${minutes % 60}m ${seconds % 60}s`
44+
} else if (hours > 0) {
45+
return `${hours}h ${minutes % 60}m ${seconds % 60}s`
46+
} else if (minutes > 0) {
47+
return `${minutes}m ${seconds % 60}s`
48+
} else {
49+
return `${seconds}s`
50+
}
51+
52+
}
53+
54+
let Hooks = {}
55+
56+
Hooks.Countdown = {
57+
tick() {
58+
let seconds = Math.floor((this.target - new Date()) / 1000)
59+
if (seconds <= 0) {
60+
this.el.innerHTML = "done"
61+
pushEvent("update_timers", this.el, {})
62+
return
63+
} else {
64+
this.el.innerHTML = formatDuration(seconds)
65+
this.timeout = setTimeout(() => this.tick(), 1000)
66+
}
67+
},
68+
mounted() {
69+
this.target = new Date(this.el.dataset.target)
70+
this.tick()
71+
},
72+
destroyed() {
73+
clearTimeout(this.timeout)
74+
},
75+
updated() {
76+
clearTimeout(this.timeout)
77+
this.mounted()
78+
}
79+
}
80+
2581
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
26-
let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}})
82+
let liveSocket = new LiveSocket("/live", Socket, {
83+
params: { _csrf_token: csrfToken },
84+
hooks: Hooks
85+
})
2786

2887
// Show progress bar on live navigation and form submits
29-
topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"})
88+
topbar.config({ barColors: { 0: "#29d" }, shadowColor: "rgba(0, 0, 0, .3)" })
3089
window.addEventListener("phx:page-loading-start", _info => topbar.show(300))
3190
window.addEventListener("phx:page-loading-stop", _info => topbar.hide())
3291

lib/galaxies/planets.ex

+2-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ defmodule Galaxies.Planets do
6363
add_resources(planet_id, -cost_metal, -cost_crystal, -cost_deuterium)
6464

6565
# TODO: replace with a real formula
66-
construction_duration_seconds = level + 1
66+
construction_duration_seconds = :math.pow(level, 2) |> trunc()
6767

6868
event_id = Ecto.UUID.generate()
6969
now = DateTime.utc_now(:second)
@@ -336,6 +336,7 @@ defmodule Galaxies.Planets do
336336
else
337337
Repo.all(from pb in PlanetBuilding, where: pb.planet_id == ^planet.id)
338338
end
339+
339340
check_prerequisites(prereqs, player_researches, planet_buildings)
340341
end
341342
end

lib/galaxies_web/live/resources_live.ex

+62-48
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,11 @@ defmodule GalaxiesWeb.ResourcesLive do
1111
_ = Planets.process_planet_events(socket.assigns.current_planet.id)
1212
build_queue = Planets.get_building_queue(socket.assigns.current_planet.id)
1313
planet_buildings = Accounts.get_planet_resource_buildings(socket.assigns.current_planet)
14-
building_timers = timers_from_build_queue(build_queue)
15-
schedule_next_timer_update()
1614

1715
{:ok,
1816
socket
1917
|> assign(:build_queue, build_queue)
20-
|> assign(:planet_buildings, planet_buildings)
21-
|> assign(:building_timers, building_timers)}
18+
|> assign(:planet_buildings, planet_buildings)}
2219
end
2320

2421
defp timers_from_build_queue([]), do: %{}
@@ -80,7 +77,13 @@ defmodule GalaxiesWeb.ResourcesLive do
8077
{hd(@build_queue).level}
8178
</td>
8279
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
83-
{format_timer(@building_timers[hd(@build_queue).building_id])}
80+
<span
81+
id="build-queue-countdown"
82+
phx-hook="Countdown"
83+
data-target={hd(@build_queue).completed_at}
84+
>
85+
{hd(@build_queue).completed_at}
86+
</span>
8487
</td>
8588
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 lg:pr-8">
8689
<a href="#" class="text-indigo-600 hover:text-indigo-900">
@@ -159,43 +162,54 @@ defmodule GalaxiesWeb.ResourcesLive do
159162
"""
160163
end
161164

162-
def handle_info(:update_timers, socket) do
163-
num_timers = Enum.count(socket.assigns.building_timers)
164-
165-
building_timers =
166-
socket.assigns.building_timers
167-
|> Enum.reduce(%{}, fn
168-
{_building_id, secs}, acc when secs <= 1 ->
169-
acc
170-
171-
{building_id, seconds}, acc ->
172-
Map.put(acc, building_id, seconds - 1)
173-
end)
174-
175-
socket =
176-
if Enum.count(building_timers) != num_timers do
177-
# building timer reached zero, meaning some building was upgraded
178-
# re-fetch planet_buildings building queue and update building timers
179-
current_planet = socket.assigns.current_planet
180-
_ = Planets.process_planet_events(current_planet.id)
181-
build_queue = Planets.get_building_queue(current_planet.id)
182-
planet_buildings = Accounts.get_planet_resource_buildings(current_planet)
183-
184-
building_timers = timers_from_build_queue(build_queue)
185-
186-
socket
187-
|> assign(:build_queue, build_queue)
188-
|> assign(:building_timers, building_timers)
189-
|> assign(:planet_buildings, planet_buildings)
190-
else
191-
socket
192-
|> assign(:building_timers, building_timers)
193-
end
194-
195-
# no need for periodic ticks if the current building timers Map is empty
196-
unless Enum.empty?(socket.assigns.building_timers) do
197-
schedule_next_timer_update()
198-
end
165+
def handle_info(event, socket) when event in [:update_timers, "update_timers"] do
166+
dbg(:ping)
167+
168+
# building timer reached zero, meaning some building was upgraded
169+
# re-fetch planet_buildings building queue and update building timers
170+
current_planet = socket.assigns.current_planet
171+
_ = Planets.process_planet_events(current_planet.id)
172+
build_queue = Planets.get_building_queue(current_planet.id)
173+
174+
socket
175+
|> assign(:build_queue, build_queue)
176+
177+
# num_timers = Enum.count(socket.assigns.building_timers)
178+
179+
# building_timers =
180+
# socket.assigns.building_timers
181+
# |> Enum.reduce(%{}, fn
182+
# {_building_id, secs}, acc when secs <= 1 ->
183+
# acc
184+
185+
# {building_id, seconds}, acc ->
186+
# Map.put(acc, building_id, seconds - 1)
187+
# end)
188+
189+
# socket =
190+
# if Enum.count(building_timers) != num_timers do
191+
# # building timer reached zero, meaning some building was upgraded
192+
# # re-fetch planet_buildings building queue and update building timers
193+
# current_planet = socket.assigns.current_planet
194+
# _ = Planets.process_planet_events(current_planet.id)
195+
# build_queue = Planets.get_building_queue(current_planet.id)
196+
# planet_buildings = Accounts.get_planet_resource_buildings(current_planet)
197+
198+
# building_timers = timers_from_build_queue(build_queue)
199+
200+
# socket
201+
# |> assign(:build_queue, build_queue)
202+
# |> assign(:building_timers, building_timers)
203+
# |> assign(:planet_buildings, planet_buildings)
204+
# else
205+
# socket
206+
# |> assign(:building_timers, building_timers)
207+
# end
208+
209+
# # no need for periodic ticks if the current building timers Map is empty
210+
# unless Enum.empty?(socket.assigns.building_timers) do
211+
# schedule_next_timer_update()
212+
# end
199213

200214
{:noreply, socket}
201215
end
@@ -222,16 +236,16 @@ defmodule GalaxiesWeb.ResourcesLive do
222236

223237
building_timers = timers_from_build_queue(build_queue)
224238

225-
if Enum.empty?(socket.assigns.building_timers) do
226-
# building timers was previously empty so we need to restart the periodic timer update
227-
schedule_next_timer_update()
228-
end
239+
# if Enum.empty?(socket.assigns.building_timers) do
240+
# # building timers was previously empty so we need to restart the periodic timer update
241+
# # schedule_next_timer_update()
242+
# end
229243

230244
{:noreply,
231245
socket
232246
|> assign(:build_queue, build_queue)
233247
|> assign(:current_planet, current_planet)
234-
|> assign(:building_timers, building_timers)
248+
# |> assign(:building_timers, building_timers)
235249
|> assign(:planet_buildings, planet_buildings)}
236250

237251
{:error, error} ->
@@ -240,7 +254,7 @@ defmodule GalaxiesWeb.ResourcesLive do
240254
end
241255

242256
defp schedule_next_timer_update() do
243-
:erlang.send_after(@timer_update_interval, self(), :update_timers)
257+
# :erlang.send_after(@timer_update_interval, self(), :update_timers)
244258
end
245259

246260
# defp list_replace(list, to_replace, acc \\ [])

0 commit comments

Comments
 (0)