Skip to content

Commit

Permalink
Imperative version, but it kinda works.
Browse files Browse the repository at this point in the history
  • Loading branch information
davesmith00000 committed Mar 31, 2024
1 parent da538e6 commit b36ba6b
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 15 deletions.
65 changes: 53 additions & 12 deletions tyrian/js/src/main/scala/tyrian/runtime/Renderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,69 @@ package tyrian.runtime
import cats.effect.kernel.Async
import cats.effect.kernel.Ref
import cats.effect.syntax.all.*
import org.scalajs.dom
import snabbdom.VNode
import tyrian.Html
import tyrian.Location

final case class Renderer(vnode: VNode, state: RendererState, lastTriggered: Long):
import scala.scalajs.js.Date

final case class Renderer(vnode: VNode, state: RendererState, lastTriggered: Long, runningTime: Long)

object Renderer:

def init[F[_]](vnode: VNode)(using F: Async[F]): F[Ref[F, Renderer]] =
F.ref(
Renderer(vnode, RendererState.Idle, 0, 0)
)

@SuppressWarnings(Array("scalafix:DisableSyntax.var", "scalafix:DisableSyntax.null"))
var renderer: Renderer = null
val timeout: Long = 1000

def render[Model, Msg](
model: Model,
view: Model => Html[Msg],
onMsg: Msg => Unit,
router: Location => Msg
)(t: Long): Unit =
// t is the running time, last triggered is the epoch. What to do?
// println(s"render $t - ${renderer.lastTriggered} >= $timeout = ${t - renderer.lastTriggered > 2000}")
if t - renderer.lastTriggered >= timeout then
renderer = renderer.copy(
state = RendererState.Idle,
runningTime = t
)
()
else
renderer = renderer.copy(
vnode = Rendering.render(renderer.vnode, model, view, onMsg, router),
state = RendererState.Running,
runningTime = t
)
dom.window.requestAnimationFrame(_ => render(model, view, onMsg, router)(Date.now().toLong))
()

// This function gets called on every model update
@SuppressWarnings(Array("scalafix:DisableSyntax.null"))
def redraw[Model, Msg](
time: Long,
r: Renderer,
model: Model,
view: Model => Html[Msg],
onMsg: Msg => Unit,
router: Location => Msg
): Renderer =
this.copy(
vnode = Rendering.render(vnode, model, view, onMsg, router), // TODO: Replace
state = RendererState.Running,
lastTriggered = time
)
// Sadly, need to do a null check for now.
if renderer == null then renderer = r

object Renderer:
renderer.state match
case RendererState.Idle =>
// If the render state is idle, begin.
renderer = renderer.copy(lastTriggered = Date.now().toLong)
dom.window.requestAnimationFrame(_ => render(model, view, onMsg, router)(Date.now().toLong))
renderer

def init[F[_]](vnode: VNode)(using F: Async[F]): F[Ref[F, Renderer]] =
F.ref(
Renderer(vnode, RendererState.Idle, 0)
)
case RendererState.Running =>
// If the render state is running, just update the triggered time.
renderer = renderer.copy(lastTriggered = Date.now().toLong)
renderer
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package tyrian.runtime

enum RendererState:
enum RendererState derives CanEqual:
case Idle, Running
3 changes: 1 addition & 2 deletions tyrian/js/src/main/scala/tyrian/runtime/TyrianRuntime.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ object TyrianRuntime:

_ <- runCmd(cmdsAndSubs._1) *> runSub(cmdsAndSubs._2)
m <- model.get
t <- clock.realTime.map(_.toMillis)
_ <- renderer.update(_.redraw(t, m, view, onMsg, router))
_ <- renderer.update(r => Renderer.redraw(r, m, view, onMsg, router)) // Renderer update not needed...
} yield ()
}.foreverM

Expand Down

0 comments on commit b36ba6b

Please sign in to comment.