Nexilis.swift 254 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449
  1. //
  2. // Qmera.swift
  3. // Runner
  4. //
  5. // Created by Yayan Dwi on 15/04/20.
  6. // Copyright © 2020 The Chromium Authors. All rights reserved.
  7. //
  8. import Foundation
  9. import nuSDKService
  10. import AVFoundation
  11. import AVKit
  12. import UIKit
  13. import FMDB
  14. import QuickLook
  15. import NotificationBannerSwift
  16. import SDWebImage
  17. public class Nexilis: NSObject {
  18. public static var sAPIKey = ""
  19. public static var ADDRESS = ""
  20. // static let ADDRESS_33 = "192.168.0.33"
  21. // static let ADDRESS_RELEASE = "202.158.33.26" //CBN
  22. // static let ADDRESS_RELEASE = "108.137.84.148" //AWS
  23. // static let PORT = 45328
  24. // static let PORT = 65328 // 33
  25. static var PORT = PORT_RELEASE
  26. static let PORT_33 = 62328
  27. static let PORT_RELEASE = 42328
  28. static var nSessionMode: Int! = 1
  29. static var dispatch: DispatchGroup?
  30. public static var showFB = false
  31. public static var fromMAB = false
  32. let callManager = CallManager()
  33. var providerDelegate: CallProviderDelegate?
  34. public static let shared = Nexilis()
  35. // public static var broadcastTimer = Timer()
  36. public static var broadcastList = [[String: String]]()
  37. public static var onGoingPushCC: [String: String] = [:]
  38. public static var openBroadcast = false
  39. public static var loadingAlert = LibAlertController()
  40. public static var floatingButton = FloatingButton()
  41. public static var defaultFloatingButton: [Int] = []
  42. public static var showButtonFB = false
  43. public static var isShowForceSignIn = true
  44. public static var afterConnect = true
  45. public static var imageCache = NSCache<NSString, UIImage>()
  46. public static let listenerReceiveChat = "onReceiveChatLibLite"
  47. public static let listenerStatusChat = "onMessageChatLibLite"
  48. public static let listenerTypingChat = "onTypingChatLibLite"
  49. public static let listenerStatusCall = "onStatusCallLibLite"
  50. public static let callFCM = "onCallFCM"
  51. public static let failedSendMessage = "onFailedSendMessage"
  52. public static var showLibraryNotification = true
  53. public static let STREAMING_SEMINAR_ENDED = 88
  54. public static let VIDEO_CALL_END = 38
  55. public static let VIDEO_CALL_MUTE_UNMUTE = 36
  56. public static let VIDEO_CALL_ZOOM = 35
  57. public static let VIDEO_CAMERA_PARAMS_CHANED = 34
  58. public static let VIDEO_CALL_RINGING = 33
  59. public static let VIDEO_CALL_OFFHOOK = 32
  60. public static let VIDEO_CALL_INCOMING = 31
  61. public static let AUDIO_CALL_END = 28
  62. public static let AUDIO_CALL_RINGING = 23
  63. public static let AUDIO_CALL_OFFHOOK = 22
  64. public static let AUDIO_CALL_INCOMING = 21
  65. public static let AUDIO_VIDEO_CALL_MUTED = 26
  66. public static let VIDEO_RINGING = 11
  67. public static let ENDED = 8
  68. public static let INITIATING = 4
  69. public static let AUDIO_RINGING = 1
  70. public static let OUTGOING_CALL = 0
  71. public static let OFFLINE = -3
  72. public static let BUSY = -4
  73. public static let IDX_QUEUE_SYSTEM = 2
  74. public static let IDX_NOTIF_CENTER = 3
  75. public static let IDX_CC_STREAM = 4
  76. public static let IDX_CHAT = 6
  77. public static let IDX_CALL = 7
  78. public static let IDX_STREAM = 8
  79. public static let IDX_CC = 9
  80. public static let IDX_CALL_AUDIO = 11
  81. public static let IDX_CALL_VIDEO = 12
  82. public static let IDX_WHITEBOARD = 13
  83. public static let IDX_SCREENSHARING = 14
  84. public static let IDX_WB_SS = 15
  85. public static let IDX_BROADCAST_FORM = 16
  86. public static let IDX_CONVERSATION = 17
  87. public static let IDX_FAVORITEMESSAGE = 18
  88. public static let IDX_CONFERENCE_ROOM_FORM = 19
  89. public static let IDX_EMAIL_CONFIGURATION = 20
  90. public static let IDX_CREATE_GROUP = 21
  91. public static let IDX_ADDFRIEND = 22
  92. public static let IDX_SIGNUP_OR_IN_PAGE = 23
  93. public static let IDX_SECURE_FOLDER = 29
  94. public static let IDX_SETTING = 32
  95. public static let IDX_POST = 99
  96. public static let IDX_SELF_ACT = 100
  97. public static let IDX_SOCIAL_COMMERCE = 101
  98. public static let IDX_NEWS = 102
  99. public static let IDX_SECURE_BROWSER = 105
  100. public static var callAPNActivated = false
  101. private static var ringtonePlayer: AVAudioPlayer?
  102. private static var ringbacktonePlayer: AVAudioPlayer?
  103. private static var busyPlayer: AVAudioPlayer?
  104. static var sharedAudioPlayer: AVAudioPlayer?
  105. private func createDelegate() {
  106. //print("createDelegate...")
  107. callDelegate = self
  108. messageDelegate = self
  109. groupDelegate = self
  110. personInfoDelegate = self
  111. providerDelegate = CallProviderDelegate(callManager: callManager)
  112. }
  113. public static func connect(apiKey: String, delegate: ConnectDelegate, showButton: Bool = true, fromMAB: Bool = false) {
  114. showFB = showButton
  115. Nexilis.fromMAB = fromMAB
  116. Nexilis.shared.createDelegate()
  117. Nexilis.sAPIKey = apiKey
  118. Nexilis.showButtonFB = showButton
  119. do {
  120. try MasterKeyUtil.shared.generateAndStoreMasterKey()
  121. try MasterKeyUtil.shared.generateAndStorePrefsKey()
  122. if Utils.getCertificatePinningWebview().isEmpty {
  123. let cert: [String: String] = ["nexilis.io": Utils.decrypt(str: "7^reFspLRnRz3NaVjeI2AUQ0l5JFQbf0bZZ3dfYaBMqnL"), "newuniverse.io": Utils.decrypt(str: "6]umyRKg9l6D2N?2wVaejmtPrWNtVKpjqt0mqyA68XwFi")]
  124. if let jsonData = try? JSONSerialization.data(withJSONObject: cert, options: []),
  125. let jsonString = String(data: jsonData, encoding: .utf8) {
  126. Utils.setCertificatePinningWebview(value: jsonString)
  127. }
  128. }
  129. } catch {
  130. }
  131. IncomingThread.default.run()
  132. imageCache.countLimit = 100
  133. imageCache.totalCostLimit = 1024 * 1024 * 200
  134. UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum)
  135. DispatchQueue.global().async {
  136. do {
  137. if Utils.getFinishInitPrefsr() {
  138. Utils.setFinishInitPrefs(value: false)
  139. }
  140. let address = Nexilis.getAddressNew(apiKey:apiKey)
  141. if address.isEmpty {
  142. return
  143. }
  144. // print("HUHU>> \(API.sGetVersion())")
  145. var id = Utils.getConnectionID()
  146. Nexilis.ADDRESS = address.components(separatedBy: ":")[0]
  147. Nexilis.PORT = Int(address.components(separatedBy: ":")[1]) ?? 0
  148. if id.isEmpty {
  149. let sDID = UIDevice.current.identifierForVendor?.uuidString ?? "UNK-DEVICE"
  150. id = String(sDID[sDID.index(sDID.endIndex, offsetBy: -5)...])
  151. Utils.setConnectionID(value: id)
  152. }
  153. try API.initConnection(sAPIK: apiKey, cbiI: Callback(), sTCPAddr: Nexilis.ADDRESS, nTCPPort: Nexilis.PORT, sUserID: id, sStartWH: "09:00")
  154. while (API.nGetCLXConnState() == 0) {
  155. Thread.sleep(forTimeInterval: 0.5)
  156. }
  157. if(User.getMyPin() == nil) {
  158. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getSignUpApi(api: apiKey, p_pin: id), timeout: 30 * 1000){
  159. id = response.getBody(key: CoreMessage_TMessageKey.F_PIN, default_value: "")
  160. let enable_signup = (response.getBody(key: CoreMessage_TMessageKey.IS_ENABLED_ANONYMOUS, default_value: "0")) == "1"
  161. Utils.setForceAnonymous(value: enable_signup)
  162. if(!id.isEmpty) {
  163. SecureUserDefaults.shared.set(id, forKey: "me")
  164. }
  165. }
  166. }
  167. let api: String? = SecureUserDefaults.shared.value(forKey: "apiKey") ?? nil
  168. if api == nil {
  169. SecureUserDefaults.shared.set(apiKey, forKey: "apiKey")
  170. }
  171. getPullPrefs()
  172. getFeatureAccess()
  173. if let me = User.getMyPin() {
  174. if Utils.getSetProfile() {
  175. _ = Database.shared.openDatabase()
  176. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  177. do {
  178. if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: "SELECT * FROM BUDDY where f_pin = '\(me)' ") {
  179. if !cursorData.next() {
  180. _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: me))
  181. }
  182. cursorData.close()
  183. }
  184. } catch {
  185. rollback.pointee = true
  186. print("Access database error: \(error.localizedDescription)")
  187. }
  188. })
  189. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  190. do {
  191. if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: "SELECT image_id FROM GROUPZ where group_type = 1 AND official = 1"), cursorData.next() {
  192. do {
  193. let documentDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
  194. let file = documentDir.appendingPathComponent(cursorData.string(forColumnIndex: 0)!)
  195. if !FileManager().fileExists(atPath: file.path) {
  196. Download().startHTTP(forKey: cursorData.string(forColumnIndex: 0)!) { (name, progress) in}
  197. }
  198. } catch {}
  199. cursorData.close()
  200. }
  201. } catch {
  202. rollback.pointee = true
  203. print("Access database error: \(error.localizedDescription)")
  204. }
  205. })
  206. } else if isShowForceSignIn && !Utils.getForceAnonymous() && !Utils.getSetProfile() {
  207. DispatchQueue.main.async {
  208. showForceSignIn()
  209. }
  210. }
  211. getServiceBank()
  212. getPullWorkingArea()
  213. getPullGroupNoMember()
  214. delegate.onSuccess(userId: me)
  215. DispatchQueue.main.async {
  216. var viewController = UIApplication.shared.windows.first?.rootViewController
  217. var notNull = false
  218. while !notNull {
  219. viewController = UIApplication.shared.windows.first?.rootViewController
  220. if viewController != nil && Utils.getFinishInitPrefsr() {
  221. notNull = true
  222. }
  223. }
  224. if showButton {
  225. addFB(viewController: viewController!, fromMAB: fromMAB)
  226. }
  227. if let rootViewController = viewController {
  228. let isDarkMode = rootViewController.traitCollection.userInterfaceStyle == .dark
  229. if isDarkMode {
  230. UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
  231. let cancelButtonAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  232. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes , for: .normal)
  233. } else {
  234. UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black]
  235. let cancelButtonAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  236. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes , for: .normal)
  237. }
  238. }
  239. }
  240. if (Utils.getSetProfile() && !Utils.getFinishInitPrefsr()) || (!Utils.getForceAnonymous() && !Utils.getFinishInitPrefsr()) {
  241. Utils.setFinishInitPrefs(value: true)
  242. }
  243. Nexilis.destroyAll()
  244. if !Utils.getLoginMultipleFPin().isEmpty {
  245. let dialog = DialogUnableAccess()
  246. dialog.modalTransitionStyle = .crossDissolve
  247. dialog.modalPresentationStyle = .overCurrentContext
  248. UIApplication.shared.visibleViewController?.present(dialog, animated: true)
  249. }
  250. }
  251. } catch {
  252. delegate.onFailed(error: "99:Something went wrong")
  253. }
  254. }
  255. NetworkMonitor.shared.startMonitoring()
  256. OutgoingThread.default.run()
  257. InquiryThread.default.run()
  258. if UIFont.systemFont(ofSize: 12).familyName == ".AppleSystemUIFont" {
  259. UIFont.libOverrideInitialize()
  260. }
  261. _ = LocationManager()
  262. }
  263. private static var ringtoneID: SystemSoundID = 0
  264. public static func playRingtoneCall() {
  265. var ringtonePath = Bundle.resourceBundle(for: Nexilis.self).url(forResource: "pb_call_in_ios", withExtension: "mp3")
  266. if ringtonePath == nil {
  267. ringtonePath = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: "pb_call_in_ios", withExtension: "mp3")
  268. }
  269. if let a = ringtonePath {
  270. // AudioServicesCreateSystemSoundID(a as CFURL, &ringtoneID)
  271. // AudioServicesPlaySystemSound(ringtoneID)
  272. do {
  273. Nexilis.sharedAudioPlayer = try AVAudioPlayer(contentsOf: a)
  274. Nexilis.sharedAudioPlayer?.prepareToPlay()
  275. Nexilis.sharedAudioPlayer?.numberOfLoops = -1
  276. Nexilis.sharedAudioPlayer?.play()
  277. } catch {
  278. }
  279. }
  280. }
  281. public static func stopRingtoneCall() {
  282. // AudioServicesDisposeSystemSoundID(ringtoneID)
  283. Nexilis.sharedAudioPlayer?.stop()
  284. }
  285. private static var ringBackToneID: SystemSoundID = 0
  286. public static func playRingbacktoneCall() {
  287. var ringbacktonePath = Bundle.resourceBundle(for: Nexilis.self).url(forResource: "pb_call_out_ios", withExtension: "mp3")
  288. if ringbacktonePath == nil {
  289. ringbacktonePath = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: "pb_call_out_ios", withExtension: "mp3")
  290. }
  291. if let a = ringbacktonePath {
  292. // AudioServicesCreateSystemSoundID(a as CFURL, &ringBackToneID)
  293. // AudioServicesPlaySystemSound(ringBackToneID)
  294. do {
  295. Nexilis.sharedAudioPlayer = try AVAudioPlayer(contentsOf: a)
  296. Nexilis.sharedAudioPlayer?.prepareToPlay()
  297. Nexilis.sharedAudioPlayer?.numberOfLoops = -1
  298. Nexilis.sharedAudioPlayer?.play()
  299. } catch {
  300. }
  301. }
  302. }
  303. public static func stopRingbacktoneCall() {
  304. // AudioServicesDisposeSystemSoundID(ringBackToneID)
  305. Nexilis.sharedAudioPlayer?.stop()
  306. }
  307. private static var busyToneID: SystemSoundID = 0
  308. public static func playBusyCall() {
  309. var busyPath = Bundle.resourceBundle(for: Nexilis.self).url(forResource: "pb_call_busy", withExtension: "mp3")
  310. if busyPath == nil {
  311. busyPath = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: "pb_call_busy", withExtension: "mp3")
  312. }
  313. if let a = busyPath {
  314. // AudioServicesCreateSystemSoundID(a as CFURL, &busyToneID)
  315. // AudioServicesPlaySystemSound(busyToneID)
  316. do {
  317. Nexilis.sharedAudioPlayer = try AVAudioPlayer(contentsOf: a)
  318. Nexilis.sharedAudioPlayer?.prepareToPlay()
  319. Nexilis.sharedAudioPlayer?.numberOfLoops = -1
  320. Nexilis.sharedAudioPlayer?.play()
  321. } catch {
  322. }
  323. }
  324. }
  325. public static func stopBusyCall() {
  326. // AudioServicesDisposeSystemSoundID(busyToneID)
  327. Nexilis.sharedAudioPlayer?.stop()
  328. }
  329. public static func addFB(viewController: UIViewController, fromMAB: Bool) {
  330. if let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) {
  331. keyWindow.addSubview(floatingButton)
  332. }
  333. if fromMAB {
  334. var vc = viewController
  335. if viewController is UINavigationController {
  336. vc = (viewController as! UINavigationController).rootViewController!
  337. }
  338. floatingButton.mySettingDelegate = vc as? any SettingMABDelegate
  339. }
  340. }
  341. private static func getPullPrefs() {
  342. DispatchQueue.global().async {
  343. let urlString = Utils.getBEId().isEmpty ? Utils.getDomainOpr() + "nexilis/logics/get_baseurl_new?key=\(Nexilis.sAPIKey)" : Utils.getDomainOpr() + "nexilis/logics/get_prefs?be=\(Utils.getBEId())&appId=\(APIS.getAppNm())"
  344. Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
  345. if let data = data, let responseString = String(data: data, encoding: .utf8) {
  346. if let json = try? JSONSerialization.jsonObject(with: responseString.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [String: Any?] {
  347. do {
  348. if Utils.getBEId().isEmpty {
  349. Utils.setBEId(value: "\(json["be_id"] as? Int ?? 0)")
  350. getPullPrefs()
  351. } else {
  352. let dataArray: [[String: Any?]] = [json]
  353. if !dataArray.isEmpty && !Utils.getIsLoadThemeFromOther() {
  354. if let jsonData = try? JSONSerialization.data(withJSONObject: dataArray, options: .prettyPrinted) {
  355. // Convert to JSON String
  356. let jsonString = String(data: jsonData, encoding: .utf8)
  357. Utils.setPrefTheme(value: jsonString ?? "")
  358. Utils.setValueInitialApp(data: jsonString ?? "")
  359. }
  360. }
  361. }
  362. } catch {
  363. }
  364. }
  365. }
  366. }
  367. }
  368. }
  369. private static func getPullGroupNoMember() {
  370. while Nexilis.isProcessWriteSync {
  371. Thread.sleep(forTimeInterval: 0.5)
  372. }
  373. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.pullGroupNoMember(), timeout: 30 * 1000), response.isOk() {
  374. let data = response.getBody(key: CoreMessage_TMessageKey.DATA)
  375. if !data.isEmpty {
  376. if let jsonArray = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [AnyObject] {
  377. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  378. do {
  379. for json in jsonArray {
  380. let group_id = CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.GROUP_ID)
  381. _ = try Database.shared.insertRecord(fmdb: fmdb, table: "GROUP_NM", cvalues: [
  382. "group_id" : group_id,
  383. "f_name" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.GROUP_NAME),
  384. "scope_id" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.MESSAGE_SCOPE_ID),
  385. "image_id": CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.THUMB_ID),
  386. "quote": CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.QUOTE),
  387. "last_update" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.LAST_UPDATE),
  388. "created_by" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.CREATED_BY),
  389. "created_date" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.CREATED_DATE),
  390. "ex_block" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.BLOCK),
  391. "folder_id" : "",
  392. "chat_modifier" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.CHAT_MODIFIER),
  393. "group_type" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.IS_ORGANIZATION),
  394. "parent" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.PARENT_ID),
  395. "level" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.LEVEL),
  396. "is_open" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.IS_OPEN),
  397. "official" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.OFFICIAL_ACCOUNT),
  398. "level_edu" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.LEVEL_EDU),
  399. "materi_edu" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.MATERI_EDU),
  400. "is_education" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.IS_EDUCATION)
  401. ], replace: true)
  402. }
  403. } catch {
  404. rollback.pointee = true
  405. print("Access database error: \(error.localizedDescription)")
  406. }
  407. })
  408. }
  409. }
  410. }
  411. }
  412. private static func getServiceBank() {
  413. DispatchQueue.global().async {
  414. _ = Nexilis.write(message: CoreMessage_TMessageBank.getServiceBank())
  415. }
  416. }
  417. public static func sendStateToServer(s: String) {
  418. DispatchQueue.global().async {
  419. let parameter: [String : Any] = [
  420. "f_pin": User.getMyPin() ?? "",
  421. "state": s
  422. ]
  423. Utils.postDataWithCookiesAndUserAgent(from: URL(string: Utils.getDomainOpr() + "logging")!, parameter: parameter) { data, response, error in
  424. print("\(response)")
  425. }
  426. }
  427. }
  428. private static func getFeatureAccess() {
  429. DispatchQueue.global().async {
  430. Utils.postDataWithCookiesAndUserAgent(from: URL(string: Utils.getDomainOpr() + "get_feature_access_new")!) { data, response, error in
  431. let response = response as? HTTPURLResponse
  432. if response?.statusCode != 200 || error != nil {
  433. return
  434. }
  435. if let data = data, let responseString = String(data: data, encoding: .utf8) {
  436. if let jsonArray = try? JSONSerialization.jsonObject(with: responseString.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [AnyObject] {
  437. do {
  438. var jsonFA: [String: Any] = [:]
  439. for jsonData in jsonArray {
  440. var tmp = jsonData as! [String: Any]
  441. tmp.removeValue(forKey: "action")
  442. tmp.removeValue(forKey: "alert_title")
  443. tmp.removeValue(forKey: "alert_message")
  444. jsonFA[Array(tmp.keys)[0]] = Array(tmp.values)[0]
  445. if jsonData["upload_max_retry"]! != nil {
  446. let umr = jsonData["upload_max_retry"] as! String
  447. Utils.setMaxRetryUpload(value: umr)
  448. jsonFA[Array(tmp.keys)[0]] = Array(tmp.values)[0]
  449. }
  450. if jsonData["upload_max_time"]! != nil {
  451. let umt = jsonData["upload_max_time"] as! String
  452. Utils.setMaxRetryTimeUpload(value: umt)
  453. jsonFA[Array(tmp.keys)[0]] = Array(tmp.values)[0]
  454. }
  455. if jsonData["default_fb"]! != nil {
  456. if !Utils.getAfterConfigFB() {
  457. Utils.setConfigModeFB(value: jsonData["default_fb"] as! String)
  458. }
  459. jsonFA[Array(tmp.keys)[0]] = Array(tmp.values)[0]
  460. }
  461. if jsonData["authentication_duration"]! != nil {
  462. let ad = jsonData["authentication_duration"] as! String
  463. Utils.setAuthenticationDuration(value: ad)
  464. }
  465. if jsonData["secure_folder_encrypt_key"]! != nil {
  466. do {
  467. if let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
  468. let secureURL = documentsDirectoryURL.appendingPathComponent("secure")
  469. if !FileManager.default.fileExists(atPath: secureURL.path){
  470. try FileManager.default.createDirectory(at: secureURL, withIntermediateDirectories: true, attributes: nil)
  471. }
  472. }
  473. try MasterKeyUtil.shared.generateAndStoreServerKey(jsonData["secure_folder_encrypt_key"] as! String)
  474. }
  475. catch {
  476. }
  477. }
  478. if jsonData["secure_folder_encrypt_key_iv"]! != nil {
  479. Utils.setSecureFolderEncryptIv(value: jsonData["secure_folder_encrypt_key_iv"] as! String)
  480. }
  481. if jsonData["chatbot_greetings"]! != nil {
  482. if let greeting = jsonData["chatbot_greetings"] as? String {
  483. print("Chatbot greeting: \(greeting)")
  484. Utils.setChatbotGreetings(value: greeting)
  485. }
  486. }
  487. }
  488. if let convertJsonFA = try? JSONSerialization.data(withJSONObject: jsonFA, options: .prettyPrinted) {
  489. if let jsonFAString = String(data: convertJsonFA, encoding: .utf8) {
  490. Utils.setFeatureAccess(value: jsonFAString)
  491. }
  492. }
  493. } catch {
  494. }
  495. }
  496. }
  497. }
  498. }
  499. }
  500. public static func checkingAccess(key: String) -> Bool {
  501. let dataAccess = Utils.getFeatureAccess()
  502. if dataAccess.isEmpty {
  503. if key == "sms" || key == "email" || key == "whatsapp" || key == "battery_optimization_force" || key == "backup_restore" || key == "check_sim_swap" || key == "admin_features" || key == "can_config_fb" || key == "friend_request_approval" {
  504. return false
  505. } else {
  506. return true
  507. }
  508. } else if let jsonArray = try? JSONSerialization.jsonObject(with: dataAccess.data(using: String.Encoding.utf8)!, options: []) as? [String: Any] {
  509. if jsonArray[key] != nil {
  510. return jsonArray[key] as! String == "1"
  511. } else {
  512. if key == "sms" || key == "email" || key == "whatsapp" || key == "battery_optimization_force" || key == "backup_restore" || key == "check_sim_swap" || key == "admin_features" || key == "can_config_fb" || key == "friend_request_approval" {
  513. return false
  514. } else {
  515. return true
  516. }
  517. }
  518. }
  519. return false
  520. }
  521. private static func getPullWorkingArea() {
  522. while Nexilis.isProcessWriteSync {
  523. Thread.sleep(forTimeInterval: 0.5)
  524. }
  525. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getWorkingAreaContactCenter(), timeout: 30 * 1000), response.isOk() {
  526. let data = response.getBody(key: CoreMessage_TMessageKey.DATA)
  527. if !data.isEmpty {
  528. if let jsonArray = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [AnyObject] {
  529. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  530. do {
  531. for json in jsonArray {
  532. var parent = CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.PARENT_ID)
  533. if parent.isEmpty {
  534. parent = "-99"
  535. }
  536. _ = try Database.shared.insertRecord(fmdb: fmdb, table: "WORKING_AREA", cvalues: [
  537. "area_id" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.WORKING_AREA),
  538. "name" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.NAME),
  539. "parent" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.PARENT_ID),
  540. "level" : CoreMessage_TMessageUtil.getString(json: json, key: CoreMessage_TMessageKey.LEVEL)
  541. ], replace: true)
  542. }
  543. } catch {
  544. rollback.pointee = true
  545. print("Access database error: \(error.localizedDescription)")
  546. }
  547. })
  548. }
  549. }
  550. }
  551. }
  552. public static func showForceSignIn() {
  553. let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "changeDevice") as! ChangeDeviceViewController
  554. controller.forceLogin = true
  555. let navigationController = CustomNavigationController(rootViewController: controller)
  556. navigationController.modalPresentationStyle = .fullScreen
  557. navigationController.navigationBar.tintColor = .white
  558. navigationController.navigationBar.barTintColor = UIApplication.shared.visibleViewController?.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  559. navigationController.navigationBar.isTranslucent = false
  560. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  561. navigationController.navigationBar.barStyle = .black
  562. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  563. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  564. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  565. navigationController.navigationBar.titleTextAttributes = textAttributes
  566. navigationController.modalPresentationStyle = .fullScreen
  567. navigationController.modalTransitionStyle = .crossDissolve
  568. UIApplication.shared.visibleViewController?.present(navigationController, animated: true)
  569. }
  570. public static func destroyAll() {
  571. let onGoingCC: String = SecureUserDefaults.shared.value(forKey: "onGoingCC") ?? ""
  572. if !onGoingCC.isEmpty {
  573. let requester = onGoingCC.components(separatedBy: ",")[0]
  574. let officer = onGoingCC.isEmpty ? "" : onGoingCC.components(separatedBy: ",")[1]
  575. let complaintId = onGoingCC.isEmpty ? "" : onGoingCC.components(separatedBy: ",")[2]
  576. let idMe = User.getMyPin()!
  577. let startTimeCC: String = SecureUserDefaults.shared.value(forKey: "startTimeCC") ?? ""
  578. let date = "\(Date().currentTimeMillis())"
  579. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  580. do {
  581. _ = try Database.shared.insertRecord(fmdb: fmdb, table: "CALL_CENTER_HISTORY", cvalues: [
  582. "type" : "0",
  583. "title" : "Contact Center".localized(),
  584. "time" : startTimeCC,
  585. "f_pin" : officer,
  586. "data" : complaintId,
  587. "time_end" : date,
  588. "complaint_id" : complaintId,
  589. "members" : "",
  590. "requester": requester
  591. ], replace: true)
  592. } catch {
  593. rollback.pointee = true
  594. print("Access database error: \(error.localizedDescription)")
  595. }
  596. })
  597. if officer == idMe {
  598. _ = Nexilis.write(message: CoreMessage_TMessageBank.endCallCenter(complaint_id: complaintId, l_pin: requester))
  599. } else {
  600. if requester == idMe {
  601. _ = Nexilis.write(message: CoreMessage_TMessageBank.endCallCenter(complaint_id: complaintId, l_pin: officer))
  602. } else {
  603. _ = Nexilis.write(message: CoreMessage_TMessageBank.leaveCCRoomInvite(ticket_id: complaintId))
  604. }
  605. }
  606. SecureUserDefaults.shared.removeValue(forKey: "onGoingCC")
  607. SecureUserDefaults.shared.removeValue(forKey: "membersCC")
  608. SecureUserDefaults.shared.removeValue(forKey: "startTimeCC")
  609. DispatchQueue.main.async {
  610. if UIApplication.shared.applicationState == .active {
  611. let imageView = UIImageView(image: UIImage(systemName: "info.circle"))
  612. imageView.tintColor = .white
  613. let banner = FloatingNotificationBanner(title: "Call Center Session has ended".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .info, colors: nil, iconPosition: .center)
  614. banner.show()
  615. }
  616. }
  617. }
  618. if !Nexilis.onGoingPushCC.isEmpty {
  619. DispatchQueue.global().async {
  620. _ = Nexilis.write(message: CoreMessage_TMessageBank.timeOutRequestCallCenter(channel: Nexilis.onGoingPushCC["channel"]!, l_pin: Nexilis.onGoingPushCC["l_pin"]!))
  621. }
  622. }
  623. SecureUserDefaults.shared.removeValue(forKey: "inEditorPersonal")
  624. SecureUserDefaults.shared.removeValue(forKey: "inEditorGroup")
  625. SecureUserDefaults.shared.removeValue(forKey: "waitingRequestCC")
  626. }
  627. // public static func changeUser(f_pin: String){
  628. // do {
  629. // //print("change user to fpin")
  630. // Nexilis.dispatch = DispatchGroup()
  631. // Nexilis.dispatch?.enter()
  632. //
  633. // try API.switchUser(cbiI: Callback(), sUserID: f_pin)
  634. //
  635. // // wait until connection true
  636. // Nexilis.dispatch?.wait()
  637. // Nexilis.dispatch = nil
  638. // //print("success change user to fpin")
  639. //// _ = Nexilis.write(message: CoreMessage_TMessageBank.getChangeConnectionID(p_pin: f_pin))
  640. // } catch{
  641. // //print(error)
  642. // }
  643. // }
  644. public static func apiSendChat(destination: String, message: String, isGroup: Bool, thumbnailName: String = "", imageName: String = "", videoName: String = "", fileName: String = "", audioName: String = "", replyMessageId : String = "") -> String {
  645. let message = CoreMessage_TMessageBank.sendMessage(l_pin: destination, message_scope_id: isGroup ? MessageScope.GROUP : MessageScope.WHISPER, status: "3", message_text: message, credential: "", attachment_flag: !imageName.isEmpty ? "1" : !videoName.isEmpty ? "2" : !audioName.isEmpty ? "5" : !fileName.isEmpty ? "6" : "0", ex_blog_id: "", message_large_text: "", ex_format: "", image_id: imageName, audio_id: audioName, video_id: videoName, file_id: fileName, thumb_id: thumbnailName, reff_id: replyMessageId, read_receipts: "4", chat_id: "", is_call_center: "0", call_center_id: "", opposite_pin: User.getMyPin() ?? "")
  646. addQueueMessage(message: message)
  647. return message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)
  648. }
  649. public static func apiInitiateAudioCall(destination: String) {
  650. API.initiateCCall(sParty: destination)
  651. }
  652. public static func apiReceiveAudioCall(destination: String) {
  653. API.receiveCCall(sParty: destination)
  654. }
  655. public static func apiInitiateVideoCall(destination: String, backCamera: Bool = false, listRemoteViews: [UIImageView], localView: UIImageView, remoteViewSpeaker: UIImageView) {
  656. API.initiateCCall(sParty: destination, nCamIdx: backCamera ? 0 : 1, nResIdx: 2, nVQuality: 4, ivRemoteView: listRemoteViews, ivLocalView: localView, ivRemoteZ: remoteViewSpeaker)
  657. }
  658. public static func apiReceiveVideoCall(destination: String, backCamera: Bool = false, listRemoteViews: [UIImageView], localView: UIImageView, remoteViewSpeaker: UIImageView) {
  659. API.receiveCCall(sParty: destination, nCamIdx: backCamera ? 0 : 1, nResIdx: 2, nVQuality: 4, ivRemoteView: listRemoteViews, ivLocalView: localView, ivRemoteZ: remoteViewSpeaker)
  660. }
  661. public static func apiInitiateStreaming(localView: UIImageView, titleStream: String = "", backCamera: Bool = false) {
  662. API.initiateBC(sTitle: titleStream, nCamIdx: backCamera ? 0 : 1, nResIdx: 2, nVQuality: 4, ivLocalView: localView)
  663. }
  664. public static func apiJoinStreaming(streamerId: String, remoteView: UIImageView) {
  665. API.joinBC(sBroadcasterID: streamerId, ivRemoteView: remoteView)
  666. }
  667. public static func apiTerminateStreaming(streamerId: String?) {
  668. API.terminateBC(sBroadcasterID: streamerId)
  669. }
  670. public static func apiEndAllCall() {
  671. API.terminateCall(sParty: nil)
  672. }
  673. public static func addQueueMessage(message: TMessage, isEditMessage: Bool = false) {
  674. // OutgoingThread.default.addQueue(message: message)
  675. if isEditMessage {
  676. OutgoingThread.default.addQueue(message: message)
  677. } else {
  678. InquiryThread.default.addQueue(message: message)
  679. }
  680. }
  681. public static func deleteQueueMessage(message: TMessage) {
  682. OutgoingThread.default.addQueue(message: message)
  683. }
  684. private static var wbDelegate: WhiteboardDelegate?
  685. private static var wbReceiver: WhiteboardReceiver?
  686. public static func setWhiteboardDelegate(delegate: WhiteboardDelegate?){
  687. Nexilis.wbDelegate = delegate
  688. }
  689. public static func getWhiteboardDelegate() -> WhiteboardDelegate? {
  690. return Nexilis.wbDelegate
  691. }
  692. public static func setWhiteboardReceiver(receiver: WhiteboardReceiver?){
  693. Nexilis.wbReceiver = receiver
  694. }
  695. public static func getWhiteboardReceiver() -> WhiteboardReceiver? {
  696. return Nexilis.wbReceiver
  697. }
  698. public static func getEditorPersonal() -> EditorPersonal {
  699. return AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  700. }
  701. public static func getEditorGroup() -> EditorGroup {
  702. return AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorGroupVC") as! EditorGroup
  703. }
  704. public static func getEditorStarMessage() -> EditorStarMessages {
  705. return AppStoryBoard.Palio.instance.instantiateViewController(identifier: "staredVC") as! EditorStarMessages
  706. }
  707. static func getAddress(apiKey: String) -> [String] {
  708. var result = [String]()
  709. let url = URL(string: "https://nexilis.io/dipp/NuN1v3rs3/Qm3r4i0/get_ip?account=\(apiKey)")!
  710. let urlConfig = URLSessionConfiguration.default
  711. let sessionDelegate = SelfSignedURLSessionDelegate()
  712. urlConfig.requestCachePolicy = .returnCacheDataElseLoad
  713. urlConfig.timeoutIntervalForRequest = 10.0
  714. urlConfig.timeoutIntervalForResource = 10.0
  715. let semaphore = DispatchSemaphore(value: 0)
  716. let task = URLSession(configuration: urlConfig, delegate: sessionDelegate, delegateQueue: nil).dataTask(with: url) {(data, response, error) in
  717. guard let data = data else {
  718. semaphore.signal()
  719. return
  720. }
  721. let html = String(data: data, encoding: .utf8)!
  722. let base64Address = html.components(separatedBy: "<body>")[1].components(separatedBy: "</body>")[0].trimmingCharacters(in: .whitespacesAndNewlines)
  723. if let addressData = Data(base64Encoded: base64Address), let decodeAddress = String(data: addressData, encoding: .utf8) {
  724. let rows = decodeAddress.trimmingCharacters(in: CharacterSet.newlines).split(separator: ",")
  725. for r in rows {
  726. let _address = r.split(separator: ":")
  727. var ip:String = ""
  728. let _data = _address[0].split(separator: ".", maxSplits: 4, omittingEmptySubsequences: false)
  729. ip.append(String(_data[3]))
  730. ip.append(".")
  731. ip.append(String(_data[1]))
  732. ip.append(".")
  733. ip.append(String(_data[0]))
  734. ip.append(".")
  735. ip.append(String(_data[2]))
  736. result.append(ip + ":" + _address[2])
  737. }
  738. }
  739. semaphore.signal()
  740. }
  741. task.resume()
  742. _ = semaphore.wait(timeout: .distantFuture)
  743. //print("[App] getAddress:", result)
  744. return result
  745. }
  746. static func getAddressNew(apiKey: String) -> String {
  747. var result = ""
  748. if !Utils.getHarcodedIp().isEmpty {
  749. result = Utils.getHarcodedIp()
  750. return result
  751. }
  752. let url = URL(string: "\(Utils.getDomainOpr())dipp/NuN1v3rs3/Qm3r4i0/get_ip_domain?account=\(apiKey)")!
  753. let urlConfig = URLSessionConfiguration.default
  754. let sessionDelegate = SelfSignedURLSessionDelegate()
  755. urlConfig.requestCachePolicy = .returnCacheDataElseLoad
  756. urlConfig.timeoutIntervalForRequest = 10.0
  757. urlConfig.timeoutIntervalForResource = 10.0
  758. let semaphore = DispatchSemaphore(value: 0)
  759. let task = URLSession(configuration: urlConfig, delegate: sessionDelegate, delegateQueue: nil).dataTask(with: url) {(data, response, error) in
  760. guard let data = data,
  761. let url = response?.url,
  762. let httpResponse = response as? HTTPURLResponse,
  763. let fields = httpResponse.allHeaderFields as? [String: String] else {
  764. print("MASUK SINI0 \(url)")
  765. semaphore.signal()
  766. return
  767. }
  768. let cookies = HTTPCookie.cookies(withResponseHeaderFields: fields, for: url)
  769. //print("MASUK SINI1 \(cookies)")
  770. Utils.setCookiesMobileForStorage(value: convertCookiesToJSONString(cookies: cookies) ?? "")
  771. HTTPCookieStorage.shared.setCookies(cookies, for: url, mainDocumentURL: nil)
  772. if let cookieHeader = HTTPCookie.requestHeaderFields(with: cookies)["Cookie"] {
  773. Utils.setCookiesMobile(value: cookieHeader.replacingOccurrences(of: "; ", with: ";"))
  774. }
  775. let dataEncode = String(data: data, encoding: .utf8)!
  776. // print("dataEncode \(dataEncode.trimmingCharacters(in: .whitespacesAndNewlines))")
  777. // //print("decrypt \(Utils.decrypt(str: "4=sm<wmpm1ir==>wtxxl"))")
  778. if !dataEncode.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
  779. let dataDecodeBase64 = String(data: Data(base64Encoded: dataEncode)!, encoding: .utf8)!
  780. let dataRealDecode = Utils.decrypt(str: dataDecodeBase64)
  781. // print("dataRealDecode \(dataRealDecode)")
  782. do {
  783. if let jsonData = dataRealDecode.data(using: .utf8), let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
  784. var newDomain = jsonObject["domain"] as! String
  785. let jsonAddress = jsonObject["address"] as! [[String: Any]]
  786. let newIp = jsonAddress[0]["ip"] as! String
  787. let newPort = jsonAddress[0]["portI"] as! String
  788. if newDomain.substring(from: newDomain.count-1, to: nil) != "/" {
  789. newDomain += "/"
  790. }
  791. if (newIp+":"+newPort) != Utils.getIpOpr() || newDomain != Utils.getDomainOpr() {
  792. //check new domain
  793. if checkNewDomain(newDomain) {
  794. Utils.setDomainOpr(value: newDomain)
  795. Utils.setIpPortOpr(value: (newIp+":"+newPort))
  796. }
  797. }
  798. }
  799. } catch {
  800. }
  801. }
  802. semaphore.signal()
  803. }
  804. task.resume()
  805. _ = semaphore.wait(timeout: .distantFuture)
  806. result = Utils.getIpOpr()
  807. if HTTPCookieStorage.shared.cookies(for: URL(string: Utils.getDomainOpr())!)!.count == 0 && !Utils.getCookiesMobileForStorage().isEmpty {
  808. HTTPCookieStorage.shared.setCookies(convertJSONStringToCookies(jsonString: Utils.getCookiesMobileForStorage()), for: url, mainDocumentURL: nil)
  809. }
  810. // print("[App] getAddress:", result)
  811. return result
  812. }
  813. private static func convertCookiesToJSONString(cookies: [HTTPCookie]) -> String? {
  814. let cookiesArray = cookies.map { cookie -> [String: Any] in
  815. return [
  816. "name": cookie.name,
  817. "value": cookie.value,
  818. "domain": cookie.domain,
  819. "path": cookie.path,
  820. "expiresDate": cookie.expiresDate?.timeIntervalSince1970 ?? NSNull(),
  821. "isSecure": cookie.isSecure,
  822. "isHTTPOnly": cookie.isHTTPOnly
  823. ]
  824. }
  825. if let jsonData = try? JSONSerialization.data(withJSONObject: cookiesArray, options: .prettyPrinted) {
  826. return String(data: jsonData, encoding: .utf8)
  827. }
  828. return nil
  829. }
  830. private static func convertJSONStringToCookies(jsonString: String) -> [HTTPCookie] {
  831. guard let jsonData = jsonString.data(using: .utf8),
  832. let jsonArray = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [[String: Any]] else {
  833. return []
  834. }
  835. var cookies: [HTTPCookie] = []
  836. for cookieDict in jsonArray {
  837. var properties: [HTTPCookiePropertyKey: Any] = [
  838. .name: cookieDict["name"] as? String ?? "",
  839. .value: cookieDict["value"] as? String ?? "",
  840. .domain: cookieDict["domain"] as? String ?? "",
  841. .path: cookieDict["path"] as? String ?? "/",
  842. .secure: cookieDict["isSecure"] as? Bool ?? false
  843. ]
  844. if let expiresTimeInterval = cookieDict["expiresDate"] as? TimeInterval {
  845. properties[.expires] = Date(timeIntervalSince1970: expiresTimeInterval)
  846. }
  847. if let cookie = HTTPCookie(properties: properties) {
  848. cookies.append(cookie)
  849. }
  850. }
  851. return cookies
  852. }
  853. private static func checkNewDomain(_ newDomain: String) -> Bool {
  854. var result = false
  855. let url = URL(string: "\(newDomain)dipp/NuN1v3rs3/Qm3r4i0/get_ip_domain?account=\(Nexilis.sAPIKey)")!
  856. let urlConfig = URLSessionConfiguration.default
  857. let sessionDelegate = SelfSignedURLSessionDelegate()
  858. urlConfig.requestCachePolicy = .returnCacheDataElseLoad
  859. urlConfig.timeoutIntervalForRequest = 10.0
  860. urlConfig.timeoutIntervalForResource = 10.0
  861. let semaphore = DispatchSemaphore(value: 0)
  862. let task = URLSession(configuration: urlConfig, delegate: sessionDelegate, delegateQueue: nil).dataTask(with: url) {(data, response, error) in
  863. if let httpResponse = response as? HTTPURLResponse {
  864. if httpResponse.statusCode == 200 {
  865. guard let url = response?.url,
  866. let fields = httpResponse.allHeaderFields as? [String: String] else {
  867. semaphore.signal()
  868. return
  869. }
  870. let cookies = HTTPCookie.cookies(withResponseHeaderFields: fields, for: url)
  871. HTTPCookieStorage.shared.setCookies(cookies, for: url, mainDocumentURL: nil)
  872. Utils.setCookiesMobileForStorage(value: convertCookiesToJSONString(cookies: cookies) ?? "")
  873. if let cookieHeader = HTTPCookie.requestHeaderFields(with: cookies)["Cookie"] {
  874. Utils.setCookiesMobile(value: cookieHeader.replacingOccurrences(of: "; ", with: ";"))
  875. }
  876. result = true
  877. }
  878. }
  879. semaphore.signal()
  880. }
  881. task.resume()
  882. _ = semaphore.wait(timeout: .distantFuture)
  883. return result
  884. }
  885. static func getCLMUserId() -> String {
  886. guard let me = User.getMyPin() else {
  887. return ""
  888. }
  889. return me
  890. }
  891. public static var isProcessWriteSync = false
  892. public static func writeSync(message: TMessage, timeout: Int = 15 * 1000) -> TMessage? {
  893. isProcessWriteSync = true
  894. do {
  895. // print(">> SENDING MESSAGE >> ", message.toLogString())
  896. if let data = try API.sGetResponse(sRequest: message.pack(), lTimeout: timeout, bKeepTOResp: true) {
  897. let response = TMessage(data: data)
  898. // print(">> RESPONSE WRITESYNC >> ")
  899. // print("<< RESPONSE MESSAGE << ", response.toLogString())
  900. isProcessWriteSync = false
  901. return response
  902. }
  903. } catch {
  904. //print(error)
  905. }
  906. return nil
  907. }
  908. public static func write(message: TMessage, timeout: Int = 15 * 1000) -> String? {
  909. do {
  910. if API.nGetCLXConnState() == 0 {
  911. return nil
  912. }
  913. //print(">> SENDING MESSAGE >> ", message.toLogString())
  914. if message.getMedia().count == 0 {
  915. if let data = try API.sSend(sData: message.pack(), nPriority: 1, lTimeout: timeout) {
  916. //print("<< RESPONSE MESSAGE << ", data)
  917. return data
  918. }
  919. }
  920. // media
  921. if let data = try API.sSend(abData: message.toBytes(), nPriority: 2, lTimeout: timeout) {
  922. //print("<< RESPONSE MESSAGE << ", data)
  923. return data
  924. }
  925. } catch {
  926. //print(error)
  927. }
  928. return nil
  929. }
  930. public static func writeDraw(data: String, timeout: Int = 15 * 1000) -> String? {
  931. do {
  932. if !API.bInetConnAvailable() {
  933. return nil
  934. }
  935. //print(">> SENDING MESSAGE >> ", data)
  936. if let data = try API.sSend(sData: data, nPriority: 1, lTimeout: timeout) {
  937. //print("<< RESPONSE MESSAGE << ", data)
  938. return data
  939. }
  940. } catch {
  941. //print(error)
  942. }
  943. return nil
  944. }
  945. public static func response(packetId: String, message: TMessage, timeout: Int = 15 * 1000) -> String? {
  946. var result: String? = nil
  947. do {
  948. if !API.bInetConnAvailable() {
  949. return nil
  950. }
  951. //print(">> RESPONSE >> " + packetId + " " + message.toLogString());
  952. result = try API.sSendResponse(sRequestID: packetId, sResponse: message.pack(), lTimeout: timeout)
  953. } catch {
  954. //print(error)
  955. }
  956. return result
  957. }
  958. public static func responseString(packetId: String, message: String, timeout: Int = 15 * 1000) -> String? {
  959. var result: String? = nil
  960. do {
  961. if !API.bInetConnAvailable() {
  962. return nil
  963. }
  964. //print(">> RESPONSE >> " + packetId + " " + message);
  965. result = try API.sSendResponse(sRequestID: packetId, sResponse: message, lTimeout: timeout)
  966. } catch {
  967. //print(error)
  968. }
  969. return result
  970. }
  971. public static func setSpeaker(_ isEnabled: Bool, isVideo: Bool = false) {
  972. do {
  973. API.adjustVolume(fValue: isEnabled ? 10.0: isVideo ? 0.0 : 3.0)
  974. } catch {
  975. }
  976. }
  977. public static func buttonClicked(index: Int, id: String = "") {
  978. //print("BTNCLICK \(index) \(id)")
  979. if index == IDX_QUEUE_SYSTEM || index == IDX_NEWS || index == IDX_SOCIAL_COMMERCE {
  980. if id == "fb\(index)"{
  981. APIS.openUrl(url: "https://google.com/")
  982. } else {
  983. APIS.openUrl(url: id)
  984. }
  985. } else if index == IDX_NOTIF_CENTER {
  986. APIS.openNotificationCenter()
  987. } else if index == IDX_CHAT {
  988. APIS.openChat()
  989. } else if index == IDX_CALL {
  990. APIS.openCall()
  991. } else if index == IDX_STREAM {
  992. APIS.openStreaming()
  993. } else if index == IDX_CC {
  994. APIS.openContactCenter()
  995. } else if index == IDX_ADDFRIEND {
  996. APIS.openAddFriend()
  997. } else if index == IDX_WB_SS {
  998. APIS.openWhiteboardAndScreenSharing()
  999. } else if index == IDX_WHITEBOARD {
  1000. APIS.openWhiteboard()
  1001. } else if index == IDX_SCREENSHARING {
  1002. APIS.openWhiteboardAndScreenSharing()
  1003. } else if index == IDX_POST {
  1004. } else if index == IDX_CONVERSATION {
  1005. APIS.openConversation()
  1006. } else if index == IDX_FAVORITEMESSAGE {
  1007. APIS.openFavoriteMessage()
  1008. } else if index == IDX_SECURE_FOLDER {
  1009. APIS.openSecureFolder()
  1010. } else if index == IDX_SECURE_BROWSER {
  1011. APIS.openSecureBrowser()
  1012. } else if index == IDX_CONFERENCE_ROOM_FORM {
  1013. APIS.openConference()
  1014. } else if index == IDX_SETTING {
  1015. if Nexilis.floatingButton.mySettingDelegate != nil {
  1016. Nexilis.floatingButton.mySettingDelegate?.settingDelegate()
  1017. } else {
  1018. APIS.openSetting()
  1019. }
  1020. } else if index == IDX_SELF_ACT {
  1021. openApp(id: id)
  1022. }
  1023. }
  1024. public static func openApp(id: String) {
  1025. //print("openApp itms-apps://apple.com/app/\(id)")
  1026. let isChangeProfile = Utils.getSetProfile()
  1027. if !isChangeProfile {
  1028. let alert = LibAlertController(title: "Set Profile".localized(), message: "You must set your profile to use this feature".localized(), preferredStyle: .alert)
  1029. alert.addAction(UIAlertAction(title: "OK".localized(), style: UIAlertAction.Style.default, handler: {(_) in
  1030. let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "signupsignin") as! SignUpSignIn
  1031. controller.forceLogin = true
  1032. let navigationController = CustomNavigationController(rootViewController: controller)
  1033. navigationController.modalPresentationStyle = .fullScreen
  1034. navigationController.navigationBar.tintColor = .white
  1035. navigationController.navigationBar.barTintColor = UIApplication.shared.visibleViewController?.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  1036. navigationController.navigationBar.isTranslucent = false
  1037. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  1038. navigationController.navigationBar.barStyle = .black
  1039. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  1040. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  1041. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  1042. navigationController.navigationBar.titleTextAttributes = textAttributes
  1043. if UIApplication.shared.visibleViewController?.navigationController != nil {
  1044. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  1045. } else {
  1046. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  1047. }
  1048. }))
  1049. if UIApplication.shared.visibleViewController?.navigationController != nil {
  1050. UIApplication.shared.visibleViewController?.navigationController?.present(alert, animated: true, completion: nil)
  1051. } else {
  1052. UIApplication.shared.visibleViewController?.present(alert, animated: true, completion: nil)
  1053. }
  1054. return
  1055. }
  1056. if id == nil {
  1057. return
  1058. }
  1059. if let url = URL(string: "itms-apps://apple.com/app/\(id)") {
  1060. UIApplication.shared.open(url)
  1061. }
  1062. }
  1063. static func openmailAction(subject: String = "", body: String = "", to: String = "") {
  1064. let subjectEncoded = subject.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
  1065. let bodyEncoded = body.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
  1066. let toEmail = to
  1067. let gmailUrl = URL(string: "googlegmail://co?to=\(toEmail)&subject=\(subjectEncoded)&body=\(bodyEncoded)")!
  1068. let outlookUrl = URL(string: "ms-outlook://compose?to=\(toEmail)&subject=\(subjectEncoded)&body=\(bodyEncoded)")!
  1069. let yahooMail = URL(string: "ymail://mail/compose?to=\(toEmail)&subject=\(subjectEncoded)&body=\(bodyEncoded)")!
  1070. let sparkUrl = URL(string: "readdle-spark://compose?recipient=\(toEmail)&subject=\(subjectEncoded)&body=\(bodyEncoded)")!
  1071. let defaultUrl = URL(string: "mailto:\(toEmail)?subject=\(subjectEncoded)&body=\(bodyEncoded)")!
  1072. if UIApplication.shared.canOpenURL(gmailUrl as URL) {
  1073. openMail(gmailUrl)
  1074. } else if UIApplication.shared.canOpenURL(outlookUrl as URL) {
  1075. openMail(outlookUrl)
  1076. } else if UIApplication.shared.canOpenURL(yahooMail as URL) {
  1077. openMail(yahooMail)
  1078. } else if UIApplication.shared.canOpenURL(sparkUrl as URL) {
  1079. openMail(sparkUrl)
  1080. } else if UIApplication.shared.canOpenURL(defaultUrl as URL) {
  1081. openMail(defaultUrl)
  1082. }
  1083. }
  1084. private static func openMail(_ url: URL) {
  1085. UIApplication.shared.open(url as URL, options: [:], completionHandler: nil)
  1086. }
  1087. static var alertChangeProfile = LibAlertController()
  1088. public static func checkIsChangePerson() -> Bool {
  1089. let isChangeProfile = Utils.getSetProfile()
  1090. if !isChangeProfile {
  1091. alertChangeProfile.dismiss(animated: false)
  1092. alertChangeProfile = LibAlertController(title: "Set Profile".localized(), message: "You must set your profile to use this feature".localized(), preferredStyle: .alert)
  1093. alertChangeProfile.addAction(UIAlertAction(title: "Cancel".localized(), style: .destructive, handler: nil))
  1094. alertChangeProfile.addAction(UIAlertAction(title: "OK".localized(), style: UIAlertAction.Style.default, handler: {(_) in
  1095. let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "signupsignin") as! SignUpSignIn
  1096. controller.forceLogin = true
  1097. let navigationController = CustomNavigationController(rootViewController: controller)
  1098. navigationController.modalPresentationStyle = .fullScreen
  1099. navigationController.navigationBar.tintColor = .white
  1100. navigationController.navigationBar.barTintColor = UIApplication.shared.visibleViewController?.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  1101. navigationController.navigationBar.isTranslucent = false
  1102. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  1103. navigationController.navigationBar.barStyle = .black
  1104. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  1105. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  1106. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  1107. navigationController.navigationBar.titleTextAttributes = textAttributes
  1108. let rootVC = UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.rootViewController
  1109. if rootVC?.presentedViewController == nil {
  1110. rootVC?.present(navigationController, animated: true, completion: nil)
  1111. } else {
  1112. rootVC?.presentedViewController?.present(navigationController, animated: true, completion: nil)
  1113. }
  1114. }))
  1115. let rootVC = UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.rootViewController
  1116. if rootVC?.presentedViewController == nil {
  1117. rootVC?.present(alertChangeProfile, animated: true, completion: nil)
  1118. } else {
  1119. rootVC?.presentedViewController?.present(alertChangeProfile, animated: true, completion: nil)
  1120. }
  1121. return false
  1122. }
  1123. return true
  1124. }
  1125. public static func showLoader() {
  1126. loadingAlert = LibAlertController(title: nil, message: "Please wait...".localized(), preferredStyle: .alert)
  1127. let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
  1128. loadingIndicator.hidesWhenStopped = true
  1129. loadingIndicator.style = .medium
  1130. loadingIndicator.startAnimating()
  1131. loadingAlert.view.addSubview(loadingIndicator)
  1132. UIApplication.shared.visibleViewController?.present(loadingAlert, animated: true, completion: nil)
  1133. }
  1134. public static func hideLoader(completion: @escaping () -> ()) {
  1135. loadingAlert.dismiss(animated: true, completion: completion)
  1136. }
  1137. private static var groupWait = DispatchGroup()
  1138. private static var waitQueue = [String: TMessage]()
  1139. private static var onDispatchGroupLeave = ""
  1140. public static func writeAndWait(message: TMessage, timeout: Int = 15 * 1000) -> TMessage? {
  1141. groupWait.enter()
  1142. _ = write(message: message, timeout: timeout)
  1143. waitQueue[message.getStatus()] = message
  1144. if groupWait.wait(timeout: .now() + 15) == .timedOut {
  1145. waitQueue.removeValue(forKey: message.getStatus())
  1146. groupWait.leave()
  1147. return nil
  1148. }
  1149. return waitQueue.removeValue(forKey: message.getStatus())
  1150. }
  1151. static func incomingData(packetId: String, data: AnyObject) {
  1152. let message = TMessage()
  1153. if data is String {
  1154. let d = data as! String
  1155. guard message.unpack(data: d) else {
  1156. //print("UNKNOWN DATA STRING...", data)
  1157. if(data.hasPrefix("WB")){
  1158. let dataWB = data.components(separatedBy: "/")
  1159. if(dataWB[1] == "1"){
  1160. let x = dataWB[2]
  1161. let y = dataWB[3]
  1162. let w = dataWB[4]
  1163. let h = dataWB[5]
  1164. let fc = dataWB[6]
  1165. let sw = dataWB[7]
  1166. let xo = dataWB[8]
  1167. let yo = dataWB[9]
  1168. if(Nexilis.getWhiteboardDelegate() != nil){
  1169. Nexilis.getWhiteboardDelegate()!.draw(x: x, y: y, w: w, h: h, fc: fc, sw: sw, xo: xo, yo: yo, data: "")
  1170. }
  1171. } else if(dataWB[1] == "3") {
  1172. if(Nexilis.getWhiteboardDelegate() != nil){
  1173. Nexilis.getWhiteboardDelegate()!.clear()
  1174. }
  1175. } else if(dataWB[1] == "2"){
  1176. if(Nexilis.getWhiteboardReceiver() != nil){
  1177. Nexilis.getWhiteboardReceiver()!.incomingWB(roomId: dataWB[2])
  1178. }
  1179. } else if(dataWB[1] == "22"){
  1180. } else if(dataWB[1] == "88"){
  1181. if(Nexilis.getWhiteboardReceiver() != nil){
  1182. Nexilis.getWhiteboardReceiver()!.cancel(roomId: dataWB[2])
  1183. }
  1184. }
  1185. }
  1186. return
  1187. }
  1188. } else if data is [UInt8] {
  1189. let d = data as! [UInt8]
  1190. guard message.unpack(bytes_data: d) else {
  1191. //print("UNKNOWN DATA BYTES...", data)
  1192. return
  1193. }
  1194. }
  1195. message.mBodies[CoreMessage_TMessageKey.PACKET_ID] = packetId
  1196. if let _ = waitQueue[message.getStatus()] {
  1197. //print("MESSAGE INCOMING DATA \(message.toLogString())")
  1198. if message.mBodies.keys.contains(CoreMessage_TMessageKey.ERRCOD) {
  1199. if onDispatchGroupLeave != message.getStatus() {
  1200. onDispatchGroupLeave = message.getStatus()
  1201. //print("LEAVE GROUP INCOMING DATA")
  1202. waitQueue[message.getStatus()] = message
  1203. groupWait.leave()
  1204. return
  1205. }
  1206. }
  1207. }
  1208. IncomingThread.default.addQueue(message: message)
  1209. }
  1210. static func saveMessage(message: TMessage, withStatus: Bool = true, fromAPNS: Bool = false) {
  1211. // print("save message \(message.toLogString())")
  1212. guard let me = User.getMyPin() else {
  1213. return
  1214. }
  1215. let message_id = message.getBody(key : CoreMessage_TMessageKey.MESSAGE_ID, default_value : "")
  1216. guard !message_id.isEmpty else {
  1217. if message.getBody(key: CoreMessage_TMessageKey.ATTACHMENT_FLAG) == "61" {
  1218. let nameReq = message.getBody(key: CoreMessage_TMessageKey.MESSAGE_TEXT)
  1219. let nameFpin = message.getBody(key: CoreMessage_TMessageKey.F_PIN)
  1220. var messageExist = false
  1221. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  1222. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select message_id from MESSAGE where attachment_flag = '61' and blog_id = '\(nameFpin)'"), cursor.next() {
  1223. messageExist = true
  1224. cursor.close()
  1225. }
  1226. })
  1227. if !messageExist {
  1228. Nexilis.saveMessageBot(textMessage: "*\(nameReq.trimmingCharacters(in: .whitespaces))*" + " " + "has requested to be your friend", blog_id: nameFpin, attachment_type: "61")
  1229. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
  1230. }
  1231. }
  1232. return
  1233. }
  1234. let f_pin = message.getBody(key : CoreMessage_TMessageKey.F_PIN, default_value : "")
  1235. guard !f_pin.isEmpty else {
  1236. return
  1237. }
  1238. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  1239. do {
  1240. var messageExist = false
  1241. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select message_id from MESSAGE where message_id = '\(message_id)'"), cursor.next() {
  1242. messageExist = true
  1243. cursor.close()
  1244. }
  1245. let l_pin = message.getBody(key : CoreMessage_TMessageKey.L_PIN, default_value : "")
  1246. let scope = message.getBody(key : CoreMessage_TMessageKey.MESSAGE_SCOPE_ID, default_value : MessageScope.WHISPER)
  1247. let status = message.getBody(key : CoreMessage_TMessageKey.STATUS, default_value : "")
  1248. let chat_id = message.getBody(key : CoreMessage_TMessageKey.CHAT_ID, default_value : "")
  1249. let broadcast_flag = message.getBody(key: CoreMessage_TMessageKey.BROADCAST_FLAG, default_value: "0")
  1250. let is_call_center = message.getBody(key: CoreMessage_TMessageKey.IS_CALL_CENTER, default_value: "0")
  1251. let call_center_id = message.getBody(key: CoreMessage_TMessageKey.CALL_CENTER_ID, default_value: "")
  1252. let last_edited = message.getBodyAsLong(key: CoreMessage_TMessageKey.LAST_EDIT, default_value: 0)
  1253. let is_secret = message.getBodyAsLong(key: CoreMessage_TMessageKey.IS_SECRET, default_value: 0)
  1254. let is_delete_retention = message.getBodyAsLong(key: CoreMessage_TMessageKey.IS_DELETED_RETENTION, default_value: 0)
  1255. let is_forwarded_message = message.getBodyAsLong(key: CoreMessage_TMessageKey.IS_FORWARDED_MESSAGE, default_value: 0)
  1256. let opposite_pin = message.getBody(key: CoreMessage_TMessageKey.OPPOSITE_PIN, default_value: "")
  1257. //print("prepare save db")
  1258. do {
  1259. _ = try Database.shared.insertRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
  1260. "message_id" : message_id,
  1261. "f_pin" : f_pin,
  1262. "f_display_name" : message.getBody(key : CoreMessage_TMessageKey.F_DISPLAY_NAME, default_value : ""),
  1263. "l_pin" : l_pin,
  1264. "l_user_id" : message.getBody(key : CoreMessage_TMessageKey.L_USER_ID, default_value : ""),
  1265. "message_scope_id" : scope,
  1266. "server_date" : message.getBody(key: CoreMessage_TMessageKey.SERVER_DATE, default_value : String(Date().currentTimeMillis())),
  1267. "status" : status,
  1268. "message_text" : message.getBody(key : CoreMessage_TMessageKey.MESSAGE_TEXT, default_value : "").toNormalString(),
  1269. "audio_id" : message.getBody(key : CoreMessage_TMessageKey.AUDIO_ID, default_value : ""),
  1270. "video_id" : message.getBody(key : CoreMessage_TMessageKey.VIDEO_ID, default_value : ""),
  1271. "image_id" : message.getBody(key : CoreMessage_TMessageKey.IMAGE_ID, default_value : ""),
  1272. "file_id" : message.getBody(key : CoreMessage_TMessageKey.FILE_ID, default_value : ""),
  1273. "gif_id" : message.getBody(key : CoreMessage_TMessageKey.GIF_ID, default_value : ""),
  1274. "thumb_id" : message.getBody(key : CoreMessage_TMessageKey.THUMB_ID, default_value : ""),
  1275. "opposite_pin" : message.getBody(key : CoreMessage_TMessageKey.OPPOSITE_PIN, default_value : ""),
  1276. "format" : message.getBody(key : CoreMessage_TMessageKey.FORMAT, default_value : ""),
  1277. "blog_id" : message.getBody(key : CoreMessage_TMessageKey.BLOG_ID, default_value : ""),
  1278. "read_receipts" : message.getBody(key: CoreMessage_TMessageKey.READ_RECEIPTS, default_value: "0"),
  1279. "chat_id" : chat_id,
  1280. "account_type" : message.getBody(key : CoreMessage_TMessageKey.BUSINESS_CATEGORY, default_value : "1"),
  1281. "credential" : message.getBody(key : CoreMessage_TMessageKey.CREDENTIAL, default_value : ""),
  1282. "reff_id" : message.getBody(key : CoreMessage_TMessageKey.REF_ID, default_value : ""),
  1283. "message_large_text" : message.getBody(key : CoreMessage_TMessageKey.BODY, default_value : "").toNormalString(),
  1284. "attachment_flag" : message.getBody(key: CoreMessage_TMessageKey.ATTACHMENT_FLAG, default_value: "0"),
  1285. "local_timestamp" : message.getBody(key: CoreMessage_TMessageKey.LOCAL_TIMESTAMP, default_value : String(Date().currentTimeMillis())),
  1286. "broadcast_flag" : broadcast_flag,
  1287. "is_call_center" : is_call_center,
  1288. "call_center_id" : call_center_id,
  1289. "last_edited" : last_edited,
  1290. "is_secret" : is_secret,
  1291. "is_deleted_retention" : is_delete_retention,
  1292. "is_forwarded_message" : is_forwarded_message
  1293. ], replace: true)
  1294. } catch {
  1295. rollback.pointee = true
  1296. //print(error)
  1297. }
  1298. if withStatus {
  1299. do {
  1300. if scope == MessageScope.GROUP {
  1301. for pin in getGroupMembers(fmdb: fmdb, l_pin: l_pin) {
  1302. if f_pin == pin { continue }
  1303. _ = try Database.shared.insertRecord(fmdb: fmdb, table: "MESSAGE_STATUS", cvalues: [
  1304. "message_id" : message_id,
  1305. "status" : status,
  1306. "f_pin" : pin,
  1307. "last_update" : Date().currentTimeMillis()
  1308. ], replace: true)
  1309. }
  1310. } else {
  1311. _ = try Database.shared.insertRecord(fmdb: fmdb, table: "MESSAGE_STATUS", cvalues: [
  1312. "message_id" : message_id,
  1313. "status" : status,
  1314. "f_pin" : l_pin,
  1315. "last_update" : Date().currentTimeMillis()
  1316. ], replace: true)
  1317. }
  1318. } catch {
  1319. rollback.pointee = true
  1320. //print(error)
  1321. }
  1322. }
  1323. var pin = opposite_pin
  1324. if pin.isEmpty {
  1325. if scope == MessageScope.GROUP {
  1326. pin = chat_id.isEmpty ? l_pin : chat_id
  1327. } else {
  1328. pin = f_pin
  1329. }
  1330. }
  1331. if pin == me {
  1332. pin = l_pin
  1333. }
  1334. var counter : Int? = nil
  1335. if !withStatus {
  1336. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select counter from MESSAGE_SUMMARY where l_pin = '\(pin)'"), cursor.next() {
  1337. counter = Int(cursor.int(forColumnIndex: 0))
  1338. if last_edited == 0 && !messageExist {
  1339. counter! += 1
  1340. }
  1341. cursor.close()
  1342. //print("select db message summary")
  1343. }
  1344. if counter == nil {
  1345. counter = 1
  1346. //print("set counter message summary")
  1347. }
  1348. }
  1349. if is_call_center == "0" {
  1350. do {
  1351. var queryGetLastMessageId = "SELECT message_id FROM MESSAGE where (f_pin = '\(pin)' OR l_pin = '\(pin)') AND message_scope_id = '\(MessageScope.WHISPER)' order by server_date desc LIMIT 1"
  1352. if scope == "4" {
  1353. queryGetLastMessageId = "SELECT message_id FROM MESSAGE where l_pin = '\(chat_id.isEmpty ? pin : l_pin)' AND chat_id = '\(chat_id)' AND message_scope_id = '\(MessageScope.GROUP)' order by server_date desc LIMIT 1"
  1354. }
  1355. var messageId = ""
  1356. if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: queryGetLastMessageId), cursorData.next() {
  1357. messageId = cursorData.string(forColumnIndex: 0) ?? ""
  1358. cursorData.close()
  1359. }
  1360. if !messageId.isEmpty {
  1361. _ = try Database.shared.insertRecord(fmdb: fmdb, table: "MESSAGE_SUMMARY", cvalues: [
  1362. "l_pin" : pin,
  1363. "message_id" : messageId,
  1364. "counter" : counter ?? 0
  1365. ], replace: true)
  1366. }
  1367. } catch {
  1368. rollback.pointee = true
  1369. //print(error)
  1370. }
  1371. }
  1372. if !withStatus && !fromAPNS && (!messageExist || last_edited != 0) {
  1373. DispatchQueue.main.async {
  1374. if let delegate = Nexilis.shared.messageDelegate, Utils.getSetProfile() {
  1375. message.mBodies[CoreMessage_TMessageKey.MESSAGE_TEXT] = message.getBody(key : CoreMessage_TMessageKey.MESSAGE_TEXT, default_value : "").toNormalString()
  1376. delegate.onReceive(message: message)
  1377. }
  1378. }
  1379. }
  1380. //print("insert db message summary \(message_id)")
  1381. } catch {
  1382. rollback.pointee = true
  1383. print("Access database error: \(error.localizedDescription)")
  1384. }
  1385. })
  1386. }
  1387. public static func saveMessageBot(textMessage: String, blog_id: String, attachment_type:String)->Void{
  1388. guard let me = User.getMyPin() else {
  1389. return
  1390. }
  1391. var user_id:String? = ""
  1392. let message_id = me + CoreMessage_TMessageUtil.getTID()
  1393. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  1394. do {
  1395. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select user_id from BUDDY where f_pin = '\(me)'"), cursor.next() {
  1396. user_id = cursor.string(forColumnIndex: 0)
  1397. cursor.close()
  1398. }
  1399. } catch {
  1400. rollback.pointee = true
  1401. print("Access database error: \(error.localizedDescription)")
  1402. }
  1403. })
  1404. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  1405. do {
  1406. _ = try Database.shared.insertRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
  1407. "message_id" : message_id ,
  1408. "f_pin" : "-999",
  1409. "f_display_name" : "Bot",
  1410. "l_pin" : me,
  1411. "l_user_id" : String(user_id!),
  1412. "message_scope_id" : MessageScope.WHISPER,
  1413. "server_date" : String(Date().currentTimeMillis()),
  1414. "status" : "3",
  1415. "message_text" : textMessage,
  1416. "audio_id" : "",
  1417. "video_id" : "",
  1418. "image_id" : "",
  1419. "file_id" : "",
  1420. "thumb_id" : "",
  1421. "opposite_pin" : "",
  1422. "format" : "",
  1423. "blog_id" : blog_id,
  1424. "read_receipts" : "0",
  1425. "chat_id" : "",
  1426. "account_type" : "1",
  1427. "credential" :"",
  1428. "reff_id" : "",
  1429. "message_large_text" : "",
  1430. "attachment_flag" : attachment_type,
  1431. "local_timestamp" : String(Date().currentTimeMillis())
  1432. ], replace: true)
  1433. } catch {
  1434. rollback.pointee = true
  1435. print("Access database error: \(error.localizedDescription)")
  1436. }
  1437. })
  1438. let pin = "-999"
  1439. var counter : Int? = nil
  1440. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  1441. do {
  1442. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select counter from MESSAGE_SUMMARY where l_pin = '\(pin)'"), cursor.next() {
  1443. counter = Int(cursor.int(forColumnIndex: 0))
  1444. counter! += 1
  1445. cursor.close()
  1446. //print("select db message summary")
  1447. }
  1448. } catch {
  1449. rollback.pointee = true
  1450. print("Access database error: \(error.localizedDescription)")
  1451. }
  1452. })
  1453. if counter == nil {
  1454. counter = 1
  1455. //print("set counter message summary")
  1456. }
  1457. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  1458. do {
  1459. _ = try Database.shared.insertRecord(fmdb: fmdb, table: "MESSAGE_SUMMARY", cvalues: [
  1460. "l_pin" : pin,
  1461. "message_id" : message_id,
  1462. "counter" : counter!
  1463. ], replace: true)
  1464. } catch {
  1465. rollback.pointee = true
  1466. print("Access database error: \(error.localizedDescription)")
  1467. }
  1468. })
  1469. //print("insert db message summary \(message_id)")
  1470. }
  1471. public static func saveMessageCall(idCall: String, textMessage: String, fPin: String, lPin: String, timeCall: String, attachment_type:String) {
  1472. guard let me = User.getMyPin() else {
  1473. return
  1474. }
  1475. let dataFpin = User.getDataCanNil(pin: fPin)
  1476. let dataLpin = User.getDataCanNil(pin: lPin)
  1477. var messageExist = false
  1478. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  1479. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select server_date from MESSAGE where server_date = '\(timeCall)'"), cursor.next() {
  1480. messageExist = true
  1481. cursor.close()
  1482. }
  1483. })
  1484. if messageExist {
  1485. return
  1486. }
  1487. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  1488. do {
  1489. _ = try Database.shared.insertRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
  1490. "message_id" : idCall ,
  1491. "f_pin" : fPin,
  1492. "f_display_name" : dataFpin != nil ? dataFpin!.fullName : "",
  1493. "l_pin" : lPin,
  1494. "l_user_id" : dataLpin != nil ? dataLpin!.pin : "",
  1495. "message_scope_id" : attachment_type,
  1496. "server_date" : timeCall,
  1497. "status" : "3",
  1498. "message_text" : textMessage,
  1499. "audio_id" : "",
  1500. "video_id" : "",
  1501. "image_id" : "",
  1502. "file_id" : "",
  1503. "thumb_id" : "",
  1504. "opposite_pin" : "",
  1505. "format" : "",
  1506. "blog_id" : "",
  1507. "read_receipts" : "0",
  1508. "chat_id" : "",
  1509. "account_type" : "1",
  1510. "credential" :"",
  1511. "reff_id" : "",
  1512. "message_large_text" : "",
  1513. "attachment_flag" : attachment_type,
  1514. "local_timestamp" : timeCall
  1515. ], replace: true)
  1516. } catch {
  1517. rollback.pointee = true
  1518. print("Access database error: \(error.localizedDescription)")
  1519. }
  1520. })
  1521. let pin = lPin == me ? fPin : lPin
  1522. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  1523. do {
  1524. _ = try Database.shared.insertRecord(fmdb: fmdb, table: "MESSAGE_SUMMARY", cvalues: [
  1525. "l_pin" : pin,
  1526. "message_id" : idCall,
  1527. "counter" : 0
  1528. ], replace: true)
  1529. } catch {
  1530. rollback.pointee = true
  1531. print("Access database error: \(error.localizedDescription)")
  1532. }
  1533. })
  1534. var dataMessage: [AnyHashable : Any] = [:]
  1535. dataMessage["message_id"] = idCall
  1536. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "refreshCallLog"), object: nil, userInfo: dataMessage)
  1537. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
  1538. }
  1539. static func updateMessageStatus(message: TMessage) -> Void {
  1540. let message_id = message.getBody(key : CoreMessage_TMessageKey.MESSAGE_ID, default_value : "")
  1541. guard !message_id.isEmpty else {
  1542. return
  1543. }
  1544. let status = message.getBody(key : CoreMessage_TMessageKey.STATUS, default_value : "")
  1545. let latitude = message.getBody(key : CoreMessage_TMessageKey.LATITUDE, default_value : "")
  1546. let longitude = message.getBody(key : CoreMessage_TMessageKey.LONGITUDE, default_value : "")
  1547. let desc = message.getBody(key : CoreMessage_TMessageKey.DESCRIPTION, default_value : "")
  1548. guard !status.isEmpty else {
  1549. return
  1550. }
  1551. let l_pin = message.getBody(key : CoreMessage_TMessageKey.L_PIN, default_value : "")
  1552. guard !l_pin.isEmpty else {
  1553. return
  1554. }
  1555. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  1556. do {
  1557. if message_id.starts(with: "-1") || message_id.starts(with: "-2") {
  1558. for s in message_id.split(separator: ",") {
  1559. let t = s.trimmingCharacters(in: .whitespaces)
  1560. if t == "-1" || t == "-2" {
  1561. continue
  1562. }
  1563. if let cursorStatus = Database.shared.getRecords(fmdb: fmdb, query: "SELECT status FROM MESSAGE_STATUS where message_id = '\(t)'"), cursorStatus.next() {
  1564. let lastStatus = cursorStatus.int(forColumnIndex: 0)
  1565. if lastStatus < Int(status)! {
  1566. if status == "3" {
  1567. _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE_STATUS", cvalues: [
  1568. "status" : status,
  1569. "longitude" : longitude,
  1570. "latitude" : latitude,
  1571. "location" : desc,
  1572. "time_delivered" : String(Date().currentTimeMillis()),
  1573. "last_update" : String(Date().currentTimeMillis())], _where: "message_id = '\(t)' and f_pin = '\(l_pin)'")
  1574. } else if status == "4" {
  1575. _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE_STATUS", cvalues: [
  1576. "status" : status,
  1577. "time_read" : String(Date().currentTimeMillis()),
  1578. "longitude" : longitude,
  1579. "latitude" : latitude,
  1580. "location" : desc,
  1581. "last_update" : String(Date().currentTimeMillis())], _where: "message_id = '\(t)' and f_pin = '\(l_pin)'")
  1582. } else if status == "8" {
  1583. _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE_STATUS", cvalues: [
  1584. "status" : status,
  1585. "time_ack" : String(Date().currentTimeMillis()),
  1586. "longitude" : longitude,
  1587. "latitude" : latitude,
  1588. "location" : desc,
  1589. "last_update" : String(Date().currentTimeMillis())], _where: "message_id = '\(t)' and f_pin = '\(l_pin)'")
  1590. } else {
  1591. _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE_STATUS", cvalues: [
  1592. "status" : status,
  1593. "last_update" : String(Date().currentTimeMillis())], _where: "message_id = '\(t)' and f_pin = '\(l_pin)'")
  1594. }
  1595. }
  1596. cursorStatus.close()
  1597. }
  1598. }
  1599. } else {
  1600. if let cursorStatus = Database.shared.getRecords(fmdb: fmdb, query: "SELECT status FROM MESSAGE_STATUS where message_id = '\(message_id)'"), cursorStatus.next() {
  1601. let lastStatus = cursorStatus.int(forColumnIndex: 0)
  1602. if lastStatus < Int(status)! {
  1603. if status == "3" {
  1604. _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE_STATUS", cvalues: [
  1605. "status" : status,
  1606. "time_delivered" : String(Date().currentTimeMillis()),
  1607. "longitude" : longitude,
  1608. "latitude" : latitude,
  1609. "location" : desc,
  1610. "last_update" : String(Date().currentTimeMillis())], _where: "message_id = '\(message_id)' and f_pin = '\(l_pin)'")
  1611. } else if status == "4" {
  1612. _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE_STATUS", cvalues: [
  1613. "status" : status,
  1614. "time_read" : String(Date().currentTimeMillis()),
  1615. "longitude" : longitude,
  1616. "latitude" : latitude,
  1617. "location" : desc,
  1618. "last_update" : String(Date().currentTimeMillis())], _where: "message_id = '\(message_id)' and f_pin = '\(l_pin)'")
  1619. } else if status == "8" {
  1620. _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE_STATUS", cvalues: [
  1621. "status" : status,
  1622. "time_ack" : String(Date().currentTimeMillis()),
  1623. "longitude" : longitude,
  1624. "latitude" : latitude,
  1625. "location" : desc,
  1626. "last_update" : String(Date().currentTimeMillis())], _where: "message_id = '\(message_id)' and f_pin = '\(l_pin)'")
  1627. } else {
  1628. _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE_STATUS", cvalues: [
  1629. "status" : status,
  1630. "longitude" : longitude,
  1631. "latitude" : latitude,
  1632. "location" : desc,
  1633. "last_update" : String(Date().currentTimeMillis())], _where: "message_id = '\(message_id)' and f_pin = '\(l_pin)'")
  1634. }
  1635. }
  1636. cursorStatus.close()
  1637. }
  1638. }
  1639. } catch {
  1640. rollback.pointee = true
  1641. print("Access database error: \(error.localizedDescription)")
  1642. }
  1643. })
  1644. }
  1645. static func getGroupMembers(fmdb: FMDatabase, l_pin: String) -> [String] {
  1646. var result = [String]()
  1647. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select f_pin from GROUPZ_MEMBER where group_id = '\(l_pin)'") {
  1648. while cursor.next() {
  1649. if let value = cursor.string(forColumnIndex: 0) {
  1650. result.append(value)
  1651. }
  1652. }
  1653. cursor.close()
  1654. }
  1655. return result
  1656. }
  1657. static func getVideoThumbnail(name: String, completion: @escaping (Bool)->()) {
  1658. DispatchQueue.global().async {
  1659. do {
  1660. let fileManager = FileManager.default
  1661. let documentDir = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
  1662. let fileDir = documentDir.appendingPathComponent(name)
  1663. let path = fileDir.path
  1664. if FileManager.default.fileExists(atPath: path) {
  1665. let asset = AVAsset(url: URL(fileURLWithPath: path))
  1666. let avAssetImageGenerator = AVAssetImageGenerator(asset: asset)
  1667. avAssetImageGenerator.appliesPreferredTrackTransform = true
  1668. let thumnailTime = CMTimeMake(value: 2, timescale: 1)
  1669. let thumbImage = UIImage(cgImage: try avAssetImageGenerator.copyCGImage(at: thumnailTime, actualTime: nil))
  1670. guard let data = thumbImage.jpegData(compressionQuality: 1.0) else {
  1671. completion(false)
  1672. return
  1673. }
  1674. let thumbFileDir = documentDir.appendingPathComponent("THUMB_" + name)
  1675. try data.write(to: thumbFileDir)
  1676. completion(true)
  1677. } else {
  1678. completion(false)
  1679. }
  1680. } catch {
  1681. //print(error)
  1682. }
  1683. }
  1684. }
  1685. static func resizedImage(at url: URL, for size: CGSize) -> UIImage? {
  1686. var image : UIImage?
  1687. if FileManager.default.fileExists(atPath: url.path){
  1688. image = UIImage(contentsOfFile: url.path)
  1689. }
  1690. else if FileEncryption.shared.isSecureExists(filename: url.lastPathComponent) {
  1691. do {
  1692. if let imageData = try FileEncryption.shared.readSecure(filename: url.lastPathComponent) {
  1693. image = UIImage(data: imageData)
  1694. }
  1695. }
  1696. catch {
  1697. }
  1698. }
  1699. if image == nil {
  1700. return nil
  1701. }
  1702. let renderer = UIGraphicsImageRenderer(size: size)
  1703. return renderer.image { (context) in
  1704. image!.draw(in: CGRect(origin: .zero, size: size))
  1705. }
  1706. }
  1707. static func initFollowing() -> Void {
  1708. if let me = User.getMyPin() {
  1709. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getListFollowing(l_pin: me)) {
  1710. let data = response.getBody(key: CoreMessage_TMessageKey.DATA)
  1711. if !data.isEmpty {
  1712. if let jsonArray = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [AnyObject] {
  1713. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  1714. do {
  1715. for json in jsonArray {
  1716. _ = try Database.shared.insertRecord(fmdb: fmdb, table: "FOLLOW", cvalues: [
  1717. "f_pin" : CoreMessage_TMessageUtil.getString(json: json, key: "pin")
  1718. ], replace: true)
  1719. }
  1720. } catch {
  1721. rollback.pointee = true
  1722. print("Access database error: \(error.localizedDescription)")
  1723. }
  1724. })
  1725. }
  1726. }
  1727. }
  1728. }
  1729. }
  1730. // do {
  1731. // _ = try Database.shared.insertRecord(fmdb: fmdb, table: "CALL_CENTER_HISTORY", cvalues: [
  1732. // "type" : "1",
  1733. // "title" : displayName,
  1734. // "time" : timeStart,
  1735. // "f_pin" : f_pin,
  1736. // "data" : dataCC,
  1737. // "time_end" : date,
  1738. // "complaint_id" : complaint_id.isEmpty ? "C\(date)" : complaint_id,
  1739. // "members" : "",
  1740. // "requester": ""
  1741. // ], replace: true)
  1742. // _ = try Database.shared.insertRecord(fmdb: fmdb, table: "PREFS", cvalues: [
  1743. // "key" : "CC:\(f_pin)",
  1744. // "value" : status,
  1745. // ], replace: true)
  1746. // ret = true
  1747. // } catch {
  1748. // rollback.pointee = true
  1749. // //print(error)
  1750. // }
  1751. private static var uploadQueue = DispatchQueue(label: "UPLOAD_DICT", attributes: .concurrent)
  1752. private static var UPLOAD_DICT = [String: Network]()
  1753. static func removeUploadFile(forKey: String) -> Network? {
  1754. var _result: Network? = nil
  1755. uploadQueue.sync {
  1756. _result = self.UPLOAD_DICT.removeValue(forKey: forKey)
  1757. }
  1758. return _result
  1759. }
  1760. static func putUploadFile(forKey: String, uploader: Network) {
  1761. uploadQueue.async (flags: .barrier) {
  1762. self.UPLOAD_DICT[forKey] = uploader
  1763. }
  1764. }
  1765. static func getUploadFile(forKey: String) -> Network? {
  1766. var _result: Network? = nil
  1767. uploadQueue.sync {
  1768. _result = self.UPLOAD_DICT[forKey]
  1769. }
  1770. return _result
  1771. }
  1772. private static var downloadQueue = DispatchQueue(label: "DOWNLOAD_DICT", attributes: .concurrent)
  1773. private static var DOWNLOAD_DICT = [String:Download]()
  1774. static func addDownload(forKey : String, download: Download){
  1775. downloadQueue.async (flags: .barrier) {
  1776. self.DOWNLOAD_DICT[forKey] = download
  1777. }
  1778. }
  1779. static func getDownload(forKey: String) -> Download? {
  1780. var _result: Download? = nil
  1781. downloadQueue.sync {
  1782. _result = self.DOWNLOAD_DICT[forKey]
  1783. }
  1784. return _result
  1785. }
  1786. static func removeDownload(forKey: String) -> Download? {
  1787. var _result: Download? = nil
  1788. downloadQueue.sync {
  1789. _result = self.DOWNLOAD_DICT.removeValue(forKey: forKey)
  1790. }
  1791. return _result
  1792. }
  1793. static func writeImageToFile(data: Data, fileName: String){
  1794. guard let directory = FileManager.default.urls(for: .picturesDirectory, in: .userDomainMask).last else {
  1795. return
  1796. }
  1797. let fileURL = directory.appendingPathComponent("\(fileName)")
  1798. if FileManager.default.fileExists(atPath: fileURL.path) {
  1799. if let fileHandle = FileHandle(forWritingAtPath: fileURL.path) {
  1800. fileHandle.seekToEndOfFile()
  1801. fileHandle.write(data)
  1802. fileHandle.closeFile()
  1803. } else {
  1804. //print("Can't open file to write")
  1805. }
  1806. } else {
  1807. do {
  1808. try data.write(to: fileURL, options: .atomic)
  1809. } catch {
  1810. //print("Unable to write in new file")
  1811. }
  1812. }
  1813. }
  1814. static func writeVideoToFile(data: Data, fileName: String){
  1815. guard let directory = FileManager.default.urls(for: .moviesDirectory, in: .userDomainMask).last else {
  1816. return
  1817. }
  1818. let fileURL = directory.appendingPathComponent("\(fileName)")
  1819. if FileManager.default.fileExists(atPath: fileURL.path) {
  1820. if let fileHandle = FileHandle(forWritingAtPath: fileURL.path) {
  1821. fileHandle.seekToEndOfFile()
  1822. fileHandle.write(data)
  1823. fileHandle.closeFile()
  1824. } else {
  1825. //print("Can't open file to write")
  1826. }
  1827. } else {
  1828. do {
  1829. try data.write(to: fileURL, options: .atomic)
  1830. } catch {
  1831. //print("Unable to write in new file")
  1832. }
  1833. }
  1834. }
  1835. static func writeDocumentsToFile(data: Data, fileName: String){
  1836. guard let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last else {
  1837. return
  1838. }
  1839. let fileURL = directory.appendingPathComponent("\(fileName)")
  1840. if FileManager.default.fileExists(atPath: fileURL.path) {
  1841. if let fileHandle = FileHandle(forWritingAtPath: fileURL.path) {
  1842. fileHandle.seekToEndOfFile()
  1843. fileHandle.write(data)
  1844. fileHandle.closeFile()
  1845. } else {
  1846. //print("Can't open file to write")
  1847. }
  1848. } else {
  1849. do {
  1850. try data.write(to: fileURL, options: .atomic)
  1851. } catch {
  1852. //print("Unable to write in new file")
  1853. }
  1854. }
  1855. }
  1856. public static func checkMicPermission() -> Bool {
  1857. var permissionCheck: Bool = false
  1858. switch AVAudioSession.sharedInstance().recordPermission {
  1859. case .granted:
  1860. permissionCheck = true
  1861. case .denied:
  1862. permissionCheck = false
  1863. case .undetermined:
  1864. Nexilis.dispatch = DispatchGroup()
  1865. Nexilis.dispatch?.enter()
  1866. AVAudioSession.sharedInstance().requestRecordPermission({ (granted) in
  1867. if granted {
  1868. permissionCheck = true
  1869. } else {
  1870. permissionCheck = false
  1871. }
  1872. if let dispatch = Nexilis.dispatch {
  1873. dispatch.leave()
  1874. }
  1875. })
  1876. Nexilis.dispatch?.wait()
  1877. Nexilis.dispatch = nil
  1878. default:
  1879. break
  1880. }
  1881. return permissionCheck
  1882. }
  1883. public static func checkCameraPermission() -> Int {
  1884. var permissionCheck: Int = -1
  1885. if AVCaptureDevice.authorizationStatus(for: .video) == .authorized {
  1886. permissionCheck = 1
  1887. } else if AVCaptureDevice.authorizationStatus(for: .video) == .denied {
  1888. permissionCheck = 0
  1889. } else {
  1890. AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) -> Void in
  1891. })
  1892. }
  1893. return permissionCheck
  1894. }
  1895. // public static func startTimer(){
  1896. // broadcastTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: {_ in
  1897. // if(!openBroadcast && !broadcastList.isEmpty){
  1898. // openBroadcast = true
  1899. // let m = broadcastList.removeFirst()
  1900. // //print("broadcast show: \(m)")
  1901. // DispatchQueue.main.async {
  1902. // Nexilis.shared.showBroadcastMessage(m: m)
  1903. // }
  1904. // }
  1905. // })
  1906. // }
  1907. public static func debugBroadcast(){
  1908. if(Utils.getDebugBC() != nil) {
  1909. let m = Utils.getDebugBC()
  1910. Nexilis.shared.showBroadcastMessage(m: m!)
  1911. }
  1912. }
  1913. /*
  1914. * Delegate
  1915. */
  1916. weak open var loginDelegate: LoginDelegate?
  1917. weak open var messageDelegate: MessageDelegate?
  1918. weak open var groupDelegate: GroupDelegate?
  1919. weak open var callDelegate: CallDelegate?
  1920. weak open var streamingDelagate: LiveStreamingDelegate?
  1921. weak open var seminarDelegate: SeminarDelegate?
  1922. weak open var personInfoDelegate: PersonInfoDelegate?
  1923. weak open var screenSharingDelegate: ScreenSharingDelegate?
  1924. weak open var commentDelegate: CommentDelegate?
  1925. weak open var uploadDelegate: UploadDelegate?
  1926. weak open var timelineDelegate: TimelineDelegate?
  1927. weak open var connectionDelegate: ConnectionDelegate?
  1928. var floating: FloatingNotificationBanner!
  1929. var stateUnfriend = ""
  1930. }
  1931. struct LibFontName {
  1932. static let regular = "Poppins-Regular"
  1933. static let bold = "Poppins-SemiBold"
  1934. static let italic = "Poppins-Italic"
  1935. static let medium = "Poppins-Medium"
  1936. static let boldItalic = "Poppins-SemiBoldItalic"
  1937. }
  1938. extension UIFontDescriptor.AttributeName {
  1939. static let nsctFontUIUsage = UIFontDescriptor.AttributeName(rawValue: "NSCTFontUIUsageAttribute")
  1940. }
  1941. extension UIFont {
  1942. static var isOverrided: Bool = false
  1943. static let FONT_SELECT = 0
  1944. @objc class func libSystemFont(ofSize size: CGFloat) -> UIFont? {
  1945. if UIFont(name: LibFontName.regular, size: size) == nil {
  1946. jbs_registerFont(withFilenameString: LibFontName.regular)
  1947. }
  1948. return UIFont(name: LibFontName.regular, size: size)
  1949. }
  1950. @objc class func libSystemFontWeight(ofSize size: CGFloat, weight: UIFont.Weight) -> UIFont? {
  1951. if weight == .medium {
  1952. if UIFont(name: LibFontName.medium, size: size) == nil {
  1953. jbs_registerFont(withFilenameString: LibFontName.medium)
  1954. }
  1955. return UIFont(name: LibFontName.medium, size: size)
  1956. } else if weight == .semibold {
  1957. if UIFont(name: LibFontName.boldItalic, size: size) == nil {
  1958. jbs_registerFont(withFilenameString: LibFontName.boldItalic)
  1959. }
  1960. return UIFont(name: LibFontName.boldItalic, size: size)
  1961. }
  1962. return UIFont(name: LibFontName.regular, size: size)
  1963. }
  1964. @objc class func libBoldSystemFont(ofSize size: CGFloat) -> UIFont? {
  1965. if UIFont(name: LibFontName.bold, size: size) == nil {
  1966. jbs_registerFont(withFilenameString: LibFontName.bold)
  1967. }
  1968. return UIFont(name: LibFontName.bold, size: size)
  1969. }
  1970. @objc class func libItalicSystemFont(ofSize size: CGFloat) -> UIFont? {
  1971. if UIFont(name: LibFontName.italic, size: size) == nil {
  1972. jbs_registerFont(withFilenameString: LibFontName.italic)
  1973. }
  1974. return UIFont(name: LibFontName.italic, size: size)
  1975. }
  1976. @objc convenience init(myCoder aDecoder: NSCoder) {
  1977. guard
  1978. let fontDescriptor = aDecoder.decodeObject(forKey: "UIFontDescriptor") as? UIFontDescriptor,
  1979. let fontAttribute = fontDescriptor.fontAttributes[.nsctFontUIUsage] as? String else {
  1980. self.init(myCoder: aDecoder)
  1981. return
  1982. }
  1983. var fontName = ""
  1984. switch fontAttribute {
  1985. case "CTFontRegularUsage":
  1986. fontName = LibFontName.regular
  1987. case "CTFontEmphasizedUsage", "CTFontBoldUsage":
  1988. fontName = LibFontName.bold
  1989. case "CTFontObliqueUsage":
  1990. fontName = LibFontName.italic
  1991. default:
  1992. fontName = LibFontName.regular
  1993. }
  1994. self.init(name: fontName, size: fontDescriptor.pointSize)!
  1995. }
  1996. class func libOverrideInitialize() {
  1997. guard self == UIFont.self, !isOverrided, FONT_SELECT == 0 else { return }
  1998. // Avoid method swizzling run twice and revert to original initialize function
  1999. isOverrided = true
  2000. if let systemFontMethod = class_getClassMethod(self, #selector(systemFont(ofSize:))),
  2001. let mySystemFontMethod = class_getClassMethod(self, #selector(libSystemFont(ofSize:))) {
  2002. method_exchangeImplementations(systemFontMethod, mySystemFontMethod)
  2003. }
  2004. if let systemFontWeightMethod = class_getClassMethod(self, #selector(systemFont(ofSize:weight:))),
  2005. let mySystemFontWeightMethod = class_getClassMethod(self, #selector(libSystemFontWeight(ofSize:weight:))) {
  2006. method_exchangeImplementations(systemFontWeightMethod, mySystemFontWeightMethod)
  2007. }
  2008. if let boldSystemFontMethod = class_getClassMethod(self, #selector(boldSystemFont(ofSize:))),
  2009. let myBoldSystemFontMethod = class_getClassMethod(self, #selector(libBoldSystemFont(ofSize:))) {
  2010. method_exchangeImplementations(boldSystemFontMethod, myBoldSystemFontMethod)
  2011. }
  2012. if let italicSystemFontMethod = class_getClassMethod(self, #selector(italicSystemFont(ofSize:))),
  2013. let myItalicSystemFontMethod = class_getClassMethod(self, #selector(libItalicSystemFont(ofSize:))) {
  2014. method_exchangeImplementations(italicSystemFontMethod, myItalicSystemFontMethod)
  2015. }
  2016. if let initCoderMethod = class_getInstanceMethod(self, #selector(UIFontDescriptor.init(coder:))), // Trick to get over the lack of UIFont.init(coder:))
  2017. let myInitCoderMethod = class_getInstanceMethod(self, #selector(UIFont.init(myCoder:))) {
  2018. method_exchangeImplementations(initCoderMethod, myInitCoderMethod)
  2019. }
  2020. }
  2021. class func jbs_registerFont(withFilenameString filenameString: String) {
  2022. // guard let pathForResourceString = Bundle.resourceBundle(for: Nexilis.self).path(forResource: filenameString, ofType: "otf") else { //resourcesMediaBundle
  2023. // //print("UIFont+: Failed to register font - path for resource not found.")
  2024. // return
  2025. // }
  2026. var pathForResourceURL = Bundle.resourceBundle(for: Nexilis.self).url(forResource: filenameString, withExtension: "otf")
  2027. if pathForResourceURL == nil {
  2028. pathForResourceURL = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: filenameString, withExtension: "otf")
  2029. }
  2030. // guard let pathForResourceURL = Bundle.resourceBundle(for: Nexilis.self).url(forResource: filenameString, withExtension: "otf") else { //resourcesMediaBundle
  2031. // //print("UIFont+: Failed to register font - path for resource not found.")
  2032. // return
  2033. // }
  2034. var errorRef: Unmanaged<CFError>? = nil
  2035. CTFontManagerRegisterFontsForURL(pathForResourceURL! as CFURL, .process, &errorRef)
  2036. // guard let fontData = NSData(contentsOfFile: pathForResourceString) else {
  2037. // //print("UIFont+: Failed to register font - font data could not be loaded.")
  2038. // return
  2039. // }
  2040. //
  2041. // guard let dataProvider = CGDataProvider(data: fontData) else {
  2042. // //print("UIFont+: Failed to register font - data provider could not be loaded.")
  2043. // return
  2044. // }
  2045. //
  2046. // guard let font = CGFont(dataProvider) else {
  2047. // //print("UIFont+: Failed to register font - font could not be loaded.")
  2048. // return
  2049. // }
  2050. //
  2051. // var errorRef: Unmanaged<CFError>? = nil
  2052. // if (CTFontManagerRegisterGraphicsFont(font, &errorRef) == false) {
  2053. // }
  2054. }
  2055. }
  2056. public protocol LoginDelegate: NSObjectProtocol {
  2057. func onProgress(code: String, progress: Int)
  2058. func onProcess(message: String, status: String)
  2059. }
  2060. public protocol MessageDelegate: NSObjectProtocol {
  2061. func onReceive(message: TMessage)
  2062. func onReceiveComment(message: TMessage)
  2063. func onReceive(message: [AnyHashable: Any?])
  2064. func onMessage(message: TMessage)
  2065. func onUpload(name: String, progress: Double)
  2066. func onTyping(message: TMessage)
  2067. }
  2068. public protocol GroupDelegate: NSObjectProtocol {
  2069. func onGroup(code: String, f_pin: String, groupId: String)
  2070. func onTopic(code: String, f_pin: String, topicId: String)
  2071. func onMember(code: String, f_pin: String, groupId: String, member: String)
  2072. }
  2073. public protocol DownloadDelegate: NSObjectProtocol {
  2074. func onDownloadProgress(fileName: String, progress: Double)
  2075. }
  2076. public protocol CallDelegate: NSObjectProtocol {
  2077. func onIncomingCall(state: Int, message: String)
  2078. func onStatusCall(state: Int, message: String)
  2079. }
  2080. public protocol LiveStreamingDelegate: NSObjectProtocol {
  2081. func onStartLS(state: Int, message: String)
  2082. func onJoinLS(state: Int, message: String)
  2083. }
  2084. public protocol SeminarDelegate: NSObjectProtocol {
  2085. func onStartSeminar(state: Int, message: String)
  2086. func onJoinSeminar(state: Int, message: String)
  2087. }
  2088. public protocol VideoCallDelegate: NSObjectProtocol {
  2089. func onInitiateVideoCall(destination:String,state: Int, message: String)
  2090. func onAcceptVideoCall(originator:String,state: Int, message: String)
  2091. func onVideoCallReceiverTerminate(originator:String,state: Int, message: String)
  2092. }
  2093. public protocol PersonInfoDelegate: NSObjectProtocol {
  2094. func onUpdatePersonInfo(state: Int, message: String)
  2095. }
  2096. public protocol ScreenSharingDelegate: NSObjectProtocol {
  2097. func onStartScreenSharing(state:Int,message:String)
  2098. func onJoinScreenSharing(state:Int,message:String)
  2099. }
  2100. public protocol CommentDelegate: NSObjectProtocol {
  2101. func onReceiveComment(message: TMessage)
  2102. func onDeleteComment(message: TMessage)
  2103. }
  2104. public protocol UploadDelegate: NSObjectProtocol {
  2105. func onUploadProgress(fileName: String, progress: Double)
  2106. }
  2107. public protocol TimelineDelegate: NSObjectProtocol {
  2108. func onPostUpdate(status: String, message: String)
  2109. }
  2110. public protocol ConnectionDelegate: NSObjectProtocol {
  2111. func connectionStateChanged(userId: String!, deviceId: String, state: Bool)
  2112. }
  2113. public protocol ConnectDelegate: NSObjectProtocol {
  2114. func onSuccess(userId: String)
  2115. func onFailed(error: String)
  2116. }
  2117. public enum AppStoryBoard: String {
  2118. case Palio = "Palio"
  2119. public var instance: UIStoryboard {
  2120. return UIStoryboard(name: self.rawValue, bundle: Bundle.resourceBundle(for: Nexilis.self))
  2121. }
  2122. }
  2123. public var uuidOngoing = UUID()
  2124. extension Nexilis: CallDelegate {
  2125. func displayIncomingCall(uuid: UUID, handle: String, hasVideo: Bool = false, completion: ((Error?) -> Void)? = nil) {
  2126. providerDelegate?.reportIncomingCall(uuid: uuid, handle: handle, hasVideo: hasVideo, completion: completion)
  2127. }
  2128. public func onIncomingCall(state: Int, message: String) {
  2129. DispatchQueue.main.async {
  2130. let idMe = User.getMyPin()!
  2131. let myData = User.getData(pin: idMe)
  2132. let onGoingCC: String = SecureUserDefaults.shared.value(forKey: "onGoingCC") ?? ""
  2133. if !onGoingCC.isEmpty {
  2134. return
  2135. }
  2136. let deviceId = message.split(separator: ",")[0]
  2137. if myData?.offline_mode == "1" || self.stateUnfriend == deviceId {
  2138. DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
  2139. API.terminateCall(sParty: nil)
  2140. })
  2141. return
  2142. }
  2143. var isShowAlert: Double?
  2144. let canShow = UIApplication.shared.visibleViewController
  2145. if canShow != nil && !(canShow is UINavigationController) {
  2146. if !(canShow is EditorPersonal) {
  2147. isShowAlert = 0
  2148. } else {
  2149. isShowAlert = 1.5
  2150. }
  2151. } else if canShow != nil {
  2152. if canShow is UINavigationController {
  2153. let canShowNC = canShow as! UINavigationController
  2154. if !(canShowNC.visibleViewController is EditorPersonal) {
  2155. isShowAlert = 0
  2156. } else {
  2157. isShowAlert = 1.5
  2158. }
  2159. } else {
  2160. isShowAlert = 0
  2161. }
  2162. }
  2163. if (state == Nexilis.AUDIO_CALL_INCOMING && message.split(separator: ",")[1] != "joining Ac.room on channel 0" && message.split(separator: ",")[1] != "joining Vc.room on channel 0") {
  2164. if Nexilis.callAPNActivated || APIS.checkAppStateisBackground() {
  2165. return
  2166. }
  2167. let data = User.getDataCanNil(pin: String(deviceId))
  2168. if data == nil {
  2169. DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
  2170. API.terminateCall(sParty: nil)
  2171. })
  2172. return
  2173. }
  2174. // let backgroundTaskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)
  2175. // uuidOngoing = UUID()
  2176. // self.displayIncomingCall(uuid: uuidOngoing, handle: String(deviceId), hasVideo: false) { error in
  2177. // UIApplication.shared.endBackgroundTask(backgroundTaskIdentifier)
  2178. // }
  2179. let controller = QmeraAudioViewController()
  2180. controller.user = User.getData(pin: String(deviceId))
  2181. controller.isOutgoing = false
  2182. controller.modalPresentationStyle = .overCurrentContext
  2183. if UIApplication.shared.visibleViewController is UIAlertController {
  2184. let vc = UIApplication.shared.visibleViewController as! UIAlertController
  2185. vc.dismiss(animated: true, completion: {
  2186. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2187. UIApplication.shared.visibleViewController?.navigationController?.present(controller, animated: true, completion: nil)
  2188. } else {
  2189. UIApplication.shared.visibleViewController?.present(controller, animated: true, completion: nil)
  2190. }
  2191. })
  2192. return
  2193. }
  2194. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2195. UIApplication.shared.visibleViewController?.navigationController?.present(controller, animated: true, completion: nil)
  2196. } else {
  2197. UIApplication.shared.visibleViewController?.present(controller, animated: true, completion: nil)
  2198. }
  2199. // API.receiveCCall(sParty: String(deviceId))
  2200. } else if (state == Nexilis.VIDEO_CALL_INCOMING && message.split(separator: ",")[1] != "joining Ac.room on channel 0" && message.split(separator: ",")[1] != "joining Vc.room on channel 0") {
  2201. if Nexilis.callAPNActivated || APIS.checkAppStateisBackground() {
  2202. return
  2203. }
  2204. let dataUser = User.getDataCanNil(pin: String(deviceId))
  2205. if dataUser == nil {
  2206. DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
  2207. API.terminateCall(sParty: nil)
  2208. })
  2209. return
  2210. }
  2211. let videoController = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "videoVCQmera") as! QmeraVideoViewController
  2212. videoController.fPin = String(deviceId)
  2213. videoController.isInisiator = false
  2214. let navigationController = CustomNavigationController(rootViewController: videoController)
  2215. navigationController.modalPresentationStyle = .fullScreen
  2216. if UIApplication.shared.visibleViewController is UIAlertController {
  2217. let vc = UIApplication.shared.visibleViewController as! UIAlertController
  2218. vc.dismiss(animated: true, completion: {
  2219. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2220. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  2221. } else {
  2222. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  2223. }
  2224. })
  2225. return
  2226. }
  2227. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2228. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  2229. } else {
  2230. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  2231. }
  2232. }
  2233. }
  2234. }
  2235. public func onStatusCall(state: Int, message: String) {
  2236. // let r = message.split(separator: ",")
  2237. // if state == Nexilis.AUDIO_CALL_RINGING {
  2238. // if let call = callManager.call(with: String(r[0])) {
  2239. // //print("onStatusCall:connectingCall")
  2240. // DispatchQueue.main.async {
  2241. // call.connectingCall()
  2242. // }
  2243. // }
  2244. // } else if state == Nexilis.AUDIO_CALL_OFFHOOK {
  2245. //// if let call = callManager.call(with: String(r[1])) {
  2246. // //print("onStatusCall:answerCall")
  2247. //// DispatchQueue.main.async {
  2248. //// call.answerCall()
  2249. //// }
  2250. //// }
  2251. // } else if state == Nexilis.AUDIO_CALL_END {
  2252. // DispatchQueue.main.async {
  2253. // if QmeraAudioViewController().viewIfLoaded?.window == nil {
  2254. // Nexilis.shared.callManager.end(call: Call(uuid: uuidOngoing))
  2255. // }
  2256. // }
  2257. // }
  2258. var dataCall: [AnyHashable : Any] = [:]
  2259. dataCall["state"] = state
  2260. dataCall["message"] = message
  2261. NotificationCenter.default.post(name: NSNotification.Name(rawValue: Nexilis.listenerStatusCall), object: nil, userInfo: dataCall)
  2262. }
  2263. }
  2264. var previewItem : NSURL?
  2265. var listCCIdInv: [String] = []
  2266. var imageGif: UIImageView!
  2267. var posGif = "0"
  2268. var loopGif = "0"
  2269. var timerAnimationGif = Timer()
  2270. extension Nexilis: MessageDelegate {
  2271. public func onReceiveComment(message: TMessage) {
  2272. var dataMessage: [AnyHashable : Any] = [:]
  2273. dataMessage["message"] = message
  2274. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onReceiveComment"), object: nil, userInfo: dataMessage)
  2275. }
  2276. @objc func tapLinkBroadcast(_ sender: ObjectGesture) {
  2277. var stringURl = sender.message_id.lowercased()
  2278. if stringURl.starts(with: "www.") {
  2279. stringURl = "https://" + stringURl.replacingOccurrences(of: "www.", with: "")
  2280. }
  2281. guard let url = URL(string: stringURl) else { return }
  2282. UIApplication.shared.open(url)
  2283. }
  2284. private func runAnimationGif() {
  2285. DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: { [self] in
  2286. if imageGif != nil {
  2287. timerAnimationGif.invalidate()
  2288. timerAnimationGif = Timer.scheduledTimer(timeInterval: 0.001, target: self, selector: #selector(animateGif), userInfo: nil, repeats: true)
  2289. }
  2290. })
  2291. }
  2292. @objc func animateGif() {
  2293. DispatchQueue.main.async {
  2294. if posGif == "0" { //left
  2295. if imageGif.frame.origin.x < (UIScreen.main.bounds.width - imageGif.frame.width) {
  2296. imageGif.frame.origin.x+=0.1
  2297. } else {
  2298. timerAnimationGif.invalidate()
  2299. }
  2300. } else if posGif == "1" { //right
  2301. if imageGif.frame.origin.x > 0 {
  2302. imageGif.frame.origin.x-=0.1
  2303. } else {
  2304. timerAnimationGif.invalidate()
  2305. }
  2306. } else if posGif == "2" { //top
  2307. if imageGif.frame.origin.y < (UIScreen.main.bounds.height - imageGif.frame.height) {
  2308. imageGif.frame.origin.y+=0.1
  2309. } else {
  2310. timerAnimationGif.invalidate()
  2311. }
  2312. } else { //bottom
  2313. if imageGif.frame.origin.y > 20 {
  2314. imageGif.frame.origin.y-=0.1
  2315. } else {
  2316. timerAnimationGif.invalidate()
  2317. }
  2318. }
  2319. }
  2320. }
  2321. func showBroadcastMessage(m: [String: String]) {
  2322. let fileType = m[CoreMessage_TMessageKey.CATEGORY_FLAG]!
  2323. let gifId = m[CoreMessage_TMessageKey.GIF_ID] ?? ""
  2324. let broadcastVC = UIViewController()
  2325. if let viewBroadcast = broadcastVC.view {
  2326. broadcastVC.modalPresentationStyle = .custom
  2327. viewBroadcast.backgroundColor = .black.withAlphaComponent(0.3)
  2328. if !gifId.isEmpty {
  2329. let urlGif = "\(Utils.getURLBase())filepalio/image/\(gifId)"
  2330. let scale = m[CoreMessage_TMessageKey.SCALE] ?? "0"
  2331. let link = m[CoreMessage_TMessageKey.LINK] ?? ""
  2332. posGif = m[CoreMessage_TMessageKey.START_ANIMATION] ?? "0"
  2333. loopGif = m[CoreMessage_TMessageKey.LOOP_ANIMATION] ?? "0"
  2334. imageGif = UIImageView()
  2335. viewBroadcast.addSubview(imageGif)
  2336. imageGif.isUserInteractionEnabled = true
  2337. imageGif.contentMode = .scaleAspectFit
  2338. let buttonClose = UIButton(type: .close)
  2339. buttonClose.frame.size = CGSize(width: 30, height: 30)
  2340. buttonClose.layer.cornerRadius = 15.0
  2341. buttonClose.clipsToBounds = true
  2342. buttonClose.backgroundColor = .black.withAlphaComponent(0.5)
  2343. buttonClose.actionHandle(controlEvents: .touchUpInside,
  2344. ForAction:{() -> Void in
  2345. broadcastVC.dismiss(animated: true, completion: {
  2346. imageGif = nil
  2347. Nexilis.broadcastList.remove(at: 0)
  2348. if Nexilis.broadcastList.count > 0 {
  2349. Nexilis.shared.showBroadcastMessage(m: Nexilis.broadcastList[0])
  2350. }
  2351. })
  2352. })
  2353. imageGif.addSubview(buttonClose)
  2354. buttonClose.anchor(top: imageGif.topAnchor, right: imageGif.rightAnchor, width: 30, height: 30)
  2355. var xpos: CGFloat = 0
  2356. var ypos: CGFloat = 0
  2357. var widthImage: CGFloat = 300
  2358. var heightImage: CGFloat = 300
  2359. if scale == "2" { //50%
  2360. widthImage = 150
  2361. heightImage = 150
  2362. } else if scale == "1" { //75%
  2363. widthImage = 225
  2364. heightImage = 225
  2365. }
  2366. if posGif == "0" { //left
  2367. xpos = 0
  2368. ypos = (viewBroadcast.frame.size.height / 2) - (heightImage / 2)
  2369. } else if posGif == "1" { //right
  2370. xpos = viewBroadcast.frame.size.width - widthImage
  2371. ypos = (viewBroadcast.frame.size.height / 2) - (heightImage / 2)
  2372. } else if posGif == "2" { //top
  2373. xpos = (viewBroadcast.frame.size.width / 2) - (widthImage / 2)
  2374. ypos = 20
  2375. } else { //bottom
  2376. xpos = (viewBroadcast.frame.size.width / 2) - (widthImage / 2)
  2377. ypos = viewBroadcast.frame.size.height - heightImage
  2378. }
  2379. imageGif.frame = CGRect(x: xpos, y: ypos, width: widthImage, height: heightImage)
  2380. imageGif.loadImageAsync(with: urlGif, isGif: true)
  2381. runAnimationGif()
  2382. imageGif.actionHandle(controlEvents: .touchUpInside, ForAction: {
  2383. broadcastVC.dismiss(animated: true, completion: {
  2384. imageGif = nil
  2385. Nexilis.broadcastList.remove(at: 0)
  2386. if Nexilis.broadcastList.count > 0 {
  2387. Nexilis.shared.showBroadcastMessage(m: Nexilis.broadcastList[0])
  2388. }
  2389. if !link.isEmpty {
  2390. APIS.openUrl(url: link)
  2391. }
  2392. })
  2393. })
  2394. } else {
  2395. let stringLink = m[CoreMessage_TMessageKey.LINK] ?? ""
  2396. let containerView = UIView()
  2397. viewBroadcast.addSubview(containerView)
  2398. if stringLink.isEmpty {
  2399. containerView.anchor(centerX: viewBroadcast.centerXAnchor, centerY: viewBroadcast.centerYAnchor, width: viewBroadcast.bounds.width - 40, minHeight: 100, maxHeight: viewBroadcast.bounds.height - 100)
  2400. } else {
  2401. containerView.anchor(centerX: viewBroadcast.centerXAnchor, centerY: viewBroadcast.centerYAnchor, width: viewBroadcast.bounds.width - 40, minHeight: 200, maxHeight: viewBroadcast.bounds.height - 100)
  2402. }
  2403. containerView.backgroundColor = .white.withAlphaComponent(0.9)
  2404. containerView.layer.cornerRadius = 15.0
  2405. containerView.clipsToBounds = true
  2406. let subContainerView = UIView()
  2407. subContainerView.backgroundColor = .clear
  2408. containerView.addSubview(subContainerView)
  2409. subContainerView.anchor(top: containerView.topAnchor, left: containerView.leftAnchor, bottom: containerView.bottomAnchor, right: containerView.rightAnchor, paddingTop: 20.0, paddingLeft: 10.0, paddingBottom: 20.0, paddingRight: 10.0)
  2410. let buttonClose = UIButton(type: .close)
  2411. buttonClose.frame.size = CGSize(width: 30, height: 30)
  2412. buttonClose.layer.cornerRadius = 15.0
  2413. buttonClose.clipsToBounds = true
  2414. buttonClose.backgroundColor = .secondaryColor.withAlphaComponent(0.5)
  2415. buttonClose.actionHandle(controlEvents: .touchUpInside,
  2416. ForAction:{() -> Void in
  2417. broadcastVC.dismiss(animated: true, completion: {
  2418. Nexilis.broadcastList.remove(at: 0)
  2419. if Nexilis.broadcastList.count > 0 {
  2420. Nexilis.shared.showBroadcastMessage(m: Nexilis.broadcastList[0])
  2421. }
  2422. })
  2423. })
  2424. containerView.addSubview(buttonClose)
  2425. buttonClose.anchor(top: containerView.topAnchor, right: containerView.rightAnchor, width: 30, height: 30)
  2426. let title = UILabel()
  2427. title.font = .systemFont(ofSize: 18, weight: .bold)
  2428. title.text = m["MERNAM"]
  2429. title.textAlignment = .center
  2430. subContainerView.addSubview(title)
  2431. title.anchor(top: subContainerView.topAnchor, left: subContainerView.leftAnchor, right: subContainerView.rightAnchor)
  2432. let titleBroadcast = UILabel()
  2433. subContainerView.addSubview(titleBroadcast)
  2434. titleBroadcast.translatesAutoresizingMaskIntoConstraints = false
  2435. NSLayoutConstraint.activate([
  2436. titleBroadcast.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 20.0),
  2437. titleBroadcast.leadingAnchor.constraint(equalTo: subContainerView.leadingAnchor),
  2438. titleBroadcast.trailingAnchor.constraint(equalTo: subContainerView.trailingAnchor),
  2439. ])
  2440. titleBroadcast.font = UIFont.systemFont(ofSize: 14, weight: .semibold)
  2441. titleBroadcast.numberOfLines = 0
  2442. titleBroadcast.attributedText = m[CoreMessage_TMessageKey.TITLE]!.richText()
  2443. titleBroadcast.textColor = .black
  2444. let descBroadcast = UILabel()
  2445. subContainerView.addSubview(descBroadcast)
  2446. descBroadcast.translatesAutoresizingMaskIntoConstraints = false
  2447. let constraintDesc = descBroadcast.bottomAnchor.constraint(equalTo: subContainerView.bottomAnchor)
  2448. if !stringLink.isEmpty{
  2449. constraintDesc.constant = constraintDesc.constant - 30
  2450. }
  2451. if fileType != BroadcastViewController.FILE_TYPE_CHAT {
  2452. constraintDesc.constant = constraintDesc.constant - 260
  2453. }
  2454. NSLayoutConstraint.activate([
  2455. descBroadcast.topAnchor.constraint(equalTo: titleBroadcast.bottomAnchor, constant: 10),
  2456. descBroadcast.leadingAnchor.constraint(equalTo: subContainerView.leadingAnchor),
  2457. descBroadcast.trailingAnchor.constraint(equalTo: subContainerView.trailingAnchor),
  2458. constraintDesc,
  2459. ])
  2460. descBroadcast.font = UIFont.systemFont(ofSize: 12)
  2461. descBroadcast.numberOfLines = 0
  2462. descBroadcast.attributedText = m[CoreMessage_TMessageKey.MESSAGE_TEXT_ENG]!.richText()
  2463. descBroadcast.textColor = .black
  2464. let linkBroadcast = UILabel()
  2465. if !stringLink.isEmpty {
  2466. subContainerView.addSubview(linkBroadcast)
  2467. linkBroadcast.translatesAutoresizingMaskIntoConstraints = false
  2468. NSLayoutConstraint.activate([
  2469. linkBroadcast.topAnchor.constraint(equalTo: descBroadcast.bottomAnchor, constant: 10),
  2470. linkBroadcast.leadingAnchor.constraint(equalTo: subContainerView.leadingAnchor),
  2471. linkBroadcast.trailingAnchor.constraint(equalTo: subContainerView.trailingAnchor),
  2472. ])
  2473. linkBroadcast.font = UIFont.systemFont(ofSize: 12)
  2474. linkBroadcast.isUserInteractionEnabled = true
  2475. linkBroadcast.numberOfLines = 2
  2476. let attributedString = NSMutableAttributedString(string: stringLink, attributes:[NSAttributedString.Key.link: URL(string: stringLink)!])
  2477. linkBroadcast.attributedText = attributedString
  2478. let tap = ObjectGesture(target: self, action: #selector(tapLinkBroadcast))
  2479. tap.message_id = stringLink
  2480. linkBroadcast.addGestureRecognizer(tap)
  2481. }
  2482. let thumb = m[CoreMessage_TMessageKey.THUMB_ID] ?? ""
  2483. let image = m[CoreMessage_TMessageKey.IMAGE_ID] ?? ""
  2484. let video = m[CoreMessage_TMessageKey.VIDEO_ID] ?? ""
  2485. let file = m[CoreMessage_TMessageKey.FILE_ID] ?? ""
  2486. if fileType != BroadcastViewController.FILE_TYPE_CHAT {
  2487. let imageBroadcast = UIImageView()
  2488. subContainerView.addSubview(imageBroadcast)
  2489. imageBroadcast.translatesAutoresizingMaskIntoConstraints = false
  2490. var constImage = imageBroadcast.topAnchor.constraint(equalTo: descBroadcast.bottomAnchor, constant: 10)
  2491. if !stringLink.isEmpty {
  2492. constImage = imageBroadcast.topAnchor.constraint(equalTo: linkBroadcast.bottomAnchor, constant: 10)
  2493. }
  2494. NSLayoutConstraint.activate([
  2495. constImage,
  2496. imageBroadcast.leadingAnchor.constraint(equalTo: subContainerView.leadingAnchor),
  2497. imageBroadcast.trailingAnchor.constraint(equalTo: subContainerView.trailingAnchor),
  2498. imageBroadcast.heightAnchor.constraint(equalToConstant: 250)
  2499. ])
  2500. imageBroadcast.layer.cornerRadius = 10.0
  2501. imageBroadcast.clipsToBounds = true
  2502. if fileType != BroadcastViewController.FILE_TYPE_DOCUMENT {
  2503. imageBroadcast.contentMode = .scaleAspectFill
  2504. imageBroadcast.setImage(name: thumb)
  2505. if fileType == BroadcastViewController.FILE_TYPE_VIDEO {
  2506. let imagePlay = UIImageView(image: UIImage(systemName: "play.circle.fill"))
  2507. imageBroadcast.addSubview(imagePlay)
  2508. imagePlay.clipsToBounds = true
  2509. imagePlay.translatesAutoresizingMaskIntoConstraints = false
  2510. imagePlay.centerYAnchor.constraint(equalTo: imageBroadcast.centerYAnchor).isActive = true
  2511. imagePlay.centerXAnchor.constraint(equalTo: imageBroadcast.centerXAnchor).isActive = true
  2512. imagePlay.widthAnchor.constraint(equalToConstant: 60).isActive = true
  2513. imagePlay.heightAnchor.constraint(equalToConstant: 60).isActive = true
  2514. imagePlay.tintColor = .gray.withAlphaComponent(0.5)
  2515. }
  2516. } else {
  2517. imageBroadcast.image = UIImage(systemName: "doc.fill")
  2518. imageBroadcast.tintColor = .mainColor
  2519. imageBroadcast.contentMode = .scaleAspectFit
  2520. }
  2521. imageBroadcast.actionHandle(controlEvents: .touchUpInside,
  2522. ForAction:{() -> Void in
  2523. let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
  2524. let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
  2525. let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
  2526. if fileType == BroadcastViewController.FILE_TYPE_IMAGE {
  2527. if let dirPath = paths.first {
  2528. let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent(image)
  2529. if FileManager.default.fileExists(atPath: imageURL.path) {
  2530. let image = UIImage(contentsOfFile: imageURL.path)
  2531. let previewImageVC = PreviewAttachmentImageVideo(nibName: "PreviewAttachmentImageVideo", bundle: Bundle.resourceBundle(for: Nexilis.self))
  2532. previewImageVC.image = image
  2533. previewImageVC.isHiddenTextField = true
  2534. previewImageVC.modalPresentationStyle = .overFullScreen
  2535. previewImageVC.modalTransitionStyle = .crossDissolve
  2536. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2537. UIApplication.shared.visibleViewController?.navigationController?.present(previewImageVC, animated: true, completion: nil)
  2538. } else {
  2539. UIApplication.shared.visibleViewController?.present(previewImageVC, animated: true, completion: nil)
  2540. }
  2541. } else if FileEncryption.shared.isSecureExists(filename: image) {
  2542. do {
  2543. let data = try FileEncryption.shared.readSecure(filename: image)
  2544. let image = UIImage(data: data!)
  2545. let previewImageVC = PreviewAttachmentImageVideo(nibName: "PreviewAttachmentImageVideo", bundle: Bundle.resourceBundle(for: Nexilis.self))
  2546. previewImageVC.image = image
  2547. previewImageVC.isHiddenTextField = true
  2548. previewImageVC.modalPresentationStyle = .overFullScreen
  2549. previewImageVC.modalTransitionStyle = .crossDissolve
  2550. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2551. UIApplication.shared.visibleViewController?.navigationController?.present(previewImageVC, animated: true, completion: nil)
  2552. } else {
  2553. UIApplication.shared.visibleViewController?.present(previewImageVC, animated: true, completion: nil)
  2554. }
  2555. } catch {
  2556. }
  2557. } else {
  2558. Download().startHTTP(forKey: image) { (name, progress) in
  2559. guard progress == 100 else {
  2560. return
  2561. }
  2562. do {
  2563. try FileEncryption.shared.writeSecure(filename: image)
  2564. } catch {
  2565. }
  2566. DispatchQueue.main.async {
  2567. var image : UIImage?
  2568. if FileManager.default.fileExists(atPath: imageURL.path) {
  2569. image = UIImage(contentsOfFile: imageURL.path)
  2570. }
  2571. else if FileEncryption.shared.isSecureExists(filename: imageURL.lastPathComponent) {
  2572. do {
  2573. if let imageData = try FileEncryption.shared.readSecure(filename: imageURL.lastPathComponent) {
  2574. image = UIImage(data: imageData)
  2575. }
  2576. } catch {
  2577. }
  2578. }
  2579. let previewImageVC = PreviewAttachmentImageVideo(nibName: "PreviewAttachmentImageVideo", bundle: Bundle.resourceBundle(for: Nexilis.self))
  2580. previewImageVC.image = image
  2581. previewImageVC.isHiddenTextField = true
  2582. previewImageVC.modalPresentationStyle = .overFullScreen
  2583. previewImageVC.modalTransitionStyle = .crossDissolve
  2584. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2585. UIApplication.shared.visibleViewController?.navigationController?.present(previewImageVC, animated: true, completion: nil)
  2586. } else {
  2587. UIApplication.shared.visibleViewController?.present(previewImageVC, animated: true, completion: nil)
  2588. }
  2589. }
  2590. }
  2591. }
  2592. }
  2593. } else if fileType == BroadcastViewController.FILE_TYPE_VIDEO {
  2594. //https://qmera.io/filepalio/image/
  2595. let player = AVPlayer(url: URL(string: "https://nexilis.io/get_file?account=\(Nexilis.sAPIKey)&image=\(video)")!)
  2596. let playerVC = AVPlayerViewController()
  2597. playerVC.player = player
  2598. playerVC.modalPresentationStyle = .custom
  2599. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2600. UIApplication.shared.visibleViewController?.navigationController?.present(playerVC, animated: true, completion: nil)
  2601. } else {
  2602. UIApplication.shared.visibleViewController?.present(playerVC, animated: true, completion: nil)
  2603. }
  2604. } else if fileType == BroadcastViewController.FILE_TYPE_DOCUMENT {
  2605. if let dirPath = paths.first {
  2606. let fileURL = URL(fileURLWithPath: dirPath).appendingPathComponent(file)
  2607. if FileManager.default.fileExists(atPath: fileURL.path) {
  2608. previewItem = fileURL as NSURL
  2609. let previewController = QLPreviewController()
  2610. let rightBarButton = UIBarButtonItem()
  2611. previewController.navigationItem.rightBarButtonItem = rightBarButton
  2612. previewController.dataSource = self
  2613. previewController.modalPresentationStyle = .overFullScreen
  2614. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2615. UIApplication.shared.visibleViewController?.navigationController?.present(previewController, animated: true, completion: nil)
  2616. } else {
  2617. UIApplication.shared.visibleViewController?.present(previewController, animated: true, completion: nil)
  2618. }
  2619. } else if FileEncryption.shared.isSecureExists(filename: file) {
  2620. do {
  2621. if let docData = try FileEncryption.shared.readSecure(filename: file) {
  2622. let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
  2623. let tempPath = cachesDirectory.appendingPathComponent(file)
  2624. try docData.write(to: tempPath)
  2625. previewItem = tempPath as NSURL
  2626. let previewController = QLPreviewController()
  2627. let rightBarButton = UIBarButtonItem()
  2628. previewController.navigationItem.rightBarButtonItem = rightBarButton
  2629. previewController.dataSource = self
  2630. previewController.modalPresentationStyle = .overFullScreen
  2631. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2632. UIApplication.shared.visibleViewController?.navigationController?.present(previewController, animated: true, completion: nil)
  2633. } else {
  2634. UIApplication.shared.visibleViewController?.present(previewController, animated: true, completion: nil)
  2635. }
  2636. }
  2637. } catch {
  2638. }
  2639. } else {
  2640. Download().startHTTP(forKey: file, isImage: false) { (name, progress) in
  2641. DispatchQueue.main.async {
  2642. guard progress == 100 else {
  2643. return
  2644. }
  2645. do {
  2646. let secureFilename = try FileEncryption.shared.writeSecure(filename: name)
  2647. if let docData = try FileEncryption.shared.readSecure(filename: secureFilename?[0] as! String) {
  2648. let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
  2649. let tempPath = cachesDirectory.appendingPathComponent(file)
  2650. try docData.write(to: tempPath)
  2651. previewItem = tempPath as NSURL
  2652. let previewController = QLPreviewController()
  2653. let rightBarButton = UIBarButtonItem()
  2654. previewController.navigationItem.rightBarButtonItem = rightBarButton
  2655. previewController.dataSource = self
  2656. previewController.modalPresentationStyle = .overFullScreen
  2657. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2658. UIApplication.shared.visibleViewController?.navigationController?.present(previewController, animated: true, completion: nil)
  2659. } else {
  2660. UIApplication.shared.visibleViewController?.present(previewController, animated: true, completion: nil)
  2661. }
  2662. }
  2663. }
  2664. catch {
  2665. }
  2666. }
  2667. }
  2668. }
  2669. }
  2670. }
  2671. })
  2672. }
  2673. }
  2674. broadcastVC.modalTransitionStyle = .crossDissolve
  2675. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2676. UIApplication.shared.visibleViewController?.navigationController?.present(broadcastVC, animated: true, completion: nil)
  2677. } else {
  2678. UIApplication.shared.visibleViewController?.present(broadcastVC, animated: true, completion: nil)
  2679. }
  2680. }
  2681. }
  2682. public func onReceive(message: TMessage) {
  2683. var dataMessage: [AnyHashable : Any] = [:]
  2684. dataMessage["message"] = message
  2685. NotificationCenter.default.post(name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil, userInfo: dataMessage)
  2686. if message.getCode() == CoreMessage_TMessageCode.PUSH_CALL_CENTER {
  2687. if User.getDataCanNil(pin: message.getBody(key: CoreMessage_TMessageKey.L_PIN)) == nil {
  2688. Nexilis.addFriendSilent(fpin: message.getBody(key: CoreMessage_TMessageKey.L_PIN))
  2689. sleep(1)
  2690. }
  2691. DispatchQueue.main.async {
  2692. if Nexilis.onGoingPushCC.isEmpty {
  2693. var data: [String: String] = [:]
  2694. data["channel"] = message.getBody(key: CoreMessage_TMessageKey.CHANNEL)
  2695. data["l_pin"] = message.getBody(key: CoreMessage_TMessageKey.L_PIN)
  2696. data["f_display_name"] = message.getBody(key: CoreMessage_TMessageKey.F_DISPLAY_NAME)
  2697. Nexilis.onGoingPushCC = data
  2698. } else if Nexilis.onGoingPushCC["f_display_name"] == message.getBody(key: CoreMessage_TMessageKey.F_DISPLAY_NAME) {
  2699. return
  2700. }
  2701. let alert = LibAlertController(title: "", message: "\n\n\n\n\n\n\n\n\n\n".localized(), preferredStyle: .alert)
  2702. let newWidth = UIScreen.main.bounds.width * 0.90 - 270
  2703. // update width constraint value for main view
  2704. if let viewWidthConstraint = alert.view.constraints.filter({ return $0.firstAttribute == .width }).first{
  2705. viewWidthConstraint.constant = newWidth
  2706. }
  2707. // update width constraint value for container view
  2708. if let containerViewWidthConstraint = alert.view.subviews.first?.constraints.filter({ return $0.firstAttribute == .width }).first {
  2709. containerViewWidthConstraint.constant = newWidth
  2710. }
  2711. let titleFont = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 18), NSAttributedString.Key.foregroundColor: UIColor.black]
  2712. let titleAttrString = NSMutableAttributedString(string: "Call Center".localized(), attributes: titleFont)
  2713. alert.setValue(titleAttrString, forKey: "attributedTitle")
  2714. alert.view.subviews.first?.subviews.first?.subviews.first?.backgroundColor = .lightGray
  2715. alert.view.tintColor = .black
  2716. let rejectAction = UIAlertAction(title: "Pass to other representative".localized(), style: .destructive, handler: {(_) in
  2717. DispatchQueue.global().async {
  2718. _ = Nexilis.write(message: CoreMessage_TMessageBank.timeOutRequestCallCenter(channel: message.getBody(key: CoreMessage_TMessageKey.CHANNEL), l_pin: message.getBody(key: CoreMessage_TMessageKey.L_PIN)))
  2719. }
  2720. Nexilis.onGoingPushCC.removeAll()
  2721. alert.dismiss(animated: true, completion: nil)
  2722. })
  2723. let acceptAction = UIAlertAction(title: "I'll handle the customer".localized(), style: .default, handler: {(_) in
  2724. let goAudioCall = Nexilis.checkMicPermission()
  2725. if !goAudioCall && message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "1" {
  2726. let alert = LibAlertController(title: "Attention!".localized(), message: "Please allow microphone permission in your settings".localized(), preferredStyle: .alert)
  2727. alert.addAction(UIAlertAction(title: "OK".localized(), style: UIAlertAction.Style.default, handler: { _ in
  2728. if let url = URL(string: UIApplication.openSettingsURLString), UIApplication.shared.canOpenURL(url) {
  2729. UIApplication.shared.open(url, options: [:], completionHandler: nil)
  2730. }
  2731. }))
  2732. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2733. UIApplication.shared.visibleViewController?.navigationController?.present(alert, animated: true, completion: nil)
  2734. } else {
  2735. UIApplication.shared.visibleViewController?.present(alert, animated: true, completion: nil)
  2736. }
  2737. DispatchQueue.global().async {
  2738. DispatchQueue.global().async {
  2739. _ = Nexilis.write(message: CoreMessage_TMessageBank.timeOutRequestCallCenter(channel: message.getBody(key: CoreMessage_TMessageKey.CHANNEL), l_pin: message.getBody(key: CoreMessage_TMessageKey.L_PIN)))
  2740. }
  2741. }
  2742. Nexilis.onGoingPushCC.removeAll()
  2743. return
  2744. }
  2745. if message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "2" {
  2746. var permissionCheck = -1
  2747. if AVCaptureDevice.authorizationStatus(for: .video) == .authorized {
  2748. permissionCheck = 1
  2749. } else if AVCaptureDevice.authorizationStatus(for: .video) == .denied {
  2750. permissionCheck = 0
  2751. } else {
  2752. Nexilis.dispatch = DispatchGroup()
  2753. Nexilis.dispatch?.enter()
  2754. AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) -> Void in
  2755. if granted == true {
  2756. permissionCheck = 1
  2757. } else {
  2758. permissionCheck = 0
  2759. }
  2760. if let dispatch = Nexilis.dispatch {
  2761. dispatch.leave()
  2762. }
  2763. })
  2764. Nexilis.dispatch?.wait()
  2765. Nexilis.dispatch = nil
  2766. }
  2767. if permissionCheck == 0 {
  2768. let alert = LibAlertController(title: "Attention!".localized(), message: "Please allow camera permission in your settings".localized(), preferredStyle: .alert)
  2769. alert.addAction(UIAlertAction(title: "OK".localized(), style: UIAlertAction.Style.default, handler: { _ in
  2770. if let url = URL(string: UIApplication.openSettingsURLString), UIApplication.shared.canOpenURL(url) {
  2771. UIApplication.shared.open(url, options: [:], completionHandler: nil)
  2772. }
  2773. }))
  2774. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2775. UIApplication.shared.visibleViewController?.navigationController?.present(alert, animated: true, completion: nil)
  2776. } else {
  2777. UIApplication.shared.visibleViewController?.present(alert, animated: true, completion: nil)
  2778. }
  2779. DispatchQueue.global().async {
  2780. DispatchQueue.global().async {
  2781. _ = Nexilis.write(message: CoreMessage_TMessageBank.timeOutRequestCallCenter(channel: message.getBody(key: CoreMessage_TMessageKey.CHANNEL), l_pin: message.getBody(key: CoreMessage_TMessageKey.L_PIN)))
  2782. }
  2783. }
  2784. Nexilis.onGoingPushCC.removeAll()
  2785. return
  2786. }
  2787. }
  2788. if UIApplication.shared.visibleViewController is UINavigationController {
  2789. let nc = UIApplication.shared.visibleViewController as! UINavigationController
  2790. if nc.visibleViewController is QmeraStreamingViewController {
  2791. let vc = nc.visibleViewController as! QmeraStreamingViewController
  2792. var alert = LibAlertController(title: "", message: "Are you sure you want to end Live Streaming, and open notification?".localized(), preferredStyle: .alert)
  2793. if !vc.isLive {
  2794. alert = LibAlertController(title: "", message: "Are you sure you want to leave Live Streaming, and open notification?".localized(), preferredStyle: .alert)
  2795. }
  2796. alert.addAction(UIAlertAction(title: "No".localized(), style: UIAlertAction.Style.default, handler: { _ in
  2797. DispatchQueue.global().async {
  2798. _ = Nexilis.write(message: CoreMessage_TMessageBank.timeOutRequestCallCenter(channel: message.getBody(key: CoreMessage_TMessageKey.CHANNEL), l_pin: message.getBody(key: CoreMessage_TMessageKey.L_PIN)))
  2799. }
  2800. Nexilis.onGoingPushCC.removeAll()
  2801. alert.dismiss(animated: true, completion: nil)
  2802. }))
  2803. alert.addAction(UIAlertAction(title: "Yes".localized(), style: UIAlertAction.Style.default, handler: { _ in
  2804. DispatchQueue.global().async {
  2805. API.terminateBC(sBroadcasterID: vc.isLive ? nil : vc.data)
  2806. vc.sendLeft()
  2807. }
  2808. vc.dismiss(animated: true, completion: {
  2809. acceptCC()
  2810. })
  2811. }))
  2812. nc.present(alert, animated: true, completion: nil)
  2813. // NotificationCenter.default.post(name: NSNotification.Name(rawValue: "isRunningStreaming"), object: nil, userInfo: dataMessage)
  2814. } else if nc.visibleViewController is SeminarViewController {
  2815. let vc = nc.visibleViewController as! SeminarViewController
  2816. var alert = LibAlertController(title: "", message: "Are you sure you want to end Seminar, and open notification?".localized(), preferredStyle: .alert)
  2817. if !vc.isLive {
  2818. alert = LibAlertController(title: "", message: "Are you sure you want to leave Seminar, and open notification?".localized(), preferredStyle: .alert)
  2819. }
  2820. alert.addAction(UIAlertAction(title: "No".localized(), style: UIAlertAction.Style.default, handler: { _ in
  2821. DispatchQueue.global().async {
  2822. _ = Nexilis.write(message: CoreMessage_TMessageBank.timeOutRequestCallCenter(channel: message.getBody(key: CoreMessage_TMessageKey.CHANNEL), l_pin: message.getBody(key: CoreMessage_TMessageKey.L_PIN)))
  2823. }
  2824. Nexilis.onGoingPushCC.removeAll()
  2825. alert.dismiss(animated: true, completion: nil)
  2826. }))
  2827. alert.addAction(UIAlertAction(title: "Yes".localized(), style: UIAlertAction.Style.default, handler: { _ in
  2828. DispatchQueue.global().async {
  2829. API.terminateBC(sBroadcasterID: vc.isLive ? nil : vc.data)
  2830. vc.sendLeft()
  2831. }
  2832. vc.dismiss(animated: true, completion: {
  2833. acceptCC()
  2834. })
  2835. }))
  2836. nc.present(alert, animated: true, completion: nil)
  2837. // NotificationCenter.default.post(name: NSNotification.Name(rawValue: "isRunningStreaming"), object: nil, userInfo: dataMessage)
  2838. } else {
  2839. acceptCC()
  2840. }
  2841. } else {
  2842. acceptCC()
  2843. }
  2844. func acceptCC() {
  2845. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.acceptRequestCallCenter(channel: message.getBody(key: CoreMessage_TMessageKey.CHANNEL), l_pin: message.getBody(key: CoreMessage_TMessageKey.L_PIN), complaint_id: message.getBody(key: CoreMessage_TMessageKey.DATA))) {
  2846. if (response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "00") {
  2847. Nexilis.onGoingPushCC.removeAll()
  2848. let complaintId = response.getBody(key: CoreMessage_TMessageKey.DATA, default_value: "")
  2849. if !complaintId.isEmpty {
  2850. alert.dismiss(animated: true, completion: nil)
  2851. let idMe = User.getMyPin()!
  2852. SecureUserDefaults.shared.set("\(message.getBody(key: CoreMessage_TMessageKey.L_PIN)),\(idMe),\(complaintId)", forKey: "onGoingCC")
  2853. SecureUserDefaults.shared.set("\(message.getBody(key: CoreMessage_TMessageKey.L_PIN))", forKey: "membersCC")
  2854. SecureUserDefaults.shared.set("\(message.getBody(key: CoreMessage_TMessageKey.CHANNEL))", forKey: "channelCC")
  2855. if message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "0" {
  2856. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  2857. editorPersonalVC.isContactCenter = true
  2858. editorPersonalVC.isRequestContactCenter = false
  2859. editorPersonalVC.unique_l_pin = message.getBody(key: CoreMessage_TMessageKey.L_PIN)
  2860. editorPersonalVC.complaintId = complaintId
  2861. editorPersonalVC.channelContactCenter = message.getBody(key: CoreMessage_TMessageKey.CHANNEL)
  2862. editorPersonalVC.fPinContacCenter = message.getBody(key: CoreMessage_TMessageKey.L_PIN)
  2863. let navigationController = CustomNavigationController(rootViewController: editorPersonalVC)
  2864. navigationController.modalPresentationStyle = .fullScreen
  2865. navigationController.navigationBar.tintColor = .white
  2866. navigationController.navigationBar.barTintColor = UIApplication.shared.visibleViewController?.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  2867. navigationController.navigationBar.isTranslucent = false
  2868. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  2869. navigationController.navigationBar.barStyle = .black
  2870. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  2871. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  2872. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  2873. navigationController.navigationBar.titleTextAttributes = textAttributes
  2874. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2875. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  2876. } else {
  2877. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  2878. }
  2879. } else {
  2880. SecureUserDefaults.shared.set("\(Date().currentTimeMillis())", forKey: "startTimeCC")
  2881. DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
  2882. if message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "1" {
  2883. let pin = message.getBody(key: CoreMessage_TMessageKey.L_PIN)
  2884. let controller = QmeraAudioViewController()
  2885. controller.user = User.getData(pin: pin)
  2886. controller.isOutgoing = true
  2887. controller.ticketId = complaintId
  2888. controller.modalPresentationStyle = .overCurrentContext
  2889. let navigationController = CustomNavigationController(rootViewController: controller)
  2890. navigationController.modalPresentationStyle = .fullScreen
  2891. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2892. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  2893. } else {
  2894. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  2895. }
  2896. } else if message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "2" {
  2897. let videoVC = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "videoVCQmera") as! QmeraVideoViewController
  2898. videoVC.fPin = message.getBody(key: CoreMessage_TMessageKey.L_PIN)
  2899. videoVC.users.append(User.getData(pin: message.getBody(key: CoreMessage_TMessageKey.L_PIN))!)
  2900. videoVC.ticketId = complaintId
  2901. let navigationController = CustomNavigationController(rootViewController: videoVC)
  2902. navigationController.modalPresentationStyle = .fullScreen
  2903. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2904. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  2905. } else {
  2906. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  2907. }
  2908. }
  2909. })
  2910. }
  2911. }
  2912. }
  2913. }
  2914. }
  2915. })
  2916. alert.addAction(acceptAction)
  2917. alert.addAction(rejectAction)
  2918. let containerView = UIView(frame: CGRect(x: 20, y: 60, width: alert.view.bounds.size.width * 0.9 - 40, height: 150))
  2919. alert.view.addSubview(containerView)
  2920. containerView.layer.cornerRadius = 10.0
  2921. containerView.clipsToBounds = true
  2922. containerView.backgroundColor = .secondaryColor.withAlphaComponent(0.5)
  2923. let imageProfile = UIImageView()
  2924. containerView.addSubview(imageProfile)
  2925. imageProfile.translatesAutoresizingMaskIntoConstraints = false
  2926. NSLayoutConstraint.activate([
  2927. imageProfile.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 10),
  2928. imageProfile.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -10),
  2929. imageProfile.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 10),
  2930. imageProfile.widthAnchor.constraint(equalToConstant: 100)
  2931. ])
  2932. imageProfile.layer.cornerRadius = 10.0
  2933. imageProfile.clipsToBounds = true
  2934. imageProfile.backgroundColor = .lightGray.withAlphaComponent(0.3)
  2935. imageProfile.tintColor = .secondaryColor
  2936. imageProfile.image = UIImage(systemName: "person")
  2937. if message.getBody(key: CoreMessage_TMessageKey.THUMB_ID) != "" {
  2938. imageProfile.setImage(name: message.getBody(key: CoreMessage_TMessageKey.THUMB_ID))
  2939. imageProfile.contentMode = .scaleAspectFill
  2940. }
  2941. let labelName = UILabel()
  2942. containerView.addSubview(labelName)
  2943. labelName.translatesAutoresizingMaskIntoConstraints = false
  2944. NSLayoutConstraint.activate([
  2945. labelName.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 15),
  2946. labelName.leadingAnchor.constraint(equalTo: imageProfile.trailingAnchor, constant: 5)
  2947. ])
  2948. labelName.font = UIFont.systemFont(ofSize: 12)
  2949. labelName.text = "Name".localized()
  2950. labelName.textColor = .mainColor
  2951. let valueName = UILabel()
  2952. containerView.addSubview(valueName)
  2953. valueName.translatesAutoresizingMaskIntoConstraints = false
  2954. NSLayoutConstraint.activate([
  2955. valueName.topAnchor.constraint(equalTo: labelName.bottomAnchor),
  2956. valueName.leadingAnchor.constraint(equalTo: imageProfile.trailingAnchor, constant: 5)
  2957. ])
  2958. valueName.font = UIFont.systemFont(ofSize: 12)
  2959. valueName.text = message.getBody(key: CoreMessage_TMessageKey.F_DISPLAY_NAME)
  2960. valueName.textColor = .mainColor
  2961. let labelType = UILabel()
  2962. containerView.addSubview(labelType)
  2963. labelType.translatesAutoresizingMaskIntoConstraints = false
  2964. NSLayoutConstraint.activate([
  2965. labelType.topAnchor.constraint(equalTo: valueName.bottomAnchor, constant: 5),
  2966. labelType.leadingAnchor.constraint(equalTo: imageProfile.trailingAnchor, constant: 5)
  2967. ])
  2968. labelType.font = UIFont.systemFont(ofSize: 12)
  2969. labelType.text = "Request Type".localized()
  2970. labelType.textColor = .mainColor
  2971. let valueType = UILabel()
  2972. containerView.addSubview(valueType)
  2973. valueType.translatesAutoresizingMaskIntoConstraints = false
  2974. NSLayoutConstraint.activate([
  2975. valueType.topAnchor.constraint(equalTo: labelType.bottomAnchor),
  2976. valueType.leadingAnchor.constraint(equalTo: imageProfile.trailingAnchor, constant: 5)
  2977. ])
  2978. valueType.font = UIFont.systemFont(ofSize: 12)
  2979. if message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "0" {
  2980. valueType.text = "Chat".localized()
  2981. } else if message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "1" {
  2982. valueType.text = "Audio Call".localized()
  2983. } else if message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "2" {
  2984. valueType.text = "Video Call".localized()
  2985. } else {
  2986. valueType.text = "Email".localized()
  2987. }
  2988. valueType.textColor = .mainColor
  2989. let labelIdentity = UILabel()
  2990. containerView.addSubview(labelIdentity)
  2991. labelIdentity.translatesAutoresizingMaskIntoConstraints = false
  2992. NSLayoutConstraint.activate([
  2993. labelIdentity.topAnchor.constraint(equalTo: valueType.bottomAnchor, constant: 5),
  2994. labelIdentity.leadingAnchor.constraint(equalTo: imageProfile.trailingAnchor, constant: 5)
  2995. ])
  2996. labelIdentity.font = UIFont.systemFont(ofSize: 12)
  2997. labelIdentity.text = "Complaint ID".localized()
  2998. labelIdentity.textColor = .mainColor
  2999. let valueIdentity = UILabel()
  3000. containerView.addSubview(valueIdentity)
  3001. valueIdentity.translatesAutoresizingMaskIntoConstraints = false
  3002. NSLayoutConstraint.activate([
  3003. valueIdentity.topAnchor.constraint(equalTo: labelIdentity.bottomAnchor),
  3004. valueIdentity.leadingAnchor.constraint(equalTo: imageProfile.trailingAnchor, constant: 5),
  3005. valueIdentity.trailingAnchor.constraint(equalTo: containerView.trailingAnchor)
  3006. ])
  3007. valueIdentity.font = UIFont.systemFont(ofSize: 12)
  3008. valueIdentity.text = message.getBody(key: CoreMessage_TMessageKey.DATA)
  3009. valueIdentity.numberOfLines = 0
  3010. valueIdentity.textColor = .mainColor
  3011. var isShowAlert: Int?
  3012. let canShow = UIApplication.shared.visibleViewController
  3013. if canShow != nil && !(canShow is UINavigationController) {
  3014. if !(canShow is EditorPersonal) && !(canShow is QmeraAudioViewController) && !(canShow is QmeraVideoViewController) {
  3015. isShowAlert = 0
  3016. } else {
  3017. isShowAlert = 3
  3018. }
  3019. } else if canShow != nil {
  3020. if canShow is UINavigationController {
  3021. let canShowNC = canShow as! UINavigationController
  3022. if !(canShowNC.visibleViewController is EditorPersonal) && !(canShowNC.visibleViewController is QmeraAudioViewController) && !(canShowNC.visibleViewController is QmeraVideoViewController) {
  3023. isShowAlert = 0
  3024. } else {
  3025. isShowAlert = 3
  3026. }
  3027. } else {
  3028. isShowAlert = 0
  3029. }
  3030. }
  3031. DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(isShowAlert!), execute: {
  3032. if UIApplication.shared.visibleViewController?.navigationController != nil {
  3033. UIApplication.shared.visibleViewController?.navigationController?.present(alert, animated: true, completion: nil)
  3034. } else {
  3035. UIApplication.shared.visibleViewController?.present(alert, animated: true, completion: nil)
  3036. }
  3037. })
  3038. }
  3039. } else if message.getCode() == CoreMessage_TMessageCode.ACCEPT_CALL_CENTER {
  3040. let fPinContacCenter = message.getBody(key: CoreMessage_TMessageKey.F_PIN)
  3041. let requester = message.getBody(key: CoreMessage_TMessageKey.UPLINE_PIN)
  3042. let complaintId = message.getBody(key: CoreMessage_TMessageKey.DATA)
  3043. let onGoingCC: String = SecureUserDefaults.shared.value(forKey: "onGoingCC") ?? ""
  3044. if !requester.isEmpty && onGoingCC.isEmpty {
  3045. SecureUserDefaults.shared.set("\(requester),\(fPinContacCenter),\(complaintId)", forKey: "onGoingCC")
  3046. SecureUserDefaults.shared.set("\(fPinContacCenter)", forKey: "membersCC")
  3047. }
  3048. } else if message.getCode() == CoreMessage_TMessageCode.INVITE_TO_ROOM_CONTACT_CENTER {
  3049. if listCCIdInv.contains(message.getBody(key: CoreMessage_TMessageKey.CALL_CENTER_ID)) {
  3050. return
  3051. }
  3052. listCCIdInv.append(message.getBody(key: CoreMessage_TMessageKey.CALL_CENTER_ID))
  3053. DispatchQueue.main.async {
  3054. let alert = LibAlertController(title: "", message: "\n\n\n\n\n\n\n\n\n\n".localized(), preferredStyle: .alert)
  3055. let newWidth = UIScreen.main.bounds.width * 0.90 - 270
  3056. // update width constraint value for main view
  3057. if let viewWidthConstraint = alert.view.constraints.filter({ return $0.firstAttribute == .width }).first{
  3058. viewWidthConstraint.constant = newWidth
  3059. }
  3060. // update width constraint value for container view
  3061. if let containerViewWidthConstraint = alert.view.subviews.first?.constraints.filter({ return $0.firstAttribute == .width }).first {
  3062. containerViewWidthConstraint.constant = newWidth
  3063. }
  3064. let titleFont = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 18), NSAttributedString.Key.foregroundColor: UIColor.black]
  3065. let titleAttrString = NSMutableAttributedString(string: "You're invited to\nCall Center".localized(), attributes: titleFont)
  3066. alert.setValue(titleAttrString, forKey: "attributedTitle")
  3067. alert.view.subviews.first?.subviews.first?.subviews.first?.backgroundColor = .lightGray
  3068. alert.view.tintColor = .black
  3069. let rejectAction = UIAlertAction(title: "Reject".localized(), style: .destructive, handler: {(_) in
  3070. listCCIdInv.removeAll(where: {$0 == message.getBody(key: CoreMessage_TMessageKey.CALL_CENTER_ID)})
  3071. DispatchQueue.global().async {
  3072. if let result = Nexilis.writeSync(message: CoreMessage_TMessageBank.acceptCCRoomInvite(l_pin: message.getPIN(), type: 0, ticket_id: message.getBody(key: CoreMessage_TMessageKey.CALL_CENTER_ID))) {
  3073. if result.isOk() {
  3074. return
  3075. }
  3076. }
  3077. }
  3078. alert.dismiss(animated: true, completion: nil)
  3079. })
  3080. let acceptAction = UIAlertAction(title: "Accept".localized(), style: .default, handler: {(_) in
  3081. listCCIdInv.removeAll(where: {$0 == message.getBody(key: CoreMessage_TMessageKey.CALL_CENTER_ID)})
  3082. let goAudioCall = Nexilis.checkMicPermission()
  3083. if !goAudioCall && message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "1" {
  3084. let alert = LibAlertController(title: "Attention!".localized(), message: "Please allow microphone permission in your settings".localized(), preferredStyle: .alert)
  3085. alert.addAction(UIAlertAction(title: "OK".localized(), style: UIAlertAction.Style.default, handler: { _ in
  3086. if let url = URL(string: UIApplication.openSettingsURLString), UIApplication.shared.canOpenURL(url) {
  3087. UIApplication.shared.open(url, options: [:], completionHandler: nil)
  3088. }
  3089. }))
  3090. if UIApplication.shared.visibleViewController?.navigationController != nil {
  3091. UIApplication.shared.visibleViewController?.navigationController?.present(alert, animated: true, completion: nil)
  3092. } else {
  3093. UIApplication.shared.visibleViewController?.present(alert, animated: true, completion: nil)
  3094. }
  3095. DispatchQueue.global().async {
  3096. if let result = Nexilis.writeSync(message: CoreMessage_TMessageBank.acceptCCRoomInvite(l_pin: message.getPIN(), type: 0, ticket_id: message.getBody(key: CoreMessage_TMessageKey.CALL_CENTER_ID))) {
  3097. if result.isOk() {
  3098. return
  3099. }
  3100. }
  3101. }
  3102. return
  3103. }
  3104. if message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "2" {
  3105. var permissionCheck = -1
  3106. if AVCaptureDevice.authorizationStatus(for: .video) == .authorized {
  3107. permissionCheck = 1
  3108. } else if AVCaptureDevice.authorizationStatus(for: .video) == .denied {
  3109. permissionCheck = 0
  3110. } else {
  3111. Nexilis.dispatch = DispatchGroup()
  3112. Nexilis.dispatch?.enter()
  3113. AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) -> Void in
  3114. if granted == true {
  3115. permissionCheck = 1
  3116. } else {
  3117. permissionCheck = 0
  3118. }
  3119. if let dispatch = Nexilis.dispatch {
  3120. dispatch.leave()
  3121. }
  3122. })
  3123. Nexilis.dispatch?.wait()
  3124. Nexilis.dispatch = nil
  3125. }
  3126. if permissionCheck == 0 {
  3127. let alert = LibAlertController(title: "Attention!".localized(), message: "Please allow camera permission in your settings".localized(), preferredStyle: .alert)
  3128. alert.addAction(UIAlertAction(title: "OK".localized(), style: UIAlertAction.Style.default, handler: { _ in
  3129. if let url = URL(string: UIApplication.openSettingsURLString), UIApplication.shared.canOpenURL(url) {
  3130. UIApplication.shared.open(url, options: [:], completionHandler: nil)
  3131. }
  3132. }))
  3133. if UIApplication.shared.visibleViewController?.navigationController != nil {
  3134. UIApplication.shared.visibleViewController?.navigationController?.present(alert, animated: true, completion: nil)
  3135. } else {
  3136. UIApplication.shared.visibleViewController?.present(alert, animated: true, completion: nil)
  3137. }
  3138. DispatchQueue.global().async {
  3139. if let result = Nexilis.writeSync(message: CoreMessage_TMessageBank.acceptCCRoomInvite(l_pin: message.getPIN(), type: 0, ticket_id: message.getBody(key: CoreMessage_TMessageKey.CALL_CENTER_ID))) {
  3140. if result.isOk() {
  3141. return
  3142. }
  3143. }
  3144. }
  3145. return
  3146. }
  3147. }
  3148. if UIApplication.shared.visibleViewController is UINavigationController {
  3149. let nc = UIApplication.shared.visibleViewController as! UINavigationController
  3150. if nc.visibleViewController is QmeraStreamingViewController {
  3151. let vc = nc.visibleViewController as! QmeraStreamingViewController
  3152. var alert = LibAlertController(title: "", message: "Are you sure you want to end Live Streaming, and open notification?".localized(), preferredStyle: .alert)
  3153. if !vc.isLive {
  3154. alert = LibAlertController(title: "", message: "Are you sure you want to leave Live Streaming, and open notification?".localized(), preferredStyle: .alert)
  3155. }
  3156. alert.addAction(UIAlertAction(title: "No".localized(), style: UIAlertAction.Style.default, handler: { _ in
  3157. DispatchQueue.global().async {
  3158. if let result = Nexilis.writeSync(message: CoreMessage_TMessageBank.acceptCCRoomInvite(l_pin: message.getPIN(), type: 0, ticket_id: message.getBody(key: CoreMessage_TMessageKey.CALL_CENTER_ID))) {
  3159. if result.isOk() {
  3160. return
  3161. }
  3162. }
  3163. }
  3164. alert.dismiss(animated: true, completion: nil)
  3165. }))
  3166. alert.addAction(UIAlertAction(title: "Yes".localized(), style: UIAlertAction.Style.default, handler: { _ in
  3167. DispatchQueue.global().async {
  3168. API.terminateBC(sBroadcasterID: vc.isLive ? nil : vc.data)
  3169. vc.sendLeft()
  3170. }
  3171. vc.dismiss(animated: true, completion: {
  3172. acceptCC()
  3173. })
  3174. }))
  3175. nc.present(alert, animated: true, completion: nil)
  3176. } else if nc.visibleViewController is SeminarViewController {
  3177. let vc = nc.visibleViewController as! SeminarViewController
  3178. var alert = LibAlertController(title: "", message: "Are you sure you want to end Seminar, and open notification?".localized(), preferredStyle: .alert)
  3179. if !vc.isLive {
  3180. alert = LibAlertController(title: "", message: "Are you sure you want to leave Seminar, and open notification?".localized(), preferredStyle: .alert)
  3181. }
  3182. alert.addAction(UIAlertAction(title: "No".localized(), style: UIAlertAction.Style.default, handler: { _ in
  3183. DispatchQueue.global().async {
  3184. if let result = Nexilis.writeSync(message: CoreMessage_TMessageBank.acceptCCRoomInvite(l_pin: message.getPIN(), type: 0, ticket_id: message.getBody(key: CoreMessage_TMessageKey.CALL_CENTER_ID))) {
  3185. if result.isOk() {
  3186. return
  3187. }
  3188. }
  3189. }
  3190. alert.dismiss(animated: true, completion: nil)
  3191. }))
  3192. alert.addAction(UIAlertAction(title: "Yes".localized(), style: UIAlertAction.Style.default, handler: { _ in
  3193. DispatchQueue.global().async {
  3194. API.terminateBC(sBroadcasterID: vc.isLive ? nil : vc.data)
  3195. vc.sendLeft()
  3196. }
  3197. vc.dismiss(animated: true, completion: {
  3198. acceptCC()
  3199. })
  3200. }))
  3201. nc.present(alert, animated: true, completion: nil)
  3202. } else {
  3203. acceptCC()
  3204. }
  3205. } else {
  3206. acceptCC()
  3207. }
  3208. func acceptCC() {
  3209. if let result = Nexilis.writeSync(message: CoreMessage_TMessageBank.acceptCCRoomInvite(l_pin: message.getPIN(), type: 1, ticket_id: message.getBody(key: CoreMessage_TMessageKey.CALL_CENTER_ID))) {
  3210. if result.isOk() {
  3211. let requester = result.getBody(key: CoreMessage_TMessageKey.UPLINE_PIN)
  3212. let officer = result.getBody(key: CoreMessage_TMessageKey.FRIEND_FPIN)
  3213. let data = result.getBody(key: CoreMessage_TMessageKey.DATA)
  3214. let complaintId = message.getBody(key: CoreMessage_TMessageKey.CALL_CENTER_ID)
  3215. SecureUserDefaults.shared.set("\(requester),\(officer),\(complaintId)", forKey: "onGoingCC")
  3216. SecureUserDefaults.shared.set("\(Date().currentTimeMillis())", forKey: "startTimeCC")
  3217. if !data.isEmpty {
  3218. if let jsonArray = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [AnyObject] {
  3219. var members = ""
  3220. var user : [User] = []
  3221. let idMe = User.getMyPin()!
  3222. for json in jsonArray {
  3223. if "\(json)" != idMe {
  3224. if let userData = User.getData(pin: "\(json)") {
  3225. user.append(userData)
  3226. } else {
  3227. Nexilis.addFriendSilent(fpin: "\(json)")
  3228. DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
  3229. if let userData = User.getData(pin: "\(json)") {
  3230. user.append(userData)
  3231. }
  3232. })
  3233. }
  3234. if members.isEmpty {
  3235. members = "\(json)"
  3236. } else {
  3237. members += ",\(json)"
  3238. }
  3239. }
  3240. }
  3241. SecureUserDefaults.shared.set("\(members)", forKey: "membersCC")
  3242. if message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "0" {
  3243. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  3244. editorPersonalVC.hidesBottomBarWhenPushed = true
  3245. editorPersonalVC.unique_l_pin = officer
  3246. editorPersonalVC.fromNotification = true
  3247. editorPersonalVC.isContactCenter = true
  3248. editorPersonalVC.fPinContacCenter = members
  3249. editorPersonalVC.complaintId = complaintId
  3250. editorPersonalVC.onGoingCC = true
  3251. editorPersonalVC.isRequestContactCenter = false
  3252. editorPersonalVC.users = user
  3253. let navigationController = CustomNavigationController(rootViewController: editorPersonalVC)
  3254. navigationController.modalPresentationStyle = .fullScreen
  3255. navigationController.navigationBar.tintColor = .white
  3256. navigationController.navigationBar.barTintColor = UIApplication.shared.visibleViewController?.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  3257. navigationController.navigationBar.isTranslucent = false
  3258. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  3259. navigationController.navigationBar.barStyle = .black
  3260. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  3261. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  3262. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  3263. navigationController.navigationBar.titleTextAttributes = textAttributes
  3264. if UIApplication.shared.visibleViewController?.navigationController != nil {
  3265. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  3266. } else {
  3267. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  3268. }
  3269. } else {
  3270. SecureUserDefaults.shared.set("\(Date().currentTimeMillis())", forKey: "startTimeCC")
  3271. DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
  3272. if message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "1" {
  3273. let pin = officer
  3274. let controller = QmeraAudioViewController()
  3275. controller.user = User.getData(pin: pin)
  3276. controller.isOutgoing = false
  3277. controller.ticketId = complaintId
  3278. controller.modalPresentationStyle = .overCurrentContext
  3279. let navigationController = CustomNavigationController(rootViewController: controller)
  3280. navigationController.modalPresentationStyle = .fullScreen
  3281. if UIApplication.shared.visibleViewController?.navigationController != nil {
  3282. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  3283. } else {
  3284. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  3285. }
  3286. } else if message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "2" {
  3287. let videoVC = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "videoVCQmera") as! QmeraVideoViewController
  3288. videoVC.fPin = officer
  3289. videoVC.users.append(User.getData(pin: officer)!)
  3290. videoVC.ticketId = complaintId
  3291. videoVC.isInisiator = false
  3292. videoVC.isAutoAccept = true
  3293. let navigationController = CustomNavigationController(rootViewController: videoVC)
  3294. navigationController.modalPresentationStyle = .fullScreen
  3295. if UIApplication.shared.visibleViewController?.navigationController != nil {
  3296. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  3297. } else {
  3298. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  3299. }
  3300. }
  3301. })
  3302. }
  3303. }
  3304. }
  3305. } else {
  3306. let imageView = UIImageView(image: UIImage(systemName: "info.circle"))
  3307. imageView.tintColor = .white
  3308. let banner = FloatingNotificationBanner(title: "Call Center Session has ended".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .info, colors: nil, iconPosition: .center)
  3309. banner.show()
  3310. }
  3311. }
  3312. }
  3313. })
  3314. alert.addAction(rejectAction)
  3315. alert.addAction(acceptAction)
  3316. let containerView = UIView(frame: CGRect(x: 50, y: 80, width: alert.view.bounds.size.width * 0.9 - 100, height: 150))
  3317. alert.view.addSubview(containerView)
  3318. containerView.layer.cornerRadius = 10.0
  3319. containerView.clipsToBounds = true
  3320. containerView.backgroundColor = .secondaryColor.withAlphaComponent(0.5)
  3321. let userData = User.getData(pin: message.getPIN())
  3322. let imageProfile = UIImageView()
  3323. containerView.addSubview(imageProfile)
  3324. imageProfile.translatesAutoresizingMaskIntoConstraints = false
  3325. NSLayoutConstraint.activate([
  3326. imageProfile.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 10),
  3327. imageProfile.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -10),
  3328. imageProfile.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 10),
  3329. imageProfile.widthAnchor.constraint(equalToConstant: 100)
  3330. ])
  3331. imageProfile.layer.cornerRadius = 10.0
  3332. imageProfile.clipsToBounds = true
  3333. imageProfile.backgroundColor = .lightGray.withAlphaComponent(0.3)
  3334. imageProfile.tintColor = .secondaryColor
  3335. imageProfile.image = UIImage(systemName: "person")
  3336. if userData!.thumb != "" {
  3337. imageProfile.setImage(name: userData!.thumb)
  3338. imageProfile.contentMode = .scaleAspectFill
  3339. }
  3340. let labelName = UILabel()
  3341. containerView.addSubview(labelName)
  3342. labelName.translatesAutoresizingMaskIntoConstraints = false
  3343. NSLayoutConstraint.activate([
  3344. labelName.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 15),
  3345. labelName.leadingAnchor.constraint(equalTo: imageProfile.trailingAnchor, constant: 5)
  3346. ])
  3347. labelName.font = UIFont.systemFont(ofSize: 12)
  3348. labelName.text = "Name".localized()
  3349. labelName.textColor = .mainColor
  3350. let valueName = UILabel()
  3351. containerView.addSubview(valueName)
  3352. valueName.translatesAutoresizingMaskIntoConstraints = false
  3353. NSLayoutConstraint.activate([
  3354. valueName.topAnchor.constraint(equalTo: labelName.bottomAnchor),
  3355. valueName.leadingAnchor.constraint(equalTo: imageProfile.trailingAnchor, constant: 5)
  3356. ])
  3357. valueName.font = UIFont.systemFont(ofSize: 12)
  3358. valueName.text = userData!.fullName
  3359. valueName.textColor = .mainColor
  3360. let labelType = UILabel()
  3361. containerView.addSubview(labelType)
  3362. labelType.translatesAutoresizingMaskIntoConstraints = false
  3363. NSLayoutConstraint.activate([
  3364. labelType.topAnchor.constraint(equalTo: valueName.bottomAnchor, constant: 5),
  3365. labelType.leadingAnchor.constraint(equalTo: imageProfile.trailingAnchor, constant: 5)
  3366. ])
  3367. labelType.font = UIFont.systemFont(ofSize: 12)
  3368. labelType.text = "Request Type".localized()
  3369. labelType.textColor = .mainColor
  3370. let valueType = UILabel()
  3371. containerView.addSubview(valueType)
  3372. valueType.translatesAutoresizingMaskIntoConstraints = false
  3373. NSLayoutConstraint.activate([
  3374. valueType.topAnchor.constraint(equalTo: labelType.bottomAnchor),
  3375. valueType.leadingAnchor.constraint(equalTo: imageProfile.trailingAnchor, constant: 5)
  3376. ])
  3377. valueType.font = UIFont.systemFont(ofSize: 12)
  3378. if message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "0" {
  3379. valueType.text = "Chat".localized()
  3380. } else if message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "1" {
  3381. valueType.text = "Audio Call".localized()
  3382. } else if message.getBody(key: CoreMessage_TMessageKey.CHANNEL) == "2" {
  3383. valueType.text = "Video Call".localized()
  3384. } else {
  3385. valueType.text = "Email".localized()
  3386. }
  3387. valueType.textColor = .mainColor
  3388. let labelIdentity = UILabel()
  3389. containerView.addSubview(labelIdentity)
  3390. labelIdentity.translatesAutoresizingMaskIntoConstraints = false
  3391. NSLayoutConstraint.activate([
  3392. labelIdentity.topAnchor.constraint(equalTo: valueType.bottomAnchor, constant: 5),
  3393. labelIdentity.leadingAnchor.constraint(equalTo: imageProfile.trailingAnchor, constant: 5)
  3394. ])
  3395. labelIdentity.font = UIFont.systemFont(ofSize: 12)
  3396. labelIdentity.text = "Complaint ID".localized()
  3397. labelIdentity.textColor = .mainColor
  3398. let valueIdentity = UILabel()
  3399. containerView.addSubview(valueIdentity)
  3400. valueIdentity.translatesAutoresizingMaskIntoConstraints = false
  3401. NSLayoutConstraint.activate([
  3402. valueIdentity.topAnchor.constraint(equalTo: labelIdentity.bottomAnchor),
  3403. valueIdentity.leadingAnchor.constraint(equalTo: imageProfile.trailingAnchor, constant: 5),
  3404. valueIdentity.trailingAnchor.constraint(equalTo: containerView.trailingAnchor)
  3405. ])
  3406. valueIdentity.font = UIFont.systemFont(ofSize: 12)
  3407. valueIdentity.text = message.getBody(key: CoreMessage_TMessageKey.CALL_CENTER_ID)
  3408. valueIdentity.numberOfLines = 0
  3409. valueIdentity.textColor = .mainColor
  3410. if UIApplication.shared.visibleViewController?.navigationController != nil {
  3411. UIApplication.shared.visibleViewController?.navigationController?.present(alert, animated: true, completion: nil)
  3412. } else {
  3413. UIApplication.shared.visibleViewController?.present(alert, animated: true, completion: nil)
  3414. }
  3415. }
  3416. } else if message.getCode() != CoreMessage_TMessageCode.PUSH_CALL_CENTER && message.getCode() != CoreMessage_TMessageCode.ACCEPT_CALL_CENTER && message.getCode() != CoreMessage_TMessageCode.END_CALL_CENTER && message.getCode() != CoreMessage_TMessageCode.TIMEOUT_CONTACT_CENTER && message.getCode() != CoreMessage_TMessageCode.ACCEPT_CONTACT_CENTER && message.getCode() != CoreMessage_TMessageCode.PUSH_MEMBER_ROOM_CONTACT_CENTER && message.getCode() != CoreMessage_TMessageCode.INVITE_END_CONTACT_CENTER && message.getCode() != CoreMessage_TMessageCode.INVITE_EXIT_CONTACT_CENTER || !message.getBody(key: CoreMessage_TMessageKey.MERCHANT_NAME).isEmpty {
  3417. let m = message.mBodies
  3418. if !message.getBody(key: CoreMessage_TMessageKey.MERCHANT_NAME).isEmpty {
  3419. // Utils.setDebugBC(value: m)
  3420. DispatchQueue.main.async {
  3421. if !Nexilis.broadcastList.isEmpty {
  3422. Nexilis.broadcastList.append(m)
  3423. } else {
  3424. Nexilis.broadcastList.append(m)
  3425. Nexilis.shared.showBroadcastMessage(m: m)
  3426. }
  3427. }
  3428. return
  3429. }
  3430. if !Nexilis.showLibraryNotification || APIS.checkAppStateisBackground() {
  3431. return
  3432. }
  3433. let sender = message.getBody(key: CoreMessage_TMessageKey.F_PIN)
  3434. let me = User.getMyPin()!
  3435. if(sender != me) {
  3436. let inEditorPersonal: String? = SecureUserDefaults.shared.value(forKey: "inEditorPersonal") ?? nil
  3437. let inEditorGroup: [String]? = SecureUserDefaults.shared.value(forKey: "inEditorGroup") ?? nil
  3438. var text = message.getBody(key: CoreMessage_TMessageKey.MESSAGE_TEXT)
  3439. let imageId = CoreMessage_TMessageKey.IMAGE_ID
  3440. let videoId = CoreMessage_TMessageKey.VIDEO_ID
  3441. let fileId = CoreMessage_TMessageKey.FILE_ID
  3442. let audioId = CoreMessage_TMessageKey.AUDIO_ID
  3443. let attachmentFlag = CoreMessage_TMessageKey.ATTACHMENT_FLAG
  3444. let messageScopeId = CoreMessage_TMessageKey.MESSAGE_SCOPE_ID
  3445. let messageText = CoreMessage_TMessageKey.MESSAGE_TEXT
  3446. let credential = CoreMessage_TMessageKey.CREDENTIAL
  3447. let gif_id = CoreMessage_TMessageKey.GIF_ID
  3448. let is_secret = CoreMessage_TMessageKey.IS_SECRET
  3449. if message.getBody(key: is_secret) == "1" {
  3450. text = "You got messages..."
  3451. } else if message.getBody(key: gif_id) != "" {
  3452. text = "Sent GIF 🎬"
  3453. } else if !message.getBody(key: imageId).isEmpty {
  3454. text = "Sent Image 📷"
  3455. } else if message.getBody(key: attachmentFlag) == "11" {
  3456. text = "Sent Sticker ❤️"
  3457. } else if !message.getBody(key: videoId).isEmpty {
  3458. text = "Sent Video 📹"
  3459. } else if !message.getBody(key: fileId).isEmpty {
  3460. if message.getBody(key: messageScopeId) == MessageScope.FORM {
  3461. text = "Sent Form 📄"
  3462. } else {
  3463. text = "Sent File 📄"
  3464. }
  3465. } else if !message.getBody(key: audioId).isEmpty {
  3466. text = "Sent Audio ♫"
  3467. } else if message.getBody(key: messageText).contains("Share%20location%20") {
  3468. text = "Sent Location 📌"
  3469. } else if message.getBody(key: attachmentFlag) == "27" {
  3470. text = "Sent Live Streaming"
  3471. } else if message.getBody(key: attachmentFlag) == "26" {
  3472. text = "Sent Seminar"
  3473. } else if message.getBody(key: attachmentFlag) == "25" {
  3474. text = "Sent Video Conference Room"
  3475. } else if message.getBody(key: attachmentFlag) == "24" {
  3476. text = "Sent Quiz"
  3477. } else if message.getBody(key: credential) == "1" {
  3478. text = "Sent Confidential Message"
  3479. }
  3480. var nameUser: String?
  3481. var profile = ""
  3482. var threadIdentifier = sender
  3483. let onGoingCC: String = SecureUserDefaults.shared.value(forKey: "onGoingCC") ?? ""
  3484. if !onGoingCC.isEmpty {
  3485. return
  3486. }
  3487. // if Utils.inTabChats{
  3488. // return
  3489. // }
  3490. if message.getBody(key: messageScopeId) == MessageScope.WHISPER || message.getBody(key: messageScopeId) == MessageScope.FORM || message.getBody(key: messageScopeId) == MessageScope.CHATROOM {
  3491. if inEditorPersonal == sender || (inEditorPersonal != nil && inEditorPersonal!.contains(",")) {
  3492. return
  3493. }
  3494. if(nameUser == nil) {
  3495. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  3496. do {
  3497. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "SELECT first_name, last_name, image_id FROM BUDDY WHERE f_pin='\(String(describing: sender))'") {
  3498. while cursor.next() {
  3499. let first_name = cursor.string(forColumnIndex: 0)!
  3500. let last_name = cursor.string(forColumnIndex: 1)!
  3501. nameUser = "\(first_name) \(last_name)".trimmingCharacters(in: .whitespaces)
  3502. profile = cursor.string(forColumnIndex: 2)!
  3503. }
  3504. cursor.close()
  3505. }
  3506. } catch {
  3507. rollback.pointee = true
  3508. print("Access database error: \(error.localizedDescription)")
  3509. }
  3510. })
  3511. }
  3512. } else {
  3513. let idGroup = message.getBody(key: CoreMessage_TMessageKey.L_PIN)
  3514. var topicGroup: String?
  3515. var idTopic: String?
  3516. if !message.getBody(key: CoreMessage_TMessageKey.CHAT_ID).isEmpty {
  3517. idTopic = message.getBody(key: CoreMessage_TMessageKey.CHAT_ID)
  3518. }
  3519. if (idTopic == nil) {
  3520. idTopic = "Lounge"
  3521. topicGroup = "Lounge"
  3522. } else {
  3523. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  3524. do {
  3525. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "SELECT title FROM DISCUSSION_FORUM WHERE chat_id='\(idTopic!)'") {
  3526. while cursor.next() {
  3527. let title = cursor.string(forColumnIndex: 0)
  3528. topicGroup = title
  3529. }
  3530. cursor.close()
  3531. }
  3532. } catch {
  3533. rollback.pointee = true
  3534. print("Access database error: \(error.localizedDescription)")
  3535. }
  3536. })
  3537. }
  3538. if (inEditorGroup != nil) {
  3539. let editorIdGroup = inEditorGroup![0]
  3540. let editorIdTopic = inEditorGroup![1]
  3541. var idTempTopic = idTopic
  3542. if (idTempTopic == "Lounge") {
  3543. idTempTopic = ""
  3544. }
  3545. if (editorIdGroup == idGroup && editorIdTopic == idTempTopic) {
  3546. return
  3547. }
  3548. }
  3549. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  3550. do {
  3551. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "SELECT f_name, image_id FROM GROUPZ WHERE group_id='\(idGroup)'") {
  3552. while cursor.next() {
  3553. let f_name = cursor.string(forColumnIndex: 0)
  3554. var senderName = message.getBody(key: CoreMessage_TMessageKey.F_DISPLAY_NAME)
  3555. if senderName.isEmpty {
  3556. senderName = "Bot"
  3557. }
  3558. nameUser =
  3559. "\(senderName) \u{2022} \(f_name!)(\(topicGroup!))"
  3560. profile = cursor.string(forColumnIndex: 1)!
  3561. }
  3562. cursor.close()
  3563. }
  3564. } catch {
  3565. rollback.pointee = true
  3566. print("Access database error: \(error.localizedDescription)")
  3567. }
  3568. })
  3569. if idTopic == "Lounge" {
  3570. threadIdentifier = idGroup
  3571. } else {
  3572. threadIdentifier = idTopic!
  3573. }
  3574. }
  3575. if nameUser == nil && threadIdentifier == "-999" {
  3576. nameUser = "Bot"
  3577. }
  3578. DispatchQueue.main.async { [self] in
  3579. let container = UIView()
  3580. container.backgroundColor = .gray
  3581. let profileImage = UIImageView()
  3582. profileImage.frame.size = CGSize(width: 60, height: 60)
  3583. container.addSubview(profileImage)
  3584. profileImage.translatesAutoresizingMaskIntoConstraints = false
  3585. NSLayoutConstraint.activate([
  3586. profileImage.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 8.0),
  3587. profileImage.centerYAnchor.constraint(equalTo: container.centerYAnchor),
  3588. profileImage.widthAnchor.constraint(equalToConstant: 60),
  3589. profileImage.heightAnchor.constraint(equalToConstant: 60),
  3590. ])
  3591. let title = UILabel()
  3592. container.addSubview(title)
  3593. title.translatesAutoresizingMaskIntoConstraints = false
  3594. NSLayoutConstraint.activate([
  3595. title.leadingAnchor.constraint(equalTo: profileImage.trailingAnchor, constant: 8.0),
  3596. title.topAnchor.constraint(equalTo: container.topAnchor, constant: 20.0),
  3597. ])
  3598. title.font = UIFont.systemFont(ofSize: 14)
  3599. title.text = nameUser ?? "Unknown"
  3600. title.textColor = .white
  3601. let subtitle = UILabel()
  3602. container.addSubview(subtitle)
  3603. subtitle.translatesAutoresizingMaskIntoConstraints = false
  3604. NSLayoutConstraint.activate([
  3605. subtitle.leadingAnchor.constraint(equalTo: profileImage.trailingAnchor, constant: 8.0),
  3606. subtitle.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -15.0),
  3607. subtitle.topAnchor.constraint(equalTo: title.bottomAnchor),
  3608. ])
  3609. subtitle.font = UIFont.systemFont(ofSize: 12)
  3610. subtitle.attributedText = text.richText()
  3611. subtitle.textColor = .white
  3612. if floating != nil {
  3613. return
  3614. }
  3615. if UIApplication.shared.visibleViewController is UINavigationController {
  3616. let nc = UIApplication.shared.visibleViewController as! UINavigationController
  3617. if nc.visibleViewController is QmeraStreamingViewController {
  3618. return
  3619. } else if nc.visibleViewController is SeminarViewController {
  3620. return
  3621. }
  3622. }
  3623. if UIApplication.shared.visibleViewController is UIAlertController {
  3624. return
  3625. }
  3626. displayNotif()
  3627. func displayNotif() {
  3628. floating = FloatingNotificationBanner(customView: container)
  3629. floating.bannerHeight = 100.0
  3630. floating.transparency = 0.9
  3631. if threadIdentifier == "-999" {
  3632. if !Utils.getIconDock().isEmpty {
  3633. let dataImage = try? Data(contentsOf: URL(string: Utils.getUrlDock()!)!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
  3634. if dataImage != nil {
  3635. profileImage.image = UIImage(data: dataImage!)
  3636. }
  3637. } else {
  3638. profileImage.image = UIImage(named: "pb_button", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
  3639. }
  3640. } else if profile != "" {
  3641. profileImage.circle()
  3642. do {
  3643. let documentDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
  3644. let file = documentDir.appendingPathComponent(profile)
  3645. if FileManager().fileExists(atPath: file.path) {
  3646. profileImage.image = UIImage(contentsOfFile: file.path)
  3647. profileImage.backgroundColor = .clear
  3648. } else {
  3649. Download().startHTTP(forKey: profile) { (name, progress) in
  3650. guard progress == 100 else {
  3651. return
  3652. }
  3653. DispatchQueue.main.async { [self] in
  3654. profileImage.image = UIImage(contentsOfFile: file.path)
  3655. profileImage.backgroundColor = .clear
  3656. if !onGoingCC.isEmpty {
  3657. floating.autoDismiss = false
  3658. }
  3659. floating.show(queuePosition: .front, bannerPosition: .top, queue: NotificationBannerQueue(maxBannersOnScreenSimultaneously: 1), on: nil, edgeInsets: UIEdgeInsets(top: 8.0, left: 8.0, bottom: 0, right: 8.0), cornerRadius: 8.0, shadowColor: .clear, shadowOpacity: .zero, shadowBlurRadius: .zero, shadowCornerRadius: .zero, shadowOffset: .zero, shadowEdgeInsets: nil)
  3660. floating.onTap = {
  3661. self.floating = nil
  3662. showNotif()
  3663. }
  3664. var soundId: String = SecureUserDefaults.shared.value(forKey: "newNotifSoundPersonal") ?? "001:Nexilis Message (Default)"
  3665. if message.getBody(key: CoreMessage_TMessageKey.MESSAGE_SCOPE_ID) == MessageScope.GROUP {
  3666. soundId = SecureUserDefaults.shared.value(forKey: "newNotifSoundGroup") ?? "001:Nexilis Message (Default)"
  3667. }
  3668. do {
  3669. var nameSound = soundId.components(separatedBy: ":")[1].replacingOccurrences(of: " ", with: "_")
  3670. var fromPref = false
  3671. if nameSound.contains("_(Default)") {
  3672. if !Utils.getDefaultIncomingMsg().isEmpty {
  3673. nameSound = Utils.getDefaultIncomingMsg()
  3674. fromPref = true
  3675. } else {
  3676. nameSound = nameSound.replacingOccurrences(of: "_(Default)", with: "")
  3677. }
  3678. }
  3679. var soundURL: URL?
  3680. if fromPref {
  3681. let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
  3682. let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
  3683. let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
  3684. if let dirPath = paths.first {
  3685. let audioURL = URL(fileURLWithPath: dirPath).appendingPathComponent(nameSound)
  3686. if !FileManager.default.fileExists(atPath: audioURL.path) && !FileEncryption.shared.isSecureExists(filename: nameSound) {
  3687. Download().startHTTP(forKey: nameSound,downloadUrl: Utils.getURLBase() + "filepalio/ringtone/") { (name, progress) in
  3688. guard progress == 100 else {
  3689. return
  3690. }
  3691. playAudio()
  3692. }
  3693. } else {
  3694. playAudio()
  3695. }
  3696. func playAudio() {
  3697. if FileManager.default.fileExists(atPath: audioURL.path) {
  3698. do {
  3699. do {
  3700. try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
  3701. try AVAudioSession.sharedInstance().setActive(true)
  3702. } catch {
  3703. }
  3704. Nexilis.sharedAudioPlayer = try AVAudioPlayer(contentsOf: audioURL)
  3705. Nexilis.sharedAudioPlayer?.prepareToPlay()
  3706. Nexilis.sharedAudioPlayer?.play()
  3707. } catch {
  3708. }
  3709. } else if FileEncryption.shared.isSecureExists(filename: nameSound) {
  3710. do {
  3711. if let audioData = try FileEncryption.shared.readSecure(filename: nameSound) {
  3712. let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
  3713. let tempPath = cachesDirectory.appendingPathComponent(nameSound)
  3714. try audioData.write(to: tempPath)
  3715. do {
  3716. do {
  3717. try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
  3718. try AVAudioSession.sharedInstance().setActive(true)
  3719. } catch {
  3720. }
  3721. Nexilis.sharedAudioPlayer = try AVAudioPlayer(contentsOf: tempPath)
  3722. Nexilis.sharedAudioPlayer?.prepareToPlay()
  3723. Nexilis.sharedAudioPlayer?.play()
  3724. } catch {
  3725. }
  3726. }
  3727. } catch {
  3728. }
  3729. }
  3730. }
  3731. }
  3732. } else {
  3733. soundURL = Bundle.resourceBundle(for: Nexilis.self).url(forResource: nameSound, withExtension: "mp3")
  3734. if soundURL == nil {
  3735. soundURL = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: nameSound, withExtension: "mp3")
  3736. }
  3737. do {
  3738. do {
  3739. try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
  3740. try AVAudioSession.sharedInstance().setActive(true)
  3741. } catch {
  3742. }
  3743. Nexilis.sharedAudioPlayer = try AVAudioPlayer(contentsOf: soundURL!)
  3744. Nexilis.sharedAudioPlayer?.prepareToPlay()
  3745. Nexilis.sharedAudioPlayer?.play()
  3746. } catch {
  3747. }
  3748. }
  3749. DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
  3750. self.floating = nil
  3751. })
  3752. } catch {
  3753. }
  3754. }
  3755. }
  3756. return
  3757. }
  3758. } catch {}
  3759. profileImage.contentMode = .scaleAspectFill
  3760. } else {
  3761. profileImage.circle()
  3762. if message.getBody(key: messageScopeId) == MessageScope.WHISPER {
  3763. profileImage.image = UIImage(systemName: "person")
  3764. } else {
  3765. profileImage.image = UIImage(systemName: "person.3")
  3766. }
  3767. profileImage.contentMode = .scaleAspectFit
  3768. profileImage.backgroundColor = .lightGray
  3769. profileImage.tintColor = .white
  3770. }
  3771. floating.show(queuePosition: .front, bannerPosition: .top, queue: NotificationBannerQueue(maxBannersOnScreenSimultaneously: 1), on: nil, edgeInsets: UIEdgeInsets(top: 8.0, left: 8.0, bottom: 0, right: 8.0), cornerRadius: 8.0, shadowColor: .clear, shadowOpacity: .zero, shadowBlurRadius: .zero, shadowCornerRadius: .zero, shadowOffset: .zero, shadowEdgeInsets: nil)
  3772. // let vibrateMode: Bool = SecureUserDefaults.shared.value(forKey: "vibrateMode") ?? false
  3773. var soundId: String = SecureUserDefaults.shared.value(forKey: "newNotifSoundPersonal") ?? "001:Nexilis Message (Default)"
  3774. if message.getBody(key: CoreMessage_TMessageKey.MESSAGE_SCOPE_ID) == MessageScope.GROUP {
  3775. soundId = SecureUserDefaults.shared.value(forKey: "newNotifSoundGroup") ?? "001:Nexilis Message (Default)"
  3776. }
  3777. do {
  3778. var nameSound = soundId.components(separatedBy: ":")[1].replacingOccurrences(of: " ", with: "_")
  3779. var fromPref = false
  3780. if nameSound.contains("_(Default)") {
  3781. if !Utils.getDefaultIncomingMsg().isEmpty {
  3782. nameSound = Utils.getDefaultIncomingMsg()
  3783. fromPref = true
  3784. } else {
  3785. nameSound = nameSound.replacingOccurrences(of: "_(Default)", with: "")
  3786. }
  3787. }
  3788. var soundURL: URL?
  3789. if fromPref {
  3790. let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
  3791. let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
  3792. let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
  3793. if let dirPath = paths.first {
  3794. let audioURL = URL(fileURLWithPath: dirPath).appendingPathComponent(nameSound)
  3795. if !FileManager.default.fileExists(atPath: audioURL.path) && !FileEncryption.shared.isSecureExists(filename: nameSound) {
  3796. Download().startHTTP(forKey: nameSound,downloadUrl: Utils.getURLBase() + "filepalio/ringtone/") { (name, progress) in
  3797. guard progress == 100 else {
  3798. return
  3799. }
  3800. playAudio()
  3801. }
  3802. } else {
  3803. playAudio()
  3804. }
  3805. func playAudio() {
  3806. if FileManager.default.fileExists(atPath: audioURL.path) {
  3807. do {
  3808. do {
  3809. try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
  3810. try AVAudioSession.sharedInstance().setActive(true)
  3811. } catch {
  3812. }
  3813. Nexilis.sharedAudioPlayer = try AVAudioPlayer(contentsOf: audioURL)
  3814. Nexilis.sharedAudioPlayer?.prepareToPlay()
  3815. Nexilis.sharedAudioPlayer?.play()
  3816. } catch {
  3817. }
  3818. } else if FileEncryption.shared.isSecureExists(filename: nameSound) {
  3819. do {
  3820. if let audioData = try FileEncryption.shared.readSecure(filename: nameSound) {
  3821. let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
  3822. let tempPath = cachesDirectory.appendingPathComponent(nameSound)
  3823. try audioData.write(to: tempPath)
  3824. do {
  3825. do {
  3826. try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
  3827. try AVAudioSession.sharedInstance().setActive(true)
  3828. } catch {
  3829. }
  3830. Nexilis.sharedAudioPlayer = try AVAudioPlayer(contentsOf: tempPath)
  3831. Nexilis.sharedAudioPlayer?.prepareToPlay()
  3832. Nexilis.sharedAudioPlayer?.play()
  3833. } catch {
  3834. }
  3835. }
  3836. } catch {
  3837. }
  3838. }
  3839. }
  3840. }
  3841. } else {
  3842. soundURL = Bundle.resourceBundle(for: Nexilis.self).url(forResource: nameSound, withExtension: "mp3")
  3843. if soundURL == nil {
  3844. soundURL = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: nameSound, withExtension: "mp3")
  3845. }
  3846. do {
  3847. do {
  3848. try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
  3849. try AVAudioSession.sharedInstance().setActive(true)
  3850. } catch {
  3851. }
  3852. Nexilis.sharedAudioPlayer = try AVAudioPlayer(contentsOf: soundURL!)
  3853. Nexilis.sharedAudioPlayer?.prepareToPlay()
  3854. Nexilis.sharedAudioPlayer?.play()
  3855. } catch {
  3856. }
  3857. }
  3858. } catch {
  3859. }
  3860. DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
  3861. self.floating = nil
  3862. })
  3863. // if !onGoingCC.isEmpty {
  3864. // floating.autoDismiss = false
  3865. // }
  3866. floating.onTap = {
  3867. self.floating = nil
  3868. showNotif()
  3869. }
  3870. }
  3871. func showNotif() {
  3872. if UIApplication.shared.visibleViewController is UINavigationController {
  3873. let nc = UIApplication.shared.visibleViewController as! UINavigationController
  3874. if nc.visibleViewController is QmeraStreamingViewController {
  3875. return
  3876. } else if nc.visibleViewController is SeminarViewController {
  3877. return
  3878. }
  3879. if let navigationC = UIApplication.shared.visibleViewController as? UINavigationController {
  3880. if navigationC.viewControllers[navigationC.viewControllers.count - 1] is EditorPersonal || navigationC.viewControllers[navigationC.viewControllers.count - 1] is EditorGroup {
  3881. navigationC.popViewController(animated: true)
  3882. }
  3883. }
  3884. } else if UIApplication.shared.visibleViewController is UIAlertController {
  3885. return
  3886. }
  3887. if message.getBody(key: attachmentFlag) == "59" {
  3888. let date = Date(milliseconds: Int64(message.getBody(key: CoreMessage_TMessageKey.LOCAL_TIMESTAMP))!)
  3889. let formatter = DateFormatter()
  3890. formatter.dateFormat = "HH:mm"
  3891. formatter.locale = NSLocale(localeIdentifier: "id") as Locale?
  3892. var timeSignIn = formatter.string(from: date as Date)
  3893. let dialog = DialogSignIn()
  3894. dialog.valueDevice = message.getBody(key: CoreMessage_TMessageKey.DEVICE_BRAND)
  3895. dialog.valueTime = timeSignIn
  3896. dialog.valueLocation = message.getBody(key: CoreMessage_TMessageKey.PLACE_NAME)
  3897. dialog.valueToken = message.getBody(key: CoreMessage_TMessageKey.TOKEN)
  3898. dialog.valueUser = message.getBody(key: CoreMessage_TMessageKey.USER_ID)
  3899. dialog.modalTransitionStyle = .crossDissolve
  3900. dialog.modalPresentationStyle = .overCurrentContext
  3901. UIApplication.shared.visibleViewController?.present(dialog, animated: true)
  3902. return
  3903. }
  3904. if !onGoingCC.isEmpty {
  3905. floating.dismiss()
  3906. }
  3907. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  3908. do {
  3909. if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: "SELECT first_name, last_name FROM BUDDY where f_pin = '\(User.getMyPin()!)'"), cursorData.next() {
  3910. if (cursorData.string(forColumnIndex: 0)! + " " + cursorData.string(forColumnIndex: 1)!).trimmingCharacters(in: .whitespaces) == "USR\(User.getMyPin()!)" {
  3911. let alert = LibAlertController(title: "Set Profile".localized(), message: "You must set your profile to use this feature".localized(), preferredStyle: .alert)
  3912. alert.addAction(UIAlertAction(title: "OK".localized(), style: UIAlertAction.Style.default, handler: {(_) in
  3913. let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "signupsignin") as! SignUpSignIn
  3914. controller.forceLogin = true
  3915. let navigationController = CustomNavigationController(rootViewController: controller)
  3916. navigationController.modalPresentationStyle = .fullScreen
  3917. navigationController.navigationBar.tintColor = .white
  3918. navigationController.navigationBar.barTintColor = UIApplication.shared.visibleViewController?.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  3919. navigationController.navigationBar.isTranslucent = false
  3920. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  3921. navigationController.navigationBar.barStyle = .black
  3922. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  3923. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  3924. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  3925. navigationController.navigationBar.titleTextAttributes = textAttributes
  3926. if UIApplication.shared.visibleViewController?.navigationController != nil {
  3927. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  3928. } else {
  3929. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  3930. }
  3931. }))
  3932. if UIApplication.shared.visibleViewController?.navigationController != nil {
  3933. UIApplication.shared.visibleViewController?.navigationController?.present(alert, animated: true, completion: nil)
  3934. } else {
  3935. UIApplication.shared.visibleViewController?.present(alert, animated: true, completion: nil)
  3936. }
  3937. }
  3938. cursorData.close()
  3939. return
  3940. }
  3941. } catch {
  3942. rollback.pointee = true
  3943. print("Access database error: \(error.localizedDescription)")
  3944. }
  3945. })
  3946. if message.getBody(key: messageScopeId) == MessageScope.WHISPER || message.getBody(key: messageScopeId) == MessageScope.FORM || message.getBody(key: messageScopeId) == MessageScope.CHATROOM {
  3947. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  3948. editorPersonalVC.hidesBottomBarWhenPushed = true
  3949. editorPersonalVC.unique_l_pin = threadIdentifier
  3950. editorPersonalVC.fromNotification = true
  3951. if !onGoingCC.isEmpty {
  3952. let compalintId = onGoingCC.components(separatedBy: ",")[2]
  3953. let fPinCC = onGoingCC.isEmpty ? "" : onGoingCC.components(separatedBy: ",")[1]
  3954. editorPersonalVC.isContactCenter = true
  3955. editorPersonalVC.fPinContacCenter = fPinCC
  3956. editorPersonalVC.complaintId = compalintId
  3957. editorPersonalVC.onGoingCC = true
  3958. editorPersonalVC.isRequestContactCenter = false
  3959. }
  3960. let navigationController = CustomNavigationController(rootViewController: editorPersonalVC)
  3961. navigationController.modalPresentationStyle = .fullScreen
  3962. navigationController.navigationBar.tintColor = .white
  3963. navigationController.navigationBar.barTintColor = UIApplication.shared.visibleViewController?.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  3964. navigationController.navigationBar.isTranslucent = false
  3965. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  3966. navigationController.navigationBar.barStyle = .black
  3967. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  3968. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  3969. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  3970. navigationController.navigationBar.titleTextAttributes = textAttributes
  3971. if UIApplication.shared.visibleViewController is UINavigationController && Nexilis.fromMAB {
  3972. editorPersonalVC.fromNotification = false
  3973. UIApplication.shared.visibleViewController?.show(editorPersonalVC, sender: nil)
  3974. } else {
  3975. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  3976. }
  3977. } else {
  3978. let editorGroupVC = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "editorGroupVC") as! EditorGroup
  3979. editorGroupVC.hidesBottomBarWhenPushed = true
  3980. editorGroupVC.unique_l_pin = threadIdentifier
  3981. editorGroupVC.fromNotification = true
  3982. let navigationController = CustomNavigationController(rootViewController: editorGroupVC)
  3983. navigationController.modalPresentationStyle = .fullScreen
  3984. navigationController.navigationBar.tintColor = .white
  3985. navigationController.navigationBar.barTintColor = UIApplication.shared.visibleViewController?.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  3986. navigationController.navigationBar.isTranslucent = false
  3987. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  3988. navigationController.navigationBar.barStyle = .black
  3989. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  3990. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  3991. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  3992. navigationController.navigationBar.titleTextAttributes = textAttributes
  3993. if UIApplication.shared.visibleViewController is UINavigationController && Nexilis.fromMAB {
  3994. editorGroupVC.fromNotification = false
  3995. UIApplication.shared.visibleViewController?.show(editorGroupVC, sender: nil)
  3996. } else {
  3997. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  3998. }
  3999. }
  4000. }
  4001. }
  4002. }
  4003. }
  4004. }
  4005. public static func addFriend(fpin: String, completion: @escaping (Bool) -> ()) {
  4006. DispatchQueue.global().async {
  4007. if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getAddFriendQRCode(fpin: fpin)), response.isOk() {
  4008. completion(true)
  4009. } else {
  4010. completion(false)
  4011. }
  4012. }
  4013. }
  4014. public static func addFriendSilent(fpin: String) {
  4015. DispatchQueue.global().async {
  4016. _ = Nexilis.write(message: CoreMessage_TMessageBank.getAddFriendQRCodeSilent(fpin: fpin))
  4017. }
  4018. }
  4019. public func onReceive(message: [AnyHashable : Any?]) {
  4020. var dataMessage: [AnyHashable : Any] = [:]
  4021. dataMessage["message"] = message
  4022. NotificationCenter.default.post(name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil, userInfo: dataMessage)
  4023. }
  4024. public func onMessage(message: TMessage) {
  4025. var dataMessage: [AnyHashable : Any] = [:]
  4026. dataMessage["message"] = message
  4027. NotificationCenter.default.post(name: NSNotification.Name(rawValue: Nexilis.listenerStatusChat), object: nil, userInfo: dataMessage)
  4028. }
  4029. public func onUpload(name: String, progress: Double) {
  4030. var dataMessage: [AnyHashable : Any] = [:]
  4031. dataMessage["name"] = name
  4032. dataMessage["progress"] = progress
  4033. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onUploadChat"), object: nil, userInfo: dataMessage)
  4034. }
  4035. public func onTyping(message: TMessage) {
  4036. var dataMessage: [AnyHashable : Any] = [:]
  4037. dataMessage["message"] = message
  4038. NotificationCenter.default.post(name: NSNotification.Name(rawValue: Nexilis.listenerTypingChat), object: nil, userInfo: dataMessage)
  4039. }
  4040. // public static func faceDetect(fd: FaceDetector?,image: UIImage, completion: ((Bool) -> ())?){
  4041. // //print("enter vision")
  4042. // let visionImage = VisionImage(image: image)
  4043. // //print("exit vision")
  4044. // var retval = false
  4045. // visionImage.orientation = image.imageOrientation
  4046. // var fd1 : FaceDetector?
  4047. // if(fd == nil){
  4048. // fd1 = FaceDetector.faceDetector()
  4049. // }
  4050. // else {
  4051. // fd1 = fd
  4052. // }
  4053. //
  4054. // // [START detect_faces]
  4055. // fd1?.process(visionImage) {faces, error in
  4056. // guard error == nil, let faces = faces, !faces.isEmpty else {
  4057. // //print("faces empty")
  4058. // completion?(false)
  4059. // return
  4060. // }
  4061. // if(faces.count > 0){
  4062. // //print("face count: \(faces.count)")
  4063. // retval = true
  4064. // }
  4065. // completion?(retval)
  4066. // }
  4067. //
  4068. // }
  4069. }
  4070. extension Nexilis: GroupDelegate {
  4071. public func onGroup(code: String, f_pin: String, groupId: String) {
  4072. var data: [AnyHashable : Any] = [:]
  4073. data["code"] = code
  4074. data["f_pin"] = f_pin
  4075. data["groupId"] = groupId
  4076. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onGroup"), object: nil, userInfo: data)
  4077. }
  4078. public func onTopic(code: String, f_pin: String, topicId: String) {
  4079. var data: [AnyHashable : Any] = [:]
  4080. data["code"] = code
  4081. data["f_pin"] = f_pin
  4082. data["topicId"] = topicId
  4083. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onTopic"), object: nil, userInfo: data)
  4084. }
  4085. public func onMember(code: String, f_pin: String, groupId: String, member: String) {
  4086. var data: [AnyHashable : Any] = [:]
  4087. data["code"] = code
  4088. data["f_pin"] = f_pin
  4089. data["groupId"] = groupId
  4090. data["member"] = member
  4091. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onMember"), object: nil, userInfo: data)
  4092. }
  4093. }
  4094. extension Nexilis: PersonInfoDelegate {
  4095. public func onUpdatePersonInfo(state: Int, message: String) {
  4096. var data: [AnyHashable : Any] = [:]
  4097. data["state"] = state
  4098. data["message"] = message
  4099. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onUpdatePersonInfo"), object: nil, userInfo: data)
  4100. }
  4101. }
  4102. extension Nexilis: QLPreviewControllerDataSource {
  4103. public func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
  4104. return 1
  4105. }
  4106. public func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
  4107. return previewItem!
  4108. }
  4109. }
  4110. public class SelfSignedURLSessionDelegate: NSObject, URLSessionTaskDelegate, URLSessionDataDelegate {
  4111. public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
  4112. if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
  4113. if let serverTrust = challenge.protectionSpace.serverTrust {
  4114. let credential = URLCredential(trust: serverTrust)
  4115. completionHandler(.useCredential, credential)
  4116. }
  4117. }
  4118. }
  4119. }