/* Ċ Ġ* ĠCopyright Ġ 2 0 1 9 Ġ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 Ċ Ġ* Ċ Ġ* ĠĠĠĠĠ Ġ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 . Ċ Ġ*/ Ċ Ċ @ file : Opt In ( Experimental Pointer Input :: class ) Ċ Ċ package Ġandroidx . compose . ui . gesture Ċ Ċ import Ġandroidx . compose . runtime . remember Ċ import Ġandroidx . compose . runtime . remember Coroutine Scope Ċ import Ġandroidx . compose . ui . Modifier Ċ import Ġandroidx . compose . ui . composed Ċ import Ġandroidx . compose . ui . geometry . Offset Ċ import Ġandroidx . compose . ui . gesture . cust ome vents . Delay Up Event Ċ import Ġandroidx . compose . ui . gesture . cust ome vents . Delay Up Message Ċ import Ġandroidx . compose . ui . input . pointer . Custom EventDispatcher Ċ import Ġandroidx . compose . ui . input . pointer . Pointer Event Ċ import Ġandroidx . compose . ui . input . pointer . Pointer Event Pass Ċ import Ġandroidx . compose . ui . input . pointer . Pointer Id Ċ import Ġandroidx . compose . ui . input . pointer . Pointer Input Change Ċ import Ġandroidx . compose . ui . input . pointer . Pointer Input Filter Ċ import Ġandroidx . compose . ui . input . pointer . any Position Change Cons umed Ċ import Ġandroidx . compose . ui . input . pointer . changed To Down Ċ import Ġandroidx . compose . ui . input . pointer . changed To Up Ċ import Ġandroidx . compose . ui . input . pointer . consume Down Change Ċ import Ġandroidx . compose . ui . unit . Int Size Ċ import Ġandroidx . compose . ui . unit . in Milliseconds Ċ import Ġandroidx . compose . ui . util . annotation . Visible ForTesting Ċ import Ġandroidx . compose . ui . util . fast Any Ċ import Ġandroidx . compose . ui . util . fast ForEach Ċ import Ġkotlinx . coroutines . Coroutine Scope Ċ import Ġkotlinx . coroutines . Job Ċ import Ġkotlinx . coroutines . delay Ċ import Ġkotlinx . coroutines . launch Ċ Ċ // ĠTODO ( b / 1 3 8 7 5 4 5 9 1 ): ĠThe Ġbehavior Ġof Ġthis Ġgesture Ġdetector Ġneeds Ġto Ġbe Ġfinal ized . Ċ // ĠTODO ( b / 1 3 9 0 2 0 6 7 8 ): ĠProbably Ġhas Ġshared Ġfunctionality Ġwith Ġother Ġpress Ġbased Ġdetector s . Ċ /** Ċ Ġ* ĠRes pon ds Ġto Ġpointers Ġgoing Ġdown Ġand Ġup Ġ( tap ) Ġand Ġthen Ġdown Ġand Ġup Ġagain Ġ( another Ġtap ) Ċ Ġ* Ġwith Ġminimal Ġgap Ġof Ġtime Ġbetween Ġthe Ġfirst Ġup Ġand Ġthe Ġsecond Ġdown . Ċ Ġ* Ċ Ġ* ĠNote : ĠThis Ġis Ġa Ġtemporary Ġimplementation Ġto Ġun block Ġdepend ents . Ġ ĠOnce Ġthe Ġunderlying ĠAPI Ġthat Ċ Ġ* Ġallows Ġdouble Ġtap Ġto Ġtemporarily Ġblock Ġtap Ġfrom Ġf iring Ġis Ġcomplete , Ġthis Ġgesture Ġdetector Ġwill Ċ Ġ* Ġnot Ġblock Ġtap Ġwhen Ġthe Ġfirst Ġ" up " Ġoccurs . ĠIt Ġwill Ġhowever Ġblock Ġthe Ġ 2 nd Ġup Ġfrom Ġcausing Ġtap Ġto Ċ Ġ* Ġfire . Ċ Ġ* Ċ Ġ* ĠAlso , Ġgiven Ġthat Ġthis Ġgesture Ġdetector Ġis Ġso Ġtemporary , Ġopt ing Ġto Ġnot Ġwrite Ġsubstantial Ġtests . Ċ Ġ*/ Ċ fun ĠModifier . double Tap Gesture Filter ( ĊĠĠĠ Ġon Double Tap : Ġ( Offset ) Ġ-> ĠUnit Ċ ): ĠModifier Ġ= Ġcomposed Ġ{ ĊĠĠĠ Ġval Ġscope Ġ= Ġremember Coroutine Scope () ĊĠĠĠ Ġval Ġfilter Ġ= Ġremember Ġ{ ĠDouble Tap Gesture Filter ( scope ) Ġ} ĊĠĠĠ Ġfilter . on Double Tap Ġ= Ġon Double Tap ĊĠĠĠ ĠPointer Input Modifier Impl ( filter ) Ċ } Ċ Ċ internal Ġclass ĠDouble Tap Gesture Filter ( ĊĠĠĠ Ġval Ġcoroutine Scope : ĠCor outine Scope Ċ ) Ġ: ĠPointer Input Filter () Ġ{ ĊĊĠĠĠ Ġlateinit Ġvar Ġon Double Tap : Ġ( Offset ) Ġ-> ĠUnit ĊĊĠĠĠ Ġprivate Ġenum Ġclass ĠState Ġ{ ĊĠĠĠĠĠĠĠ ĠId le , ĠDown , ĠUp , ĠSecond Down ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Visible ForTesting ĊĠĠĠ Ġinternal Ġvar Ġdouble Tap Timeout Ġ= ĠDouble Tap Timeout ĊĊĠĠĠ Ġprivate Ġvar Ġstate Ġ= ĠState . Idle ĊĠĠĠ Ġprivate Ġvar Ġjob : ĠJob ? Ġ= Ġnull ĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġdelay Up Dispatcher : ĠDelay Up Dispatcher ĊĊĠĠĠ Ġoverride Ġfun Ġon Init ( custom EventDispatcher : ĠCustom EventDispatcher ) Ġ{ ĊĠĠĠĠĠĠĠ Ġdelay Up Dispatcher Ġ= ĠDelay Up Dispatcher ( custom EventDispatcher ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon Pointer Event ( ĊĠĠĠĠĠĠĠ Ġpointer Event : ĠPointer Event , ĊĠĠĠĠĠĠĠ Ġpass : ĠPointer Event Pass , ĊĠĠĠĠĠĠĠ Ġbounds : ĠInt Size ĊĠĠĠ Ġ) Ġ{ ĊĊĠĠĠĠĠĠĠ Ġval Ġchanges Ġ= Ġpointer Event . changes ĊĊĠĠĠĠĠĠĠ Ġif Ġ( pass Ġ== ĠPointer Event Pass . Main ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( state Ġ== ĠState . Idle Ġ&& Ġchanges . all Ġ{ Ġit . changed To Down () Ġ}) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstate Ġ= ĠState . Down ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( state Ġ== ĠState . Down Ġ&& Ġchanges . all Ġ{ Ġit . changed To Up () Ġ}) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstate Ġ= ĠState . Up ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelay Up Dispatcher . delay Up ( changes ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġjob Ġ= Ġcoroutine Scope . launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelay ( double Tap Timeout . in Milliseconds ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstate Ġ= ĠState . Idle ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelay Up Dispatcher . allow Up () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( state Ġ== ĠState . Up Ġ&& Ġchanges . all Ġ{ Ġit . changed To Down () Ġ}) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstate Ġ= ĠState . Second Down ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġjob ?. cancel () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelay Up Dispatcher . dis allow Up () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( state Ġ== ĠState . Second Down Ġ&& Ġchanges . all Ġ{ Ġit . changed To Up () Ġ}) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstate Ġ= ĠState . Idle ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġon Double Tap . invoke ( changes [ 0 ]. previous . position !! ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġchanges . fast ForEach Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . consume Down Change () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġif Ġ( pass Ġ== ĠPointer Event Pass . Final ) Ġ{ ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġno Pointers Are In Bounds And Not Up State Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ( state Ġ!= ĠState . Up Ġ&& Ġ! changes . any Pointers In Bounds ( bounds )) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġany Position Change Cons umed Ġ= Ġchanges . fast Any Ġ{ Ġit . any Position Change Cons umed () Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( no Pointers Are In Bounds And Not Up State Ġ|| Ġany Position Change Cons umed ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠA Ġpointers Ġmovement Ġwas Ġconsumed Ġor Ġall Ġof Ġour Ġpointers Ġare Ġout Ġof Ġbounds , Ġso ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġreset Ġto Ġidle . ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfull Reset () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon Cancel () Ġ{ ĊĠĠĠĠĠĠĠ Ġfull Reset () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġfull Reset () Ġ{ ĊĠĠĠĠĠĠĠ Ġdelay Up Dispatcher . dis allow Up () ĊĠĠĠĠĠĠĠ Ġjob ?. cancel () ĊĠĠĠĠĠĠĠ Ġstate Ġ= ĠState . Idle ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġclass ĠDelay Up Dispatcher ( val Ġcustom EventDispatcher : ĠCustom EventDispatcher ) Ġ{ ĊĊĠĠĠĠĠĠĠ Ġ// ĠNon - write able Ġbecause Ġwe Ġsend Ġthis Ġto Ġcustom EventDispatcher Ġand Ġwe Ġdon 't Ġwant Ġto Ġever ĊĠĠĠĠĠĠĠ Ġ// Ġaccidentally Ġmutate Ġwhat Ġwe Ġhave Ġsent . ĊĠĠĠĠĠĠĠ Ġprivate Ġvar Ġblocked Up Events : ĠSet < Pointer Id >? Ġ= Ġnull ĊĊĠĠĠĠĠĠĠ Ġfun Ġdelay Up ( changes : ĠList < Pointer Input Change >) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġblocked Up Events Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġchanges ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map To ( mutable Set Of ()) Ġ{ Ġit . id Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. also Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcustom EventDispatcher . retain Hit Paths ( it ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcustom EventDispatcher . dispatch Custom Event ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠDelay Up Event ( Delay Up Message . Delay Up , Ġit ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġfun Ġdis allow Up () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġun Block Up Events ( true ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġfun Ġallow Up () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġun Block Up Events ( false ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġprivate Ġfun Ġun Block Up Events ( up Is Cons umed : ĠBoolean ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġblocked Up Events ?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmessage Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( up Is Cons umed ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠDelay Up Message . Delayed Up Cons umed ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠDelay Up Message . Delayed Up Not Cons umed ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcustom EventDispatcher . dispatch Custom Event ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠDelay Up Event ( message , Ġit ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcustom EventDispatcher . release Hit Paths ( it ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġblocked Up Events Ġ= Ġnull ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ }