/* Ċ Ġ* ĠCopyright Ġ 2 0 2 1 ĠThe ĠAndroid ĠOpen ĠSource ĠProject Ċ Ġ* Ċ Ġ* Ġ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 Ċ Ġ* Ċ Ġ* ĠĠĠĠ Ġhttps :// 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 . example . android dev challenge Ċ Ċ import Ġandroid . os . Bundle Ċ import Ġandroidx . activity . compose . setContent Ċ import Ġandroidx . appcompat . app . AppCompatActivity Ċ import Ġandroidx . compose . animation . Animated Visibility Ċ import Ġandroidx . compose . animation . Experimental Animation Api Ċ import Ġandroidx . compose . animation . slide In Vert ically Ċ import Ġandroidx . compose . animation . slide Out Vert ically Ċ import Ġandroidx . compose . foundation . layout . Arrange ment Ċ import Ġandroidx . compose . foundation . layout . Box Ċ import Ġandroidx . compose . foundation . layout . Column Ċ import Ġandroidx . compose . foundation . layout . Row Ċ import Ġandroidx . compose . foundation . layout . Spacer Ċ import Ġandroidx . compose . foundation . layout . fill Max Height Ċ import Ġandroidx . compose . foundation . layout . fill Max Width Ċ import Ġandroidx . compose . foundation . layout . size Ċ import Ġandroidx . compose . material . Icon Ċ import Ġandroidx . compose . material . IconButton Ċ import Ġandroidx . compose . material . Material Theme Ċ import Ġandroidx . compose . material . Surface Ċ import Ġandroidx . compose . material . Text Ċ import Ġandroidx . compose . material . icons . Icons Ċ import Ġandroidx . compose . material . icons . filled . Expand Less Ċ import Ġandroidx . compose . material . icons . filled . Expand More Ċ import Ġandroidx . compose . material . icons . filled . Pause Ċ import Ġandroidx . compose . material . icons . filled . Play Arrow Ċ import Ġandroidx . compose . runtime . Composable Ċ import Ġandroidx . compose . runtime . La unched Effect Ċ import Ġandroidx . compose . runtime . collect As State Ċ import Ġandroidx . compose . runtime . mutable State Of Ċ import Ġandroidx . compose . runtime . remember Ċ import Ġandroidx . compose . ui . Alignment Ċ import Ġandroidx . compose . ui . Modifier Ċ import Ġandroidx . compose . ui . text . font . Font Family Ċ import Ġandroidx . compose . ui . tool ing . preview . Preview Ċ import Ġandroidx . compose . ui . unit . dp Ċ import Ġandroidx . compose . ui . unit . sp Ċ import Ġandroidx . lifecycle . ViewModel Ċ import Ġandroidx . lifecycle . viewModel Scope Ċ import Ġcom . example . android dev challenge . ui . theme . My Theme Ċ import Ġkotlinx . coroutines . Coroutine Scope Ċ import Ġkotlinx . coroutines . Job Ċ import Ġkotlinx . coroutines . Obsolete Cor outines Api Ċ import Ġkotlinx . coroutines . channels . actor Ċ import Ġkotlinx . coroutines . delay Ċ import Ġkotlinx . coroutines . flow . Mutable State Flow Ċ import Ġkotlinx . coroutines . launch Ċ import Ġkotlin . time . Experimental Time Ċ Ċ class ĠMainActivity Ġ: ĠAppCompatActivity () Ġ{ ĊĠĠĠ Ġoverride Ġfun ĠonCreate ( savedInstanceState : ĠBundle ?) Ġ{ ĊĠĠĠĠĠĠĠ Ġsuper . onCreate ( savedInstanceState ) ĊĠĠĠĠĠĠĠ Ġset Content Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠMy Theme Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠMy App () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ // ĠStart Ġbuilding Ġyour Ġapp Ġhere ! Ċ @ Composable Ċ fun ĠMy App () Ġ{ ĊĠĠĠ ĠSurface ( color Ġ= ĠMaterial Theme . colors . background ) Ġ{ ĊĠĠĠĠĠĠĠ ĠCount down Timer Screen () ĊĠĠĠ Ġ} Ċ } Ċ Ċ class ĠTimer ViewModel Ġ: ĠViewModel () Ġ{ ĊĠĠĠ Ġval Ġduration Ġ= ĠMutable State Flow ( Timer Duration ( 0 , Ġ 0 , Ġ 0 )) ĊĠĠĠ Ġval Ġstarted Ġ= ĠMutable State Flow ( false ) ĊĊĠĠĠ Ġsealed Ġclass ĠMessage Ġ{ ĊĠĠĠĠĠĠĠ Ġobject ĠStart Ġ: ĠMessage () ĊĠĠĠĠĠĠĠ Ġobject ĠStop Ġ: ĠMessage () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Opt In ( Obsolete Cor outines Api :: class ) ĊĠĠĠ Ġprivate Ġfun ĠCor outine Scope . actor () Ġ= Ġactor < Message > Ġ{ ĊĠĠĠĠĠĠĠ Ġvar Ġjob : ĠJob ? Ġ= Ġnull ĊĠĠĠĠĠĠĠ Ġfor Ġ( msg Ġin Ġchannel ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( msg ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠMessage . Start Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġjob Ġ= Ġlaunch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ(! duration . value . is Zero ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġduration . value Ġ= Ġduration . value . countdown () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( duration . value . is Zero ()) Ġbreak ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelay ( 1 0 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstarted . value Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠMessage . Stop Ġ-> Ġjob ?. cancel () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġval Ġtimer Ġ= ĠviewModel Scope . actor () ĊĊĠĠĠ Ġfun Ġstart () Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! duration . value . is Zero ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtimer . offer ( Message . Start ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġstarted . value Ġ= Ġtrue ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġstop () Ġ{ ĊĠĠĠĠĠĠĠ Ġtimer . offer ( Message . Stop ) ĊĠĠĠĠĠĠĠ Ġstarted . value Ġ= Ġfalse ĊĠĠĠ Ġ} Ċ } Ċ Ċ @ Composable Ċ fun ĠCount down Timer Screen ( viewModel : ĠTimer ViewModel Ġ= ĠTimer ViewModel ()) Ġ{ ĊĠĠĠ Ġval Ġduration Ġ= ĠviewModel . duration . collect As State () ĊĠĠĠ Ġval Ġis Started Ġ= ĠviewModel . started . collect As State ( false ) ĊĊĠĠĠ ĠColumn ( ĊĠĠĠĠĠĠĠ ĠModifier . fill Max Height (), ĊĠĠĠĠĠĠĠ Ġvertical Arrange ment Ġ= ĠArrange ment . Center ĊĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠ ĠRow ( ĊĠĠĠĠĠĠĠĠĠĠĠ ĠModifier . fill Max Width (), ĊĠĠĠĠĠĠĠĠĠĠĠ Ġhorizontal Arrange ment Ġ= ĠArrange ment . Space Even ly ĊĠĠĠĠĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠCount down Timer ( duration . value ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠviewModel . duration . value Ġ= Ġit ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ ĠSp acer ( Modifier . size ( 3 2 . dp )) ĊĠĠĠĠĠĠĠ ĠRow ( ĊĠĠĠĠĠĠĠĠĠĠĠ ĠModifier . fill Max Width (), ĊĠĠĠĠĠĠĠĠĠĠĠ Ġhorizontal Arrange ment Ġ= ĠArrange ment . Space Even ly ĊĠĠĠĠĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmodifier Ġ= ĠModifier . size ( 7 2 . dp ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( is Started . value ) ĠIcon Button ( onClick Ġ= Ġ{ ĠviewModel . stop () Ġ}) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠIcon ( Icons . Filled . Pause , Ġcontent Description Ġ= Ġ" pause ", Ġmodifier Ġ= Ġmodifier ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġelse ĠIcon Button ( onClick Ġ= Ġ{ ĠviewModel . start () Ġ}) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠIcon ( Icons . Filled . Play Arrow , Ġcontent Description Ġ= Ġ" start ", Ġmodifier Ġ= Ġmodifier ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ @ Opt In ( Experimental Time :: class ) Ċ @ Composable Ċ fun ĠCount down Timer ( ĊĠĠĠ Ġduration : ĠTimer Duration , ĊĠĠĠ Ġset Duration : Ġ( Timer Duration ) Ġ-> ĠUnit , Ċ ) Ġ{ ĊĠĠĠ ĠCount down Digit ( duration . hours (), Ġrange Ġ= Ġ 0 .. 2 4 ) Ġ{ ĊĠĠĠĠĠĠĠ Ġset Duration ( duration . updated Hour ( it )) ĊĠĠĠ Ġ} ĊĠĠĠ ĠCount down Digit ( duration . minutes ()) Ġ{ ĊĠĠĠĠĠĠĠ Ġset Duration ( duration . updated Minute ( it )) ĊĠĠĠ Ġ} ĊĠĠĠ ĠCount down Digit ( duration . seconds ()) Ġ{ ĊĠĠĠĠĠĠĠ Ġset Duration ( duration . updated Second ( it )) ĊĠĠĠ Ġ} Ċ } Ċ Ċ @ Composable Ċ fun ĠCount down Digit ( ĊĠĠĠ Ġnumber : ĠInt , ĊĠĠĠ Ġrange : ĠInt Range Ġ= Ġ 0 .. 6 0 , ĊĠĠĠ Ġon Number Change : Ġ(( Int ) Ġ-> ĠUnit )? Ġ= Ġnull Ċ ) Ġ{ ĊĠĠĠ ĠColumn ( ĊĠĠĠĠĠĠĠ Ġhorizontal Alignment Ġ= ĠAlignment . Center H orizontally ĊĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠ ĠIcon Button ( onClick Ġ= Ġ{ Ġon Number Change ?. invoke (( number Ġ+ Ġ 1 ). coerce At Most ( range . last )) Ġ}) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠIcon ( Icons . Filled . Expand Less , Ġcontent Description Ġ= Ġ" increase ") ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ ĠAnimated Digit ( number Ġ= Ġnumber ) ĊĠĠĠĠĠĠĠ ĠIcon Button ( onClick Ġ= Ġ{ Ġon Number Change ?. invoke (( number Ġ- Ġ 1 ). coerce At Least ( range . first )) Ġ}) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠIcon ( Icons . Default . Expand More , Ġcontent Description Ġ= Ġ" decrease ") ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ private Ġval Ġdigit Format Ġ= Ġ"% 0 2 d " Ċ Ċ @ Opt In ( Experimental Animation Api :: class ) Ċ @ Composable Ċ fun ĠAnimated Digit ( number : ĠInt ) Ġ{ ĊĠĠĠ Ġval Ġ( prev Number , Ġset Number ) Ġ= Ġremember Ġ{ Ġmutable State Of ( number ) Ġ} ĊĠĠĠ ĠLa unched Effect ( key 1 Ġ= Ġnumber , Ġblock Ġ= Ġ{ Ġset Number ( number ) Ġ}) ĊĊĠĠĠ ĠBox Ġ{ ĊĠĠĠĠĠĠĠ ĠAnimated Visibility ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvisible Ġ= Ġnumber Ġ!= Ġprev Number , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġenter Ġ= Ġslide In Vert ically () ĊĠĠĠĠĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠText ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtext Ġ= Ġdigit Format . format ( number ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠfontFamily Ġ= ĠFont Family . Mono space , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠfontSize Ġ= Ġ 7 2 . sp ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ ĠAnimated Visibility ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvisible Ġ= Ġnumber Ġ== Ġprev Number , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġexit Ġ= Ġslide Out Vert ically () ĊĠĠĠĠĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠText ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtext Ġ= Ġdigit Format . format ( prev Number ), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠfontFamily Ġ= ĠFont Family . Mono space , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠfontSize Ġ= Ġ 7 2 . sp ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ @ Preview (" Light ĠTheme ", Ġwidth Dp Ġ= Ġ 3 6 0 , Ġheight Dp Ġ= Ġ 6 4 0 ) Ċ @ Composable Ċ fun ĠLight Preview () Ġ{ ĊĠĠĠ ĠMy Theme Ġ{ ĊĠĠĠĠĠĠĠ ĠMy App () ĊĠĠĠ Ġ} Ċ } Ċ Ċ @ Preview (" Dark ĠTheme ", Ġwidth Dp Ġ= Ġ 3 6 0 , Ġheight Dp Ġ= Ġ 6 4 0 ) Ċ @ Composable Ċ fun ĠDark Preview () Ġ{ ĊĠĠĠ ĠMy Theme ( dark Theme Ġ= Ġtrue ) Ġ{ ĊĠĠĠĠĠĠĠ ĠMy App () ĊĠĠĠ Ġ} Ċ } Ċ