package Ġorg . wikipedia . views Ċ Ċ import Ġandroid . content . Context Ċ import Ġandroid . text .* Ċ import Ġandroid . text . style . ForegroundColor Span Ċ import Ġandroid . util . Attribute Set Ċ import Ġandroidx . annotation . Color Int Ċ import Ġandroidx . core . text . get Spans Ċ import Ġandroidx . core . widget . do On TextChanged Ċ import Ġorg . wikipedia . R Ċ import Ġorg . wikipedia . datac lient . Wiki Site Ċ import Ġorg . wikipedia . static data . User Alias Data Ċ import Ġorg . wikipedia . util . Resource Util Ċ import Ġorg . wikipedia . util . log . L Ċ import Ġjava . util .* Ċ Ċ class ĠUser Mention EditText Ġ: ĠPlain Paste EditText Ġ{ ĊĠĠĠ Ġinterface ĠListener Ġ{ ĊĠĠĠĠĠĠĠ Ġfun ĠonStart UserName Entry () ĊĠĠĠĠĠĠĠ Ġfun Ġon Cancel UserName Entry () ĊĠĠĠĠĠĠĠ Ġfun Ġon UserName Changed ( userName : ĠString ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġvar Ġlistener : ĠListener ? Ġ= Ġnull ĊĊĠĠĠ Ġprivate Ġval Ġtext Watcher : ĠText Watcher ? ĊĠĠĠ Ġprivate Ġvar ĠuserName Start Pos Ġ= Ġ- 1 ĊĠĠĠ Ġprivate Ġvar ĠuserName End Pos Ġ= Ġ- 1 ĊĠĠĠ Ġprivate Ġval Ġis Enter ing UserName Ġget () Ġ= ĠuserName Start Pos Ġ>= Ġ 0 ĊĠĠĠ Ġprivate Ġvar Ġspaces Pressed Count Ġ= Ġ 0 ĊĠĠĠ Ġprivate Ġvar Ġis UserName Commit ting Ġ= Ġfalse ĊĠĠĠ Ġprivate Ġval Ġeditable Ġget () Ġ= Ġtext Ġ?: ĠSp ann able StringBuilder ("") ĊĊĠĠĠ Ġconstructor ( context : ĠContext ) Ġ: Ġsuper ( context ) ĊĠĠĠ Ġconstructor ( context : ĠContext , Ġattrs : ĠAttributeSet ?) Ġ: Ġsuper ( context , Ġattrs ) ĊĠĠĠ Ġconstructor ( context : ĠContext , Ġattrs : ĠAttributeSet ?, Ġdef Style : ĠInt ) Ġ: Ġsuper ( context , Ġattrs , Ġdef Style ) ĊĊĠĠĠ Ġinit Ġ{ ĊĊĠĠĠĠĠĠĠ Ġ// ĠThis Ġis Ġa Ġstate Ġmachine Ġthat Ġbehaves Ġroughly Ġas Ġfollows : ĊĠĠĠĠĠĠĠ Ġ// Ġ* ĠWhen Ġthe Ġ"@ " Ġsymbol Ġis Ġtyped , Ġit Ġent ers Ġa Ġstate Ġof Ġinput ting Ġa Ġusername . ĊĠĠĠĠĠĠĠ Ġ// Ġ* ĠDuring Ġthe Ġusername Ġinput Ġstate , Ġevery Ġsubsequent Ġkey press Ġwill Ġsend Ġan Ġevent Ġto Ġthe ĊĠĠĠĠĠĠĠ Ġ// ĠĠ Ġlistener , Ġto Ġgive Ġit Ġa Ġchance Ġto Ġshow Ġa Ġdropdown Ġselection Ġfor Ġsearching Ġusername s . ĊĠĠĠĠĠĠĠ Ġ// Ġ* ĠIf Ġthe Ġuser Ġselects Ġa Ġfinal Ġusername Ġfrom Ġthe Ġdropdown Ġselection , Ġthe Ġinput Ġstate Ġis ĊĠĠĠĠĠĠĠ Ġ// ĠĠ Ġfinished , Ġand Ġthe Ġusername Ġis Ġturned Ġinto Ġa Ġspecial ĠSpan Ġthat Ġcontains Ġthe Ġusername Ġat ĊĠĠĠĠĠĠĠ Ġ// ĠĠ Ġthat Ġposition . ĊĠĠĠĠĠĠĠ Ġ// Ġ* ĠIf Ġa Ġspace Ġ" Ġ" Ġcharacter Ġis Ġpressed , Ġwithout Ġhaving Ġselected Ġa Ġusername Ġfrom Ġthe ĊĠĠĠĠĠĠĠ Ġ// ĠĠ Ġdropdown Ġlist , Ġthe Ġinput Ġstate Ġis Ġcancelled , Ġand Ġno Ġspecial ĠSpan Ġis Ġadded . ĊĠĠĠĠĠĠĠ Ġ// Ġ* ĠFor Ġall Ġother Ġkey p resses , Ġwhile Ġnot Ġin Ġthe Ġusername Ġinput Ġstate , Ġit Ġbehaves Ġas Ġusual . ĊĠĠĠĠĠĠĠ Ġtext Watcher Ġ= Ġdo On TextChanged Ġ{ Ġtext , Ġstart , Ġbefore , Ġcount Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( text Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ do On TextChanged ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( count Ġ== Ġ 1 Ġ&& Ġstart Ġ< Ġtext . length Ġ&& Ġtext [ start ] Ġ== Ġ'@ ' Ġ&& ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ( start Ġ== Ġ 0 Ġ|| Ġ( start Ġ> Ġ 0 Ġ&& Ġtext [ start Ġ- Ġ 1 ] Ġ== Ġ' Ġ')) Ġ&& ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ! is Enter ing UserName ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠuserName Start Pos Ġ= Ġstart ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠuserName End Pos Ġ= ĠuserName Start Pos ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠonStart UserName Entry () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( is Enter ing UserName ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġspace Pressed Ġ= Ġcount Ġ- Ġbefore Ġ== Ġ 1 Ġ&& Ġstart Ġ+ Ġcount Ġ- Ġ 1 Ġ< Ġtext . length Ġ&& Ġstart Ġ+ Ġcount Ġ- Ġ 1 Ġ>= Ġ 0 Ġ&& ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtext [ start Ġ+ Ġcount Ġ- Ġ 1 ] Ġ== Ġ' Ġ' ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( space Pressed ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġspaces Pressed Count ++ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( space Pressed Ġ&& Ġspaces Pressed Count Ġ> Ġ 1 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġon Cancel UserName Entry () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠuserName End Pos Ġ+= Ġ( count Ġ- Ġbefore ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( userName End Pos Ġ<= ĠuserName Start Pos ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġon Cancel UserName Entry () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon Selection Changed ( sel Start : ĠInt , Ġsel End : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ Ġsuper . on Selection Changed ( sel Start , Ġsel End ) ĊĠĠĠĠĠĠĠ Ġif Ġ( text Watcher Ġ== Ġnull Ġ|| Ġis UserName Commit ting ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ( is Enter ing UserName ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(( sel Start Ġ< ĠuserName Start Pos Ġ|| Ġsel End Ġ> ĠuserName End Pos ) Ġ|| ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ( userName End Pos Ġ> Ġeditable . length )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġon Cancel UserName Entry () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġon UserName Changed ( editable . substring ( userName Start Pos , ĠuserName End Pos )) ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġif Ġ( sel Start Ġ== Ġsel End Ġ&& Ġ! is Enter ing UserName ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġspans Ġ= Ġeditable . get Spans < User Color Span >( sel Start , Ġsel End ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( spans . isNotEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠuserName Start Pos Ġ= Ġeditable . get Span Start ( spans [ 0 ]) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠuserName End Pos Ġ= Ġeditable . get Span End ( spans [ 0 ]) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠonStart UserName Entry () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġon UserName Changed ( editable . substring ( userName Start Pos , ĠuserName End Pos )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠonStart UserName Entry () Ġ{ ĊĠĠĠĠĠĠĠ Ġlistener ?. onStart UserName Entry () ĊĠĠĠĠĠĠĠ Ġspaces Pressed Count Ġ= Ġ 0 ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġon Cancel UserName Entry () Ġ{ ĊĠĠĠĠĠĠĠ ĠuserName Start Pos Ġ= Ġ- 1 ĊĠĠĠĠĠĠĠ ĠuserName End Pos Ġ= Ġ- 1 ĊĠĠĠĠĠĠĠ Ġspaces Pressed Count Ġ= Ġ 0 ĊĠĠĠĠĠĠĠ Ġlistener ?. on Cancel UserName Entry () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġon UserName Changed ( userName : ĠString ) Ġ{ ĊĠĠĠĠĠĠĠ ĠL . d (" Enter ing Ġusername : Ġ$ userName ") ĊĠĠĠĠĠĠĠ Ġlistener ?. on UserName Changed ( userName ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġpre populate UserName ( userName : ĠString ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġsb Ġ= ĠSp ann able StringBuilder () ĊĠĠĠĠĠĠĠ Ġsb . append ("@ $ userName ") ĊĠĠĠĠĠĠĠ Ġval Ġspan End Ġ= Ġsb . length ĊĠĠĠĠĠĠĠ Ġsb . append (" Ġ") ĊĠĠĠĠĠĠĠ Ġcreate UserName Span ( sb , Ġ 0 , Ġspan End ) ĊĠĠĠĠĠĠĠ Ġis UserName Commit ting Ġ= Ġtrue ĊĠĠĠĠĠĠĠ Ġtext Ġ= Ġsb ĊĠĠĠĠĠĠĠ Ġis UserName Commit ting Ġ= Ġfalse ĊĠĠĠĠĠĠĠ Ġset Selection ( sb . length ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġon Commit UserName ( userName : ĠString ) Ġ{ ĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġis UserName Commit ting Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( userName Start Pos Ġ< Ġ 0 Ġ|| ĠuserName End Pos Ġ<= ĠuserName Start Pos ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġon Cancel UserName Entry () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsb Ġ= ĠSp ann able StringBuilder () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsb . append ( editable . sub Sequence ( 0 , ĠuserName Start Pos )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġspan Start Ġ= Ġsb . length ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsb . append ("@ $ userName ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġspan End Ġ= Ġsb . length ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( userName End Pos Ġ< Ġeditable . length ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsb . append ( editable . sub Sequence ( userName End Pos , Ġeditable . length Ġ- Ġ 1 )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġcreate UserName Span ( sb , Ġspan Start , Ġspan End ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtext Ġ= Ġsb ĊĠĠĠĠĠĠĠĠĠĠĠ Ġset Selection ( span End ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġon Cancel UserName Entry () ĊĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġis UserName Commit ting Ġ= Ġfalse ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġcreate UserName Span ( span nable : ĠSp ann able , Ġstart : ĠInt , Ġend : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġspan Ġ= ĠUser Color Span ( Resource Util . get The med Color ( context , ĠR . attr . color Accent )) ĊĠĠĠĠĠĠĠ Ġsp ann able . set Span ( span , Ġstart , Ġend , ĠSp ann able . SPAN _ EXCL USIVE _ EXCL USIVE ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠReturns Ġthe Ġtext Ġof Ġthis Ġfield , Ġwith Ġproperly Ġexpanded Ġuser Ġmentions . ĊĠĠĠĠ Ġ* ĠEach Ġuser Ġmention Ġ( in Ġth Ġform Ġof Ġ@{ username }) Ġwill Ġbe Ġexpanded Ġinto Ġa Ġwiki Ġlink Ġto Ġthe ĊĠĠĠĠ Ġ* Ġuser Ġpage Ġof Ġthat Ġuser , Ġi . e . Ġ[[ User : username |@ username ]] ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġget Parsed Text ( wiki Site : ĠWiki Site ): ĠString Ġ{ ĊĠĠĠĠĠĠĠ Ġvar Ġstr Ġ= Ġeditable . toString () ĊĊĠĠĠĠĠĠĠ Ġval Ġspans Ġ= Ġeditable . get Spans < User Color Span >() ĊĠĠĠĠĠĠĠ Ġif Ġ( spans . isNotEmpty ()) Ġ{ ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġpairs Ġ= Ġmutable ListOf < Mutable Pair < Int , ĠInt >>() ĊĠĠĠĠĠĠĠĠĠĠĠ Ġspans . forEach Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġpairs . add ( Mutable Pair ( editable . get Span Start ( it ), Ġeditable . get Span End ( it ))) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġpairs . sortBy Ġ{ Ġit . first Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( i Ġin Ġ 0 Ġuntil Ġpairs . size ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġname Ġ= Ġstr . substring ( pairs [ i ]. first , Ġpairs [ i ]. second ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( name . length Ġ> Ġ 1 Ġ&& Ġname . startsWith ("@ ")) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġname Ġ= Ġname . substring ( 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġname Ġ= Ġ"[ [" Ġ+ ĠUser Alias Data . value For ( wiki Site . language Code ) Ġ+ Ġ":" Ġ+ Ġname Ġ+ Ġ"| @" Ġ+ Ġname Ġ+ Ġ" ]] " ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstr Ġ= Ġstr . replace Range ( pairs [ i ]. first , Ġpairs [ i ]. second , Ġname ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlen Diff Ġ= Ġname . length Ġ- Ġ( pairs [ i ]. second Ġ- Ġpairs [ i ]. first ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( j Ġin Ġi Ġ+ Ġ 1 Ġuntil Ġpairs . size ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġpairs [ j ]. first Ġ+= Ġlen Diff ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġpairs [ j ]. second Ġ+= Ġlen Diff ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn Ġstr ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġdata Ġclass ĠMutable Pair < T , ĠU >( var Ġfirst : ĠT , Ġvar Ġsecond : ĠU ) ĊĊĠĠĠ Ġprivate Ġclass ĠUser Color Span (@ Color Int Ġfore Color : ĠInt ) Ġ: ĠFore ground Color Span ( fore Color ) Ċ } Ċ