/* Ċ ĠCopyright Ġ 2 0 2 1 ĠSpl endo ĠConsult ing ĠB . V . ĠThe ĠNe therlands ĊĊĠĠĠ ĠLicensed Ġunder Ġthe ĠApache ĠLicense , ĠVersion Ġ 2 . 0 Ġ( the Ġ" License "); ĊĠĠĠ Ġyou Ġmay Ġnot Ġuse Ġthis Ġfile Ġexcept Ġin Ġcompliance Ġwith Ġthe ĠLicense . ĊĠĠĠ ĠYou Ġmay Ġobtain Ġa Ġcopy Ġof Ġthe ĠLicense Ġat ĊĊĠĠĠĠĠ Ġhttp :// www . apache . org / licenses / LICENSE - 2 . 0 ĊĊĠĠĠ ĠUnless Ġrequired Ġby Ġapplicable Ġlaw Ġor Ġagreed Ġto Ġin Ġwriting , Ġsoftware ĊĠĠĠ Ġdistributed Ġunder Ġthe ĠLicense Ġis Ġdistributed Ġon Ġan Ġ" AS ĠIS " ĠBASIS , ĊĠĠĠ ĠWITHOUT ĠWARRANTIES ĠOR ĠCONDITIONS ĠOF ĠANY ĠKIND , Ġeither Ġexpress Ġor Ġimplied . ĊĠĠĠ ĠSee Ġthe ĠLicense Ġfor Ġthe Ġspecific Ġlanguage Ġgoverning Ġpermissions Ġand ĊĠĠĠ Ġlimitations Ġunder Ġthe ĠLicense . ĊĊ Ġ*/ Ċ package Ġcom . spl endo . kal uga . datetime . timer Ċ Ċ import Ġcom . spl endo . kal uga . state . Handle After New State IsSet Ċ import Ġcom . spl endo . kal uga . state . Handle Before Old State Is Removed Ċ import Ġcom . spl endo . kal uga . state . Hot State Flow Repo Ċ import Ġkotlinx . coroutines . Coroutine Scope Ċ import Ġkotlinx . coroutines . Main Scope Ċ import Ġkotlinx . coroutines . Supervisor Job Ċ import Ġkotlinx . coroutines . cancel Children Ċ import Ġkotlinx . coroutines . delay Ċ import Ġkotlinx . coroutines . flow . Flow Ċ import Ġkotlinx . coroutines . flow . State Flow Ċ import Ġkotlinx . coroutines . flow . first Ċ import Ġkotlinx . coroutines . flow . flow Ċ import Ġkotlinx . coroutines . flow . flow Of Ċ import Ġkotlinx . coroutines . launch Ċ import Ġkotlinx . coroutines . with Context Ċ import Ġkotlin . time . Duration Ċ import Ġkotlin . time . Time Source Ċ import Ġcom . spl endo . kal uga . state . K al uga State Ġas ĠKal uga State Ċ Ċ /** ĠA Ġcoroutine Ġdelay Ġfunction . Ġ*/ Ċ type alias ĠDelay Function Ġ= Ġsuspend Ġ( Duration ) Ġ-> ĠUnit Ċ /** Ċ Ġ* ĠTimer Ġbased Ġon Ġthe Ġsystem Ġclock . Ċ Ġ* Ġ@ param Ġduration Ġtimer Ġduration Ċ Ġ* Ġ@ param Ġinterval Ġtimer Ġtick Ġinterval Ċ Ġ* Ġ@ param Ġcoroutine Scope Ġa Ġparent Ġcoroutine Ġscope Ġfor Ġthe Ġtimer Ċ Ġ*/ Ċ class ĠRe cur ring Timer ( ĊĠĠĠ Ġoverride Ġval Ġduration : ĠDuration , ĊĠĠĠ Ġinterval : ĠDuration Ġ= ĠDuration . milliseconds ( 1 0 0 ), ĊĠĠĠ Ġtime Source : ĠTime Source Ġ= ĠTime Source . Mon otonic , ĊĠĠĠ Ġdelay Function : ĠDelay Function Ġ= Ġ{ Ġduration Ġ-> Ġdelay ( duration ) Ġ}, ĊĠĠĠ Ġcoroutine Scope : ĠCor outine Scope Ġ= ĠMain Scope () Ċ ) Ġ: ĠCont rollable Timer Ġ{ ĊĠĠĠ Ġprivate Ġval Ġstate Repo Ġ= ĠTimer State Repo ( duration , Ġinterval , Ġtime Source , Ġdelay Function , Ġcoroutine Scope ) ĊĠĠĠ Ġoverride Ġval Ġstate : ĠState Flow < Timer . State > Ġ= Ġstate Repo . state Flow ĊĊĠĠĠ Ġoverride Ġsuspend Ġfun Ġstart () Ġ= Ġstate Repo . start () ĊĊĠĠĠ Ġoverride Ġsuspend Ġfun Ġpause () Ġ= Ġstate Repo . pause () Ċ } Ċ Ċ /** ĠTimer Ġstate Ġmachine . Ġ*/ Ċ private Ġclass ĠTimer State Repo ( ĊĠĠĠ Ġtotal Duration : ĠDuration , ĊĠĠĠ Ġprivate Ġval Ġinterval : ĠDuration , ĊĠĠĠ Ġprivate Ġval Ġtime Source : ĠTime Source , ĊĠĠĠ Ġprivate Ġval Ġdelay Function : ĠDelay Function , ĊĠĠĠ Ġprivate Ġval Ġcoroutine Scope : ĠCor outine Scope Ċ ) Ġ: ĠHot State Flow Repo < Timer State Repo . State >( ĊĠĠĠ Ġcoroutine Scope . coroutine Context , ĊĠĠĠ Ġ{ ĊĠĠĠĠĠĠĠ ĠState . Not Running . Paused ( elapsed So Far Ġ= ĠDuration . ZERO , Ġtotal Duration Ġ= Ġtotal Duration ) ĊĠĠĠ Ġ} Ċ ) Ġ{ ĊĠĠĠ Ġsuspend Ġfun Ġstart () Ġ{ ĊĠĠĠĠĠĠĠ Ġwith Context ( coroutine Scope . coroutine Context ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtake And Change State Ġ{ Ġstate Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( state ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠState . Not Running . Paused Ġ-> Ġsuspend Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstate . start ( interval , Ġtime Source , Ġdelay Function , Ġcoroutine Scope , Ġ:: finish ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠState . Not Running . Finished , Ġis ĠState . Running Ġ-> Ġstate . remain () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġpause () Ġ{ ĊĠĠĠĠĠĠĠ Ġwith Context ( coroutine Scope . coroutine Context ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtake And Change State Ġ{ Ġstate Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( state ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠState . Running Ġ-> Ġstate :: pause ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠState . Not Running Ġ-> Ġstate . remain () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġsuspend Ġfun Ġfinish () Ġ{ ĊĠĠĠĠĠĠĠ Ġwith Context ( coroutine Scope . coroutine Context ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtake And Change State Ġ{ Ġstate Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( state ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠState . Running Ġ-> Ġstate :: finish ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠState . Not Running Ġ-> Ġstate . remain () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĠTimer Ġstate . Ġ*/ ĊĠĠĠ Ġsealed Ġclass ĠState Ġ: ĠKal uga State , ĠTimer . State Ġ{ ĊĠĠĠĠĠĠĠ Ġabstract Ġval Ġtotal Duration : ĠDuration ĊĠĠĠĠĠĠĠ Ġ/** ĠTimer Ġis Ġnot Ġrunning . Ġ*/ ĊĠĠĠĠĠĠĠ Ġsealed Ġclass ĠNot Running ( protected Ġval Ġelapsed So Far : ĠDuration ) Ġ: ĠState (), ĠTimer . State . Not Running Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġval Ġelapsed Ġ= Ġflow Of ( elapsed So Far ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ/** ĠTimer Ġis Ġpaused . Ġ*/ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġclass ĠPause d ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelapsed So Far : ĠDuration , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġval Ġtotal Duration : ĠDuration ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) Ġ: ĠNot Running ( elapsed So Far ), ĠTimer . State . Not Running . Paused Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfun Ġstart ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinterval : ĠDuration , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtime Source : ĠTime Source , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelay Function : ĠDelay Function , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcoroutine Scope : ĠCor outine Scope , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfinish Callback : Ġsuspend Ġ() Ġ-> ĠUnit ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ): ĠRunning Ġ= ĠRunning ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelapsed So Far Ġ= Ġelapsed So Far , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtotal Duration Ġ= Ġtotal Duration , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinterval Ġ= Ġinterval , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtime Source Ġ= Ġtime Source , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelay Function Ġ= Ġdelay Function , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcoroutine Scope Ġ= Ġcoroutine Scope , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfinish Callback Ġ= Ġfinish Callback ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ/** ĠTimer Ġis Ġfinished . Ġ*/ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġclass ĠFinished ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġval Ġtotal Duration : ĠDuration ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) Ġ: ĠNot Running ( total Duration ), ĠTimer . State . Not Running . Finished ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ/** ĠTimer Ġis Ġrunning . Ġ*/ ĊĠĠĠĠĠĠĠ Ġclass ĠRunning ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġelapsed So Far : ĠDuration , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġval Ġtotal Duration : ĠDuration , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinterval : ĠDuration , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtime Source : ĠTime Source , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġval Ġdelay Function : ĠDelay Function , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġval Ġcoroutine Scope : ĠCor outine Scope , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġval Ġfinish Callback : Ġsuspend Ġ() Ġ-> ĠUnit ĊĠĠĠĠĠĠĠ Ġ) Ġ: ĠState (), ĠTimer . State . Running , ĠHandle After New State IsSet < State >, ĠHandle Before Old State Is Removed < State > Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġval Ġelapsed : ĠFlow < Duration > Ġ= Ġtick Provider ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoffset Ġ= Ġelapsed So Far , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmax Ġ= Ġtotal Duration , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinterval Ġ= Ġinterval , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtime Source Ġ= Ġtime Source , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelay Function Ġ= Ġdelay Function ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġval Ġsupervisor Ġ= ĠSuper visor Job () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġinternal Ġsuspend Ġfun Ġpause (): ĠNot Running . Paused Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠNot Running . Paused ( elapsed . first (), Ġtotal Duration ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinternal Ġfun Ġfinish (): ĠNot Running . Finished Ġ= ĠNot Running . Finished ( total Duration ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġsuspend Ġfun Ġbefore Old State Is Removed ( old State : ĠState ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠCor outine Scope ( supervisor Ġ+ Ġcoroutine Scope . coroutine Context ). launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelay Function ( total Duration Ġ- Ġelapsed . first ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfinish Callback () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġsuspend Ġfun Ġafter New State IsSet ( newState : ĠState ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsupervisor . cancel Children () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ /** Ċ Ġ* Ġ@ return Ġflow Ġof Ġticks Ġas Ġclose Ġto Ġ[ interval ] Ġintervals Ġas Ġpossible . Ġstarting Ġfrom Ġ[ offset ] Ġto Ġthe Ġ[ max ] Ċ Ġ*/ Ċ private Ġfun Ġtick Provider ( ĊĠĠĠ Ġoffset : ĠDuration , ĊĠĠĠ Ġmax : ĠDuration , ĊĠĠĠ Ġinterval : ĠDuration , ĊĠĠĠ Ġtime Source : ĠTime Source , ĊĠĠĠ Ġdelay Function : Ġsuspend Ġ( Duration ) Ġ-> ĠUnit , Ċ ): ĠFlow < Duration > Ġ{ ĊĠĠĠ Ġval Ġmark Ġ= Ġtime Source . mark Now () ĊĊĠĠĠ Ġfun Ġnew Elapsed () Ġ= Ġoffset Ġ+ Ġmark . elapsed Now () ĊĊĠĠĠ Ġreturn Ġflow Ġ{ ĊĠĠĠĠĠĠĠ Ġvar Ġexpected Elapsed Ġ= Ġoffset ĊĠĠĠĠĠĠĠ Ġwhile Ġ( true ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġobtain Ġand Ġdeliver Ġa Ġnew Ġelapsed Ġtime Ġvalue ĊĠĠĠĠĠĠĠĠĠĠĠ Ġemit ( new Elapsed (). coerce At Most ( max )) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġobtain Ġa Ġnew Ġelapsed Ġmarker , Ġas Ġconsuming ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġelapsed Ġ= Ġnew Elapsed () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġquit Ġif Ġthe Ġtimer Ġreached Ġthe Ġmax ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( max Ġ<= Ġelapsed ) Ġbreak ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġadaptive Ġcorrection Ġreduces Ġthe Ġinterval Ġby Ġtime Ġspent Ġdeliver ing Ġemitted Ġvalue ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġdelay Ġ= Ġinterval Ġ+ Ġexpected Elapsed Ġ- Ġelapsed ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġin Ġcase Ġconsumer Ġprocessed Ġthe Ġvalue Ġtoo Ġlong , Ġskip Ġto Ġthe Ġnext Ġinterval ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ( delay . is Negative ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelay Ġ+= Ġinterval ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexpected Elapsed Ġ+= Ġinterval ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġwait Ġfor Ġthe Ġnext Ġiteration ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdelay Function ( delay ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġexpected Elapsed Ġ+= Ġinterval ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ