Nexilis.swift 257 KB

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