package Ġcom . ek o app . ek os dk . u ikit . chat . messages . fragment Ċ Ċ import Ġandroid . Manifest Ċ import Ġandroid . annotation . Suppress Lint Ċ import Ġandroid . app . Activity Ċ import Ġandroid . content . Intent Ċ import Ġandroid . content . pm . PackageManager Ċ import Ġandroid . net . Uri Ċ import Ġandroid . os . Bundle Ċ import Ġandroid . os . Handler Ċ import Ġandroid . os . Looper Ċ import Ġandroid . view .* Ċ import Ġandroid . widget . TextView Ċ import Ġandroid . widget . Toast Ċ import Ġandroidx . activity . On Back Pressed Callback Ċ import Ġandroidx . activity . result . contract . Activity Result Contracts Ċ import Ġandroidx . appcompat . app . ActionBar Ċ import Ġandroidx . appcompat . app . AppCompatActivity Ċ import Ġandroidx . appcompat . widget . Toolbar Ċ import Ġandroidx . core . content . Context Compat Ċ import Ġandroidx . core . graphics . Color Utils Ċ import Ġandroidx . databinding . Data Binding Util Ċ import Ġandroidx . fragment . app . activity ViewModels Ċ import Ġandroidx . recyclerview . widget . Linear LayoutManager Ċ import Ġandroidx . recyclerview . widget . RecyclerView Ċ import Ġcom . ek o app . ek os dk . E ko Client Ċ import Ġcom . ek o app . ek os dk . channel . E ko Channel Ċ import Ġcom . ek o app . ek os dk . internal . util . Real Path Util Ċ import Ġcom . ek o app . ek os dk . u ikit . base . E ko Picker Fragment Ċ import Ġcom . ek o app . ek os dk . u ikit . chat . R Ċ import Ġcom . ek o app . ek os dk . u ikit . chat . databinding . Am ity Fragment Chat Binding Ċ import Ġcom . ek o app . ek os dk . u ikit . chat . messages . adapter . E ko Message ListAdapter Ċ import Ġcom . ek o app . ek os dk . u ikit . chat . messages . viewModel . E ko Message List ViewModel Ċ import Ġcom . ek o app . ek os dk . u ikit . common . set Shape Ċ import Ġcom . ek o app . ek os dk . u ikit . common . views . Color Palette Util Ċ import Ġcom . ek o app . ek os dk . u ikit . common . views . Color Shade Ċ import Ġcom . ek o app . ek os dk . u ikit . components . I Audio Recorder Listener Ċ import Ġcom . ek o app . ek os dk . u ikit . model . Event Identifier Ċ import Ġcom . ek o app . ek os dk . u ikit . utils . Android Util Ċ import Ġcom . ek o app . ek os dk . u ikit . utils . E ko Album Util Ċ import Ġcom . ek o app . ek os dk . u ikit . utils . E ko Constants Ċ import Ġcom . ek o app . ek os dk . u ikit . utils . E ko RecyclerView Item Decoration Ċ import Ġcom . google . android . material . sn ackbar . Snackbar Ċ import Ġcom . zhihu . mat isse . Mat isse Ċ import Ġio . reactivex . android . schedul ers . Android Schedulers Ċ import Ġio . reactivex . schedul ers . Schedulers Ċ import Ġkotlinx . android . synt hetic . main . am ity _ chat _ bar . view .* Ċ import Ġkotlinx . android . synt hetic . main . am ity _ fragment _ chat .* Ċ import Ġkotlinx . coroutines . Coroutine Scope Ċ import Ġkotlinx . coroutines . Dispatch ers Ċ import Ġkotlinx . coroutines . launch Ċ import Ġjava . io . File Ċ import Ġjava . util .* Ċ import Ġkotlin . concurrent . schedule ĊĊ Ċ private Ġconst Ġval ĠARG _ CHANNEL _ ID Ġ= Ġ" channelId " Ċ Ċ class ĠE ko Message List Fragment Ġprivate Ġconstructor () Ġ: ĠE ko Picker Fragment (), ĠI Audio Recorder Listener Ġ{ ĊĊĠĠĠ Ġprivate Ġval Ġmessage List ViewModel : ĠE ko Message List ViewModel Ġby Ġactivity ViewModels () ĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġm Adapter : ĠE ko Message ListAdapter ĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġm Binding : ĠAm ity Fragment Chat Binding ĊĠĠĠ Ġprivate Ġvar Ġscroll Required Ġ= Ġtrue ĊĠĠĠ Ġprivate Ġvar Ġmsg Sent Ġ= Ġfalse ĊĠĠĠ Ġprivate Ġvar Ġi Custom ViewHolder : ĠE ko Message ListAdapter . IC ustom ViewHolder ? Ġ= Ġnull ĊĠĠĠ Ġvar Ġrecord Permission Granted Ġ= Ġfalse ĊĊĠĠĠ Ġprivate Ġval Ġrequired Permissions Ġ= ĠarrayOf ( ĊĠĠĠĠĠĠĠ ĠManifest . permission . RECORD _ AUDIO , ĊĠĠĠĠĠĠĠ ĠManifest . permission . WRITE _ EXTERNAL _ STORAGE ĊĠĠĠ Ġ) ĊĊĠĠĠ Ġoverride Ġfun ĠonCreate ( savedInstanceState : ĠBundle ?) Ġ{ ĊĠĠĠĠĠĠĠ Ġsuper . onCreate ( savedInstanceState ) ĊĠĠĠĠĠĠĠ Ġmessage List ViewModel . channel ID Ġ= Ġarguments ?. getString ( ARG _ CHANNEL _ ID ) Ġ?: Ġ"" ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun ĠonCreate View ( ĊĠĠĠĠĠĠĠ Ġinflater : ĠLayoutInflater , Ġcontainer : ĠViewGroup ?, ĊĠĠĠĠĠĠĠ ĠsavedInstanceState : ĠBundle ? ĊĠĠĠ Ġ): ĠView ? Ġ{ ĊĠĠĠĠĠĠĠ Ġm Binding Ġ= ĠData Binding Util . inflate ( in flater , ĠR . layout . am ity _ fragment _ chat , Ġcontainer , Ġfalse ) ĊĠĠĠĠĠĠĠ Ġm Binding . viewModel Ġ= Ġmessage List ViewModel ĊĠĠĠĠĠĠĠ Ġreturn Ġm Binding . root ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon View Created ( view : ĠView , ĠsavedInstanceState : ĠBundle ?) Ġ{ ĊĠĠĠĠĠĠĠ Ġsuper . on View Created ( view , ĠsavedInstanceState ) ĊĠĠĠĠĠĠĠ Ġget Channel Type () ĊĠĠĠĠĠĠĠ Ġinit ToolBar () ĊĠĠĠĠĠĠĠ Ġinit RecyclerView () ĊĠĠĠĠĠĠĠ Ġobserve ViewModel Events () ĊĠĠĠĠĠĠĠ Ġset Recorder Touch Listener () ĊĠĠĠĠĠĠĠ Ġet Message . set Shape ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġnull , Ġnull , Ġnull , Ġnull , ĊĠĠĠĠĠĠĠĠĠĠĠ ĠR . color . am ity Color Base , ĠR . color . am ity Color Base , ĠColor Shade . SHA DE 4 ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġrecord Background . set Shape ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġnull , Ġnull , Ġnull , Ġnull , ĊĠĠĠĠĠĠĠĠĠĠĠ ĠR . color . am ity Color Base , ĠR . color . am ity Color Base , ĠColor Shade . SHA DE 4 ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġval Ġpercentage Ġ= Ġ 3 0 F Ġ/ Ġ 1 0 0 ĊĠĠĠĠĠĠĠ Ġval Ġbackground Ġ= ĠColor Utils . set Alpha Component ( ĊĠĠĠĠĠĠĠĠĠĠĠ ĠColor Palette Util . getColor ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠContext Compat . getColor ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrequire Context (), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠR . color . am ity Color Base ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ), ĠColor Shade . SHA DE 4 ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ), Ġ( percentage Ġ* Ġ 2 5 5 ). toInt () ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġrv Chat List . set BackgroundColor ( background ) ĊĊĠĠĠĠĠĠĠ Ġet Message . setOnClickListener Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmessage List ViewModel . show Compose Bar . set ( false ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġet Message . setOn Focus ChangeListener Ġ{ Ġ_, Ġ_ Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmessage List ViewModel . show Compose Bar . set ( false ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġm Binding . recorder View . set Audio Recorder Listener ( this ) ĊĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon Resume () Ġ{ ĊĠĠĠĠĠĠĠ Ġsuper . on Resume () ĊĠĠĠĠĠĠĠ ĠsetUp Back Press () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠsetUp Back Press () Ġ{ ĊĊĠĠĠĠĠĠĠ Ġactivity ?. on Back Pressed Dispatcher ?. add Callback ( this , Ġobject Ġ: ĠOn Back Pressed Callback ( true ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġhandle On Back Pressed () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( message List ViewModel . show Compose Bar . get ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmessage List ViewModel . show Compose Bar . set ( false ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrequire Activity (). finish () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġget Channel Type () Ġ{ ĊĠĠĠĠĠĠĠ Ġdis posable . add ( message List ViewModel . getChannel Type (). take ( 1 ). subscribe Ġ{ Ġe ko Channel Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( ek o Channel . getType () Ġ== ĠE ko Channel . Type . STANDARD ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm Binding . chat ToolBar . iv Avatar . setImage Drawable ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠContext Compat . get Drawable ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrequire Context (), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠR . drawable . am ity _ ic _ group ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm Binding . chat ToolBar . iv Avatar . setImage Drawable ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠContext Compat . get Drawable ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrequire Context (), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠR . drawable . am ity _ ic _ user ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( ek o Channel . getType () Ġ== ĠE ko Channel . Type . CONVER S ATION ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdis posable . add ( message List ViewModel . get DisplayName () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. filter Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . size Ġ> Ġ 1 ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}. subscribe Ġ{ Ġlist Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( user Ġin Ġlist ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( user . getUserId () Ġ!= ĠE ko Client . getUserId ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠCor outine Scope ( Dispatch ers . Main ). launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmessage List ViewModel . title . set ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġuser . getUser ()?. get DisplayName () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmessage List ViewModel . title . set ( ek o Channel . get DisplayName ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġinit ToolBar () Ġ{ ĊĠĠĠĠĠĠĠ Ġ( activity Ġas ĠAppCompatActivity ). support ActionBar ?. display Options Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠ ĠAction Bar . DISPLAY _ SHOW _ CUSTOM ĊĠĠĠĠĠĠĠ Ġ( activity Ġas ĠAppCompatActivity ). set Support ActionBar ( chat ToolBar Ġas ĠToolbar ) ĊĠĠĠĠĠĠĠ Ġ// set Has Options Menu ( true ) ĊĊĠĠĠĠĠĠĠ Ġchat ToolBar . iv Back . setOnClickListener Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġactivity ?. finish () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġinit RecyclerView () Ġ{ ĊĠĠĠĠĠĠĠ Ġm Adapter Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠ ĠE ko Message ListAdapter ( message List ViewModel , Ġi Custom ViewHolder , Ġactivity ?. base Context !! ) ĊĠĠĠĠĠĠĠ Ġ// m Adapter . set Has Stable Ids ( true ) ĊĠĠĠĠĠĠĠ Ġval Ġlayout Manager Ġ= ĠLinearLayoutManager ( activity ) ĊĠĠĠĠĠĠĠ Ġlayout Manager . stack From End Ġ= Ġtrue ĊĠĠĠĠĠĠĠ Ġrv Chat List . layout Manager Ġ= Ġlayout Manager ĊĠĠĠĠĠĠĠ Ġrv Chat List . adapter Ġ= Ġm Adapter ĊĠĠĠĠĠĠĠ Ġrv Chat List . addItem Decoration ( ĊĠĠĠĠĠĠĠĠĠĠĠ ĠE ko RecyclerView Item Decoration ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 0 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 0 , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġresources . get Dimension Pixel Size ( R . dim en . am ity _ padding _ xs ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġrv Chat List . item Animator ?. change Duration Ġ= Ġ 0 ĊĠĠĠĠĠĠĠ Ġ// ( rv Chat List . item Animator Ġas ĠSimple Item Animator ). supports Change Animations Ġ= Ġfalse ĊĊĠĠĠĠĠĠĠ Ġrv Chat List . add On Scroll Listener ( object Ġ: ĠRecyclerView . On Scroll Listener () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġon Sc rolled ( re cyclerView : ĠRecyclerView , Ġdx : ĠInt , Ġdy : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsuper . on Sc rolled ( re cyclerView , Ġdx , Ġdy ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġfirst Visible Item Ġ= Ġlayout Manager . findFirst Visible Item Position () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm Adapter . first Comp let ely Visible Item Ġ= Ġfirst Visible Item ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠĠĠĠĠ Ġjoin Channel () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġjoin Channel () Ġ{ ĊĠĠĠĠĠĠĠ Ġdis posable . add ( message List ViewModel . getAll Messages (). subscribe Ġ{ Ġmessage List Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġm Adapter . submit List ( message List ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġscroll Required Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠ Ġscroll ToEnd ( message List . size Ġ- Ġ 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmessage List ViewModel . is Scroll able . set ( rv Chat List . compute Vertical Scroll Range () Ġ> Ġrv Chat List . height ) ĊĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠĠĠĠĠ Ġmessage List ViewModel . start Reading () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Suppress Lint (" Click ableView Accessibility ") ĊĠĠĠ Ġprivate Ġfun Ġset Recorder Touch Listener () Ġ{ ĊĠĠĠĠĠĠĠ Ġm Binding . tv Record . setOn Touch Listener Ġ{ Ġ_, Ġevent Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( is Recorder Permission Granted ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm Binding . recorder View . on Touch ( event ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( event ?. action ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠMotion Event . ACTION _ DOWN Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmessage List ViewModel . is Recording . set ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġm Binding . recorder View . circular Re veal () ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠMotion Event . ACTION _ UP Ġ-> Ġmessage List ViewModel . is Recording . set ( false ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrequest Recorder Permission () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtrue ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġrequest Recorder Permission () Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġrecord Permission Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠ Ġregister For Activity Result ( Activity Result Contracts . Request Multiple Permissions ()) Ġ{ Ġpermissions Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġis Granted Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġpermissions . entries . forEach Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! it . value ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis Granted Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrecord Permission Granted Ġ= Ġis Granted ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġrecord Permission . launch ( required Permissions ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġis Recorder Permission Granted (): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġvar Ġis Granted Ġ= Ġtrue ĊĠĠĠĠĠĠĠ Ġrequired Permissions . forEach Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( context ?. check Calling Or Self Permission ( it ) Ġ!= ĠPackage Manager . PERMISSION _ GRAN TED ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis Granted Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġrecord Permission Granted Ġ= Ġis Granted ĊĠĠĠĠĠĠĠ Ġreturn Ġrecord Permission Granted ĊĠĠĠ Ġ} ĊĊĊĠĠĠ Ġprivate Ġfun Ġscroll ToEnd ( position : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( msg Sent Ġ|| Ġscroll Required Ġ&& Ġ! message List ViewModel . is RV Scrolling Ġ&& ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ! rv Chat List . can Scroll Vert ically ( 1 ) ĊĠĠĠĠĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTimer (). schedule ( SCROLL _ DELAY ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠCor outine Scope ( Dispatch ers . Main ). launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrv Chat List . scrollTo Position ( position ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġscroll Required Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmsg Sent Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġobserve ViewModel Events () Ġ{ ĊĠĠĠĠĠĠĠ Ġmessage List ViewModel . on Event Received Ġ+= Ġ{ Ġevent Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( event . type ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠEvent Identifier . CAMERA _ CLICK ED Ġ-> Ġtake Picture () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠEvent Identifier . P ICK _ FILE Ġ-> Ġpick File () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠEvent Identifier . P ICK _ IMAGE Ġ-> Ġpick Multiple Images () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠEvent Identifier . MSG _ SEND _ ERROR Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠCor outine Scope ( Dispatch ers . Main ). launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsn ackBar Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠSn ackbar . make ( rv Chat List , ĠR . string . am ity _ failed _ msg , ĠSn ackbar . LENGTH _ SHORT ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsn ackBar . show () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠEvent Identifier . MSG _ SEND _ SUCCESS Ġ-> Ġmsg Sent Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠEvent Identifier . TO GGLE _ CHAT _ COMP OSE _ BAR Ġ-> Ġtoggle Soft Keyboard () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠEvent Identifier . SHOW _ AUDIO _ RECORD _ UI Ġ-> Ġshow Audio Record Ui () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġ{ ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġshow Audio Record Ui () Ġ{ ĊĠĠĠĠĠĠĠ ĠAndroid Util . hide Keyboard ( layout Parent ) ĊĠĠĠĠĠĠĠ Ġmessage List ViewModel . show Compose Bar . set ( false ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġtoggle Soft Keyboard () Ġ{ ĊĠĠĠĠĠĠĠ Ġmessage List ViewModel . is Voice Msg Ui . set ( false ) ĊĠĠĠĠĠĠĠ Ġif Ġ( Android Util . is Soft Keyboard Open ( layout Parent )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠAndroid Util . hide Keyboard ( layout Parent ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠHandler ( Looper . get Main Looper ()). post Delayed ({ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmessage List ViewModel . show Compose Bar . set ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ}, Ġ 3 0 0 ) ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( message List ViewModel . show Compose Bar . get ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmessage List ViewModel . show Compose Bar . set ( false ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġet Message . request Focus () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠAndroid Util . show Keyboard ( et Message ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmessage List ViewModel . show Compose Bar . set ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġif Ġ( message List ViewModel . keyboard Height . get () Ġ== Ġ 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġheight Ġ= ĠAndroid Util . getKey board Height ( layout Parent ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( height Ġ!= Ġnull Ġ&& Ġheight Ġ> Ġ 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmessage List ViewModel . keyboard Height . set ( height ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġpick Multiple Images () Ġ{ ĊĠĠĠĠĠĠĠ ĠE ko Album Util . pick Multiple Image ( this , Ġ 0 , ĠE ko Constants . P ICK _ I MAGES ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon File Pick ed ( data : ĠUri ?) Ġ{ ĊĠĠĠĠĠĠĠ ĠToast . makeText ( require Context (), Ġ"$ data ", ĠToast . LENGTH _ SHORT ). show () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon Image Pick ed ( data : ĠUri ?) Ġ{ ĊĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon Photo Clicked ( file : ĠFile ?) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( file Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġphoto Uri Ġ= ĠUri . from File ( file ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdis posable . add ( message List ViewModel . send Image Message ( photo Uri ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. subscribe On ( Schedulers . io ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. observe On ( Android Schedulers . main Thread ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. do On Complete Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmsg Sent Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}. do OnError Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmsg Sent Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}. subscribe () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( message List ViewModel . show Compose Bar . get ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmessage List ViewModel . show Compose Bar . set ( false ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon File Re corded ( audio File : ĠFile ?) Ġ{ ĊĠĠĠĠĠĠĠ Ġmessage List ViewModel . is Recording . set ( false ) ĊĠĠĠĠĠĠĠ Ġif Ġ( audio File Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġaudio File Uri Ġ= ĠUri . from File ( audio File ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdis posable . add ( message List ViewModel . send Audio Message ( audio File Uri ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. subscribe On ( Schedulers . io ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. observe On ( Android Schedulers . main Thread ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. do On Complete Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmsg Sent Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}. do OnError Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmsg Sent Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}. subscribe () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġshow Message () Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġlayout : ĠView Ġ= Ġlayout Inflater . inflate ( ĊĠĠĠĠĠĠĠĠĠĠĠ ĠR . layout . am ity _ view _ audio _ msg _ error , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġactivity ?. findViewById ( R . id . errorMessage Container ) ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġval ĠtextView Ġ= Ġlayout . findViewById < TextView >( R . id . tv Message ) ĊĠĠĠĠĠĠĠ ĠtextView . set Shape ( null , Ġnull , Ġnull , Ġnull , ĠR . color . am ity Color Base , Ġnull , Ġnull ) ĊĊĠĠĠĠĠĠĠ Ġval Ġtoast Ġ= ĠToast ( context ) ĊĠĠĠĠĠĠĠ Ġtoast . set Gravity ( Gravity . BOTTOM , Ġ 0 , Ġ 1 8 0 ) ĊĠĠĠĠĠĠĠ Ġtoast . duration Ġ= ĠToast . LENGTH _ SHORT ĊĠĠĠĠĠĠĠ Ġtoast . view Ġ= Ġlayout ĊĠĠĠĠĠĠĠ Ġtoast . show () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġadd Custom View ( ĊĠĠĠĠĠĠĠ Ġlistener : ĠE ko Message ListAdapter . IC ustom ViewHolder ĊĠĠĠ Ġ) Ġ{ ĊĠĠĠĠĠĠĠ Ġi Custom ViewHolder Ġ= Ġlistener ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon Activity Result ( request Code : ĠInt , ĠresultCode : ĠInt , Ġdata : ĠIntent ?) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( result Code Ġ== ĠActivity . RESULT _ OK Ġ&& Ġrequest Code Ġ== ĠE ko Constants . P ICK _ I MAGES ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( request Code Ġ== ĠE ko Constants . P ICK _ I MAGES ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdata ?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġimage Uri List Ġ= ĠMat isse . obtain Result ( it ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( uri Ġin Ġimage Uri List ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġnormalized Uri Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠUri . from File ( File ( Real Path Util . get Real Path ( context , Ġuri ))) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdis posable . add ( message List ViewModel . send Image Message ( normalized Uri ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. subscribe On ( Schedulers . io ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. observe On ( Android Schedulers . main Thread ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. do On Complete Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmsg Sent Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}. do OnError Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmsg Sent Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}. subscribe () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( message List ViewModel . show Compose Bar . get ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmessage List ViewModel . show Compose Bar . set ( false ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsuper . on Activity Result ( request Code , ĠresultCode , Ġdata ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun ĠonCreate Options Menu ( menu : ĠMenu , Ġinflater : ĠMenu Inflater ) Ġ{ ĊĠĠĠĠĠĠĠ Ġ// in flater . inflate ( R . menu . ek o _ chat _ list , Ġmenu ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon Options ItemSelected ( item : ĠMenuItem ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġsuper . on Options ItemSelected ( item ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon Pause () Ġ{ ĊĠĠĠĠĠĠĠ Ġsuper . on Pause () ĊĠĠĠĠĠĠĠ Ġmessage List ViewModel . is Recording . set ( false ) ĊĠĠĠĠĠĠĠ Ġm Adapter . pause And Reset Player () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġon Destroy View () Ġ{ ĊĠĠĠĠĠĠĠ Ġsuper . on Destroy View () ĊĠĠĠĠĠĠĠ Ġmessage List ViewModel . stop Reading () ĊĠĠĠĠĠĠĠ Ġm Adapter . release MediaPlayer () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġclass ĠBuilder ( private Ġval Ġchannel Id : ĠString ) Ġ{ ĊĊĠĠĠĠĠĠĠ Ġfun Ġbuild (): ĠE ko Message List Fragment Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠE ko Message List Fragment (). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġarguments Ġ= ĠBundle (). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġput String ( ARG _ CHANNEL _ ID , Ġchannel Id ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠSC ROLL _ DELAY Ġ= Ġ 2 0 0 L ĊĠĠĠ Ġ} ĊĊ Ċ }