Nexilis.swift 260 KB

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