package Ġco . om ise . android . ui Ċ Ċ import Ġandroid . content . Context Ċ import Ġandroid . text . Editable Ċ import Ġandroid . text . Input Filter Ċ import Ġandroid . text . InputType Ċ import Ġandroid . text . Text Watcher Ċ import Ġandroid . util . Attribute Set Ċ import Ġco . om ise . android . extensions . disable Options Ċ import Ġjava . util . Calendar Ċ import Ġjava . util . G regorian Calendar Ċ Ċ /** Ċ Ġ* ĠExp iry Date EditText Ġis Ġa Ġcustom ĠEditText Ġfor Ġcredit Ġcard Ġexpiration Ġdate Ġfield . ĠThis ĠEditText Ċ Ġ* Ġhandles Ġthe Ġformatting Ġof Ġthe Ġdates Ġand Ġalso Ġlimits Ġthe Ġmonth Ġand Ġyear Ġinputs Ġto Ġa Ġvalid Ċ Ġ* Ġrange . Ċ Ġ*/ Ċ class ĠExp iry Date EditText Ġ: ĠOm ise EditText Ġ{ ĊĊĠĠĠ Ġprivate Ġvar Ġcursor Position Ġ= Ġ 0 ĊĊĠĠĠ Ġprivate Ġvar Ġtext Watcher Ġ= ĠExp iry Date Text Watcher () ĊĠĠĠ Ġprivate Ġvar Ġtext Listener : ĠExp iry Date ChangeListener ? Ġ= Ġnull ĊĠĠĠ Ġprivate Ġval Ġstarted Year : ĠInt Ġby Ġlazy Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġcurrent Year Ġ= ĠG regorian Calendar . getInstance (). get ( Calendar . YEAR ) ĊĠĠĠĠĠĠĠ Ġcurrent Year Ġ- Ġ( current Year Ġ% ĠYEAR _ LAST _ TWO _ DIGIT _ MOD ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġvar Ġexpiry Month : ĠInt Ġ= Ġ 0 ĊĠĠĠ Ġvar Ġexpiry Year : ĠInt Ġ= Ġ 0 ĊĊĠĠĠ Ġconstructor ( context : ĠContext ?) Ġ: Ġsuper ( context ) ĊĠĠĠ Ġconstructor ( context : ĠContext ?, Ġattrs : ĠAttributeSet ?) Ġ: Ġsuper ( context , Ġattrs ) ĊĠĠĠ Ġconstructor ( context : ĠContext ?, Ġattrs : ĠAttributeSet ?, Ġdef Style Attr : ĠInt ) Ġ: Ġsuper ( context , Ġattrs , Ġdef Style Attr ) ĊĊĠĠĠ Ġinit Ġ{ ĊĠĠĠĠĠĠĠ Ġadd TextChanged Listener ( text Watcher ) ĊĠĠĠĠĠĠĠ Ġdisable Options () ĊĠĠĠĠĠĠĠ Ġfilters Ġ= ĠarrayOf ( Input Filter . Length Filter ( MAX _ CHARS )) ĊĠĠĠĠĠĠĠ Ġinput Type Ġ= ĠInput Type . TYPE _ CLASS _ PHONE ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon Selection Changed ( sel Start : ĠInt , Ġsel End : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ Ġsuper . on Selection Changed ( sel Start , Ġsel End ) ĊĊĠĠĠĠĠĠĠ Ġtext ?. let Ġ{ Ġset Selection ( it . length ) Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġvalidate () Ġ{ ĊĠĠĠĠĠĠĠ Ġsuper . validate () ĊĊĠĠĠĠĠĠĠ Ġval Ġcalendar Ġ= ĠCalendar . getInstance () ĊĠĠĠĠĠĠĠ Ġval Ġcurrent Year Ġ= Ġcalendar . get ( Calendar . YEAR ) ĊĠĠĠĠĠĠĠ Ġval Ġcurrent Month Ġ= Ġcalendar . get ( Calendar . MONTH ) ĊĠĠĠĠĠĠĠ Ġval Ġexpiry Month Ġ= Ġexpiry Month ĊĠĠĠĠĠĠĠ Ġval Ġexpiry Year Ġ= Ġexpiry Year ĊĠĠĠĠĠĠĠ Ġif Ġ( expiry Year Ġ< Ġcurrent Year Ġ|| Ġ( expiry Month Ġ== Ġcurrent Month Ġ&& Ġexpiry Year Ġ<= Ġcurrent Year )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠInput ValidationException . Invalid Input Exception ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġinner Ġclass ĠExp iry Date Text Watcher Ġ: ĠText Watcher Ġ{ ĊĠĠĠĠĠĠĠ Ġvar Ġbefore Changed Text : ĠString Ġ= Ġ"" ĊĠĠĠĠĠĠĠ Ġoverride Ġfun Ġafter TextChanged ( s : ĠEdit able ?) Ġ{} ĊĊĠĠĠĠĠĠĠ Ġoverride Ġfun Ġbefore TextChanged ( s : ĠCharSequence ?, Ġstart : ĠInt , Ġcount : ĠInt , Ġafter : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtext ?. let Ġ{ Ġcursor Position Ġ= Ġit . length Ġ- Ġselection Start Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġbefore Changed Text Ġ= Ġs . toString () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġoverride Ġfun Ġon TextChanged ( s : ĠCharSequence ?, Ġstart : ĠInt , Ġbefore : ĠInt , Ġcount : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( s Ġ== Ġnull Ġ|| Ġs . length Ġ> ĠMAX _ CHARS ) Ġreturn ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠOn Ġdeleting ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( s . length Ġ< Ġbefore Changed Text . length ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( before Changed Text [ before Changed Text . length Ġ- Ġ 1 ]. toString () Ġ== ĠDATE _ SEPARATOR ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġafter Deleted Text Ġ= Ġs . substring ( 0 , Ġs . length Ġ- Ġ 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġset Text ( after Deleted Text ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnotify Expiry Date Changed ( after Deleted Text ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnotify Expiry Date Changed ( s . toString ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġset Expiry Date Text ( s . toString ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġnotify Expiry Date Changed ( text . toString ()) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġset Expiry Date Text ( date String : ĠString ) Ġ{ ĊĠĠĠĠĠĠĠ Ġremove TextChanged Listener ( text Watcher ) ĊĊĠĠĠĠĠĠĠ Ġval Ġformatted String Ġ= Ġformat String ( date String ) ĊĠĠĠĠĠĠĠ Ġset Text ( formatted String ) ĊĠĠĠĠĠĠĠ Ġset Selection ( text . toString (). length Ġ- Ġcursor Position ) ĊĊĠĠĠĠĠĠĠ Ġadd TextChanged Listener ( text Watcher ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġnotify Expiry Date Changed ( formatted String : ĠString Ġ= Ġ"") Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( formatted String . isEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġexpiry Month Ġ= Ġ 0 ĊĠĠĠĠĠĠĠĠĠĠĠ Ġexpiry Year Ġ= Ġ 0 ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtext Listener ?. text Formatted ( null , Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġ( month , Ġyear ) Ġ= Ġformatted String . separate Dates () ĊĊĠĠĠĠĠĠĠ Ġexpiry Month Ġ= Ġmonth Ġ?: Ġ 0 ĊĠĠĠĠĠĠĠ Ġexpiry Year Ġ= Ġyear ?. plus ( started Year ) Ġ?: Ġ 0 ĊĊĠĠĠĠĠĠĠ Ġtext Listener ?. text Formatted ( expiry Month , Ġexpiry Year ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ// ĠHave Ġto Ġadd Ġthis Ġinternal Ġlistener Ġbecause Ġif Ġwe Ġadd Ġan Ġexternal ĠText Watcher Ġto Ġthis Ġcustom ĠEditText ĊĠĠĠ Ġ// Ġthe Ġfirst Ġcharacter Ġwould Ġbe Ġset Ġtwice ĊĠĠĠ Ġfun Ġset Internal TextChanged Listener ( text Listener : ĠExp iry Date ChangeListener ) Ġ{ ĊĠĠĠĠĠĠĠ Ġthis . text Listener Ġ= Ġtext Listener ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( IllegalArgumentException :: class ) ĊĠĠĠ Ġfun Ġset Expiry Date ( month : ĠInt , Ġyear : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( month Ġ< Ġ 1 Ġ|| Ġmonth Ġ> Ġ 1 2 Ġ|| Ġyear Ġ< Ġ 1 Ġ|| Ġyear Ġ> Ġ 9 9 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠIllegalArgumentException (" Invalid Ġmonth Ġor Ġyear .") ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġtext ?. append ( month . toString ()) ĊĠĠĠĠĠĠĠ Ġtext ?. append ( year . toString ()) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠDATE _ SEPARATOR Ġ= Ġ"/" ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠMAX _ CHARS Ġ= Ġ 5 Ġ// ĠInclude d Ġseparator ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠMAX _ MONTH Ġ= Ġ 1 2 ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠYEAR _ LAST _ TWO _ DIGIT _ MOD Ġ= Ġ 1 0 0 ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġinterface ĠExp iry Date ChangeListener Ġ{ ĊĠĠĠĠĠĠĠ Ġfun Ġtext Formatted ( month : ĠInt ?, Ġyear : ĠInt ?) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġformat String ( str : ĠString Ġ= Ġ"") : ĠString Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġwhen Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġstr . length Ġ== Ġ 1 Ġ&& Ġstr . toInt () Ġ> Ġ 1 Ġ-> Ġstr . add Zero Prefix If Need () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġstr . length Ġ== Ġ 2 Ġ&& Ġstr . toInt () Ġ> ĠMAX _ MONTH Ġ-> ĠMAX _ MONTH . toString () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġstr ĊĠĠĠĠĠĠĠ Ġ}. add Date Separator If Need () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠString . add Date Separator If Need (): ĠString Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( this . length Ġ!= Ġ 2 Ġ|| Ġthis . contains ( DATE _ SEPARATOR )) Ġreturn Ġthis ĊĠĠĠĠĠĠĠ Ġreturn Ġthis Ġ+ ĠDATE _ SEPARATOR ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠString . add Zero Prefix If Need (): ĠString Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġif Ġ( this . toInt () Ġ> Ġ 1 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ" 0 $ this " ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthis ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠString . separate Dates (): ĠPair < Int ?, ĠInt ?> Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( this . isNotEmpty () Ġ&& Ġ! this . contains ( DATE _ SEPARATOR )) Ġreturn ĠPair ( this . toInt OrNull (), Ġnull ) ĊĊĠĠĠĠĠĠĠ Ġval Ġdates Ġ= Ġthis . split ( DATE _ SEPARATOR . to Regex ()) ĊĊĠĠĠĠĠĠĠ Ġreturn Ġif Ġ( dates . size Ġ> Ġ 1 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠPair ( dates [ 0 ]. toInt OrNull (), Ġdates [ 1 ]. toInt OrNull ()) ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠPair ( dates [ 0 ]. toInt OrNull (), Ġnull ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ