APIS.swift 176 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150
  1. //
  2. // APIS.swift
  3. // NexilisLite
  4. //
  5. // Created by Akhmad Al Qindi Irsyam on 05/05/23.
  6. //
  7. import Foundation
  8. import UIKit
  9. import FMDB
  10. import NotificationBannerSwift
  11. import Toast_Swift
  12. import nuSDKService
  13. import AVFoundation
  14. import AVKit
  15. import Intents
  16. public class APIS: NSObject {
  17. private static var isAlertPresented = false
  18. private static var transitioningDelegateRef: ZoomTransitioningDelegate?
  19. public static func connect(appName: String, apiKey: String, userName: String = "", delegate: ConnectDelegate, showButton: Bool = true, fromMAB: Bool = false) {
  20. APIS.appNm = appName.trimmingCharacters(in: .whitespacesAndNewlines)
  21. Nexilis.connect(apiKey: apiKey, userId: userName, delegate: delegate, showButton: showButton, fromMAB: fromMAB)
  22. }
  23. public static func getTotalCounter() -> Int32 {
  24. var counter: Int32?
  25. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  26. do {
  27. let query = """
  28. select SUM(counter) as total_counter
  29. from (
  30. select ms.counter from MESSAGE_SUMMARY ms, MESSAGE m, BUDDY b
  31. where ms.l_pin = b.f_pin and ms.message_id = m.message_id and m.is_call_center = 0
  32. union all
  33. select ms.counter from MESSAGE_SUMMARY ms, MESSAGE m
  34. where ms.l_pin = '-999' and ms.message_id = m.message_id
  35. union all
  36. select ms.counter from MESSAGE_SUMMARY ms, MESSAGE m
  37. where ms.l_pin = '-997' and ms.message_id = m.message_id
  38. union all
  39. select ms.counter from MESSAGE_SUMMARY ms, MESSAGE m, GROUPZ b
  40. where ms.l_pin = b.group_id and ms.message_id = m.message_id and m.is_call_center = 0
  41. union all
  42. select ms.counter from MESSAGE_SUMMARY ms, MESSAGE m, DISCUSSION_FORUM b, GROUPZ c
  43. where b.group_id = c.group_id and ms.l_pin = b.chat_id and ms.message_id = m.message_id and m.is_call_center = 0
  44. ) as subquery
  45. """
  46. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: query), cursor.next() {
  47. counter = cursor.int(forColumnIndex: 0)
  48. cursor.close()
  49. }
  50. } catch {
  51. rollback.pointee = true
  52. print("Access database error: \(error.localizedDescription)")
  53. }
  54. })
  55. return counter ?? 0
  56. }
  57. private static func showChangeProfile() {
  58. guard !isAlertPresented else { return }
  59. isAlertPresented = true
  60. let alert = LibAlertController(title: "Set Profile".localized(), message: "You must set your profile to use this feature".localized(), preferredStyle: .alert)
  61. alert.addAction(UIAlertAction(title: "OK".localized(), style: UIAlertAction.Style.default, handler: {(_) in
  62. isAlertPresented = false
  63. guard let controller = APIS.getControllerSign() else { return }
  64. if let controller = controller as? SignUpSignIn {
  65. controller.forceLogin = true
  66. } else if let controller = controller as? SignInOption {
  67. controller.forceLogin = true
  68. }
  69. let navigationController = CustomNavigationController(rootViewController: controller)
  70. navigationController.defaultStyle()
  71. if UIApplication.shared.visibleViewController?.navigationController != nil {
  72. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  73. } else {
  74. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  75. }
  76. }))
  77. if UIApplication.shared.visibleViewController?.navigationController != nil {
  78. UIApplication.shared.visibleViewController?.navigationController?.present(alert, animated: true, completion: nil)
  79. } else {
  80. UIApplication.shared.visibleViewController?.present(alert, animated: true, completion: nil)
  81. }
  82. }
  83. public static func openContactCenter(media: Int? = nil, category: Int? = nil) {
  84. let isChangeProfile = Utils.getSetProfile()
  85. if !isChangeProfile {
  86. APIS.showChangeProfile()
  87. return
  88. }
  89. if !Nexilis.checkingAccess(key: "call_center") {
  90. if Nexilis.checkingAccessAlert(key: "call_center") != "|" && !Nexilis.checkingAccessAlert(key: "call_center").isEmpty {
  91. let title = Nexilis.checkingAccessAlert(key: "call_center").components(separatedBy: "|")[0]
  92. let message = Nexilis.checkingAccessAlert(key: "call_center").components(separatedBy: "|")[1]
  93. APIS.nexilisShowAlertWithHTMLMessage(on: UIApplication.shared.visibleViewController ?? UIViewController(), title: title, message: message)
  94. } else {
  95. UIApplication.shared.visibleViewController?.view.makeToast("Feature disabled".localized(), duration: 5)
  96. }
  97. return
  98. }
  99. if User.isCallCenter(userType: (User.getData(pin: User.getMyPin())?.userType)!) {
  100. let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "myHistoryCC") as! HistoryCCViewController
  101. controller.isOfficer = true
  102. controller.fromAPI = true
  103. let navigationController = CustomNavigationController(rootViewController: controller)
  104. navigationController.setNavigationBarHidden(false, animated: false)
  105. navigationController.navigationBar.isTranslucent = false
  106. navigationController.defaultStyle()
  107. if UIApplication.shared.visibleViewController?.navigationController != nil {
  108. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  109. } else {
  110. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  111. }
  112. } else {
  113. if media != nil || (media == nil && category != nil) {
  114. if media == nil || media! < 0 || media! > 2 {
  115. UIApplication.shared.visibleViewController?.view.makeToast("108:Invalid Contact Center media parameter (0:Chat, 1:Audio Call, 2:Video Call)".localized(), duration: 3)
  116. return
  117. }
  118. }
  119. if category != nil {
  120. if category != 0 {
  121. let service = CategoryCC.getDataFromServiceId(service_id: "\(category!)")
  122. if service == nil {
  123. UIApplication.shared.visibleViewController?.view.makeToast("109:Invalid Contact Center category parameter".localized(), duration: 3)
  124. return
  125. }
  126. let serviceChilds = CategoryCC.getDatafromParent(parent: service!.service_id)
  127. if serviceChilds.count > 0 {
  128. UIApplication.shared.visibleViewController?.view.makeToast("109:Invalid Contact Center category parameter".localized(), duration: 3)
  129. return
  130. }
  131. }
  132. }
  133. let isWaitingRequestCC: Bool = SecureUserDefaults.shared.value(forKey: "waitingRequestCC") ?? false
  134. if isWaitingRequestCC {
  135. let imageView = UIImageView(image: UIImage(systemName: "info.circle"))
  136. imageView.tintColor = .white
  137. let banner = FloatingNotificationBanner(title: "You have requested Call Center, please wait for response.".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)
  138. banner.show()
  139. return
  140. }
  141. let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  142. controller.isContactCenter = true
  143. if media != nil {
  144. controller.isDirectCC = true
  145. controller.channelContactCenter = "\(media!)"
  146. controller.serviceIdCC = category == nil ? "" : "\(category!)"
  147. }
  148. let navigationController = CustomNavigationController(rootViewController: controller)
  149. navigationController.defaultStyle()
  150. if UIApplication.shared.visibleViewController?.navigationController != nil {
  151. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  152. } else {
  153. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  154. }
  155. }
  156. }
  157. public static func openContactCenterWithContext(context: String) {
  158. let isChangeProfile = Utils.getSetProfile()
  159. if !isChangeProfile {
  160. APIS.showChangeProfile()
  161. return
  162. }
  163. if !Nexilis.checkingAccess(key: "call_center") {
  164. if Nexilis.checkingAccessAlert(key: "call_center") != "|" && !Nexilis.checkingAccessAlert(key: "call_center").isEmpty {
  165. let title = Nexilis.checkingAccessAlert(key: "call_center").components(separatedBy: "|")[0]
  166. let message = Nexilis.checkingAccessAlert(key: "call_center").components(separatedBy: "|")[1]
  167. APIS.nexilisShowAlertWithHTMLMessage(on: UIApplication.shared.visibleViewController ?? UIViewController(), title: title, message: message)
  168. } else {
  169. UIApplication.shared.visibleViewController?.view.makeToast("Feature disabled".localized(), duration: 5)
  170. }
  171. return
  172. }
  173. let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  174. controller.isContactCenter = true
  175. controller.contextCC = context
  176. let navigationController = CustomNavigationController(rootViewController: controller)
  177. navigationController.defaultStyle()
  178. if UIApplication.shared.visibleViewController?.navigationController != nil {
  179. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  180. } else {
  181. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  182. }
  183. }
  184. public static func openUrl(url: String) {
  185. let isChangeProfile = Utils.getSetProfile()
  186. if !isChangeProfile {
  187. APIS.showChangeProfile()
  188. return
  189. }
  190. let controller = BNIBookingWebView()
  191. controller.customUrl = url
  192. let navigationController = CustomNavigationController(rootViewController: controller)
  193. navigationController.defaultStyle()
  194. if UIApplication.shared.visibleViewController?.navigationController != nil {
  195. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  196. } else {
  197. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  198. }
  199. }
  200. public static func openNotificationCenter() {
  201. let isChangeProfile = Utils.getSetProfile()
  202. if !isChangeProfile {
  203. APIS.showChangeProfile()
  204. return
  205. }
  206. if !Nexilis.checkingAccess(key: "notification_center") {
  207. UIApplication.shared.visibleViewController?.view.makeToast("Feature disabled".localized(), duration: 5)
  208. return
  209. }
  210. let controller = HistoryBroadcastViewController()
  211. let navigationController = CustomNavigationController(rootViewController: controller)
  212. navigationController.defaultStyle()
  213. if UIApplication.shared.visibleViewController?.navigationController != nil {
  214. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  215. } else {
  216. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  217. }
  218. }
  219. public static func openChat(withoutUCList: Bool = false) {
  220. let isChangeProfile = Utils.getSetProfile()
  221. if !isChangeProfile {
  222. APIS.showChangeProfile()
  223. return
  224. }
  225. let navigationController = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "contactChatNav") as! UINavigationController
  226. Utils.addBackground(view: navigationController.view)
  227. let vc = navigationController.topViewController as! ContactChatViewController
  228. vc.noUCList = withoutUCList
  229. navigationController.defaultStyle()
  230. if UIApplication.shared.visibleViewController?.navigationController != nil {
  231. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  232. } else {
  233. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  234. }
  235. }
  236. public static func openSmartChatbot() {
  237. let isChangeProfile = Utils.getSetProfile()
  238. if !isChangeProfile {
  239. APIS.showChangeProfile()
  240. return
  241. }
  242. let smartChatVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "chatGptVC") as! ChatGPTBotView
  243. smartChatVC.hidesBottomBarWhenPushed = true
  244. let navigationController = CustomNavigationController(rootViewController: smartChatVC)
  245. navigationController.defaultStyle()
  246. if UIApplication.shared.visibleViewController?.navigationController != nil {
  247. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  248. } else {
  249. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  250. }
  251. }
  252. public static func startChat(name: String) {
  253. if name.isEmpty {
  254. UIApplication.shared.visibleViewController?.view.makeToast("92:Username is empty".localized(), duration: 2)
  255. return
  256. }
  257. let user = User.getDataFromNameCanNil(name: name)
  258. if user == nil {
  259. UIApplication.shared.visibleViewController?.view.makeToast("91:Invalid name or you must add Username to your contact first".localized(), duration: 3)
  260. return
  261. }
  262. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  263. editorPersonalVC.hidesBottomBarWhenPushed = true
  264. editorPersonalVC.unique_l_pin = user!.pin
  265. editorPersonalVC.fromNotification = true
  266. let navigationController = CustomNavigationController(rootViewController: editorPersonalVC)
  267. navigationController.modalPresentationStyle = .fullScreen
  268. navigationController.navigationBar.tintColor = .white
  269. navigationController.navigationBar.barTintColor = UIApplication.shared.visibleViewController?.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  270. navigationController.navigationBar.isTranslucent = false
  271. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  272. navigationController.navigationBar.barStyle = .black
  273. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  274. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  275. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  276. navigationController.navigationBar.titleTextAttributes = textAttributes
  277. if UIApplication.shared.visibleViewController?.navigationController != nil {
  278. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  279. } else {
  280. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  281. }
  282. }
  283. public static func openCall() {
  284. let isChangeProfile = Utils.getSetProfile()
  285. if !isChangeProfile {
  286. APIS.showChangeProfile()
  287. return
  288. }
  289. let callContact = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "contactSID")
  290. let navigationController = CustomNavigationController(rootViewController: callContact)
  291. navigationController.defaultStyle()
  292. if UIApplication.shared.visibleViewController?.navigationController != nil {
  293. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  294. } else {
  295. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  296. }
  297. }
  298. public static func openStreaming() {
  299. let isChangeProfile = Utils.getSetProfile()
  300. if !isChangeProfile {
  301. APIS.showChangeProfile()
  302. return
  303. }
  304. if !Nexilis.checkingAccess(key: "live_streaming") {
  305. if Nexilis.checkingAccessAlert(key: "live_streaming") != "|" && !Nexilis.checkingAccessAlert(key: "live_streaming").isEmpty {
  306. let title = Nexilis.checkingAccessAlert(key: "live_streaming").components(separatedBy: "|")[0]
  307. let message = Nexilis.checkingAccessAlert(key: "live_streaming").components(separatedBy: "|")[1]
  308. APIS.nexilisShowAlertWithHTMLMessage(on: UIApplication.shared.visibleViewController ?? UIViewController(), title: title, message: message)
  309. } else {
  310. UIApplication.shared.visibleViewController?.view.makeToast("Feature disabled".localized(), duration: 5)
  311. }
  312. return
  313. }
  314. let navigationController = CustomNavigationController(rootViewController: QmeraCreateStreamingViewController())
  315. navigationController.defaultStyle()
  316. if UIApplication.shared.visibleViewController?.navigationController != nil {
  317. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  318. } else {
  319. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  320. }
  321. }
  322. public static func openConference() {
  323. let isChangeProfile = Utils.getSetProfile()
  324. if !isChangeProfile {
  325. APIS.showChangeProfile()
  326. return
  327. }
  328. if !Nexilis.checkingAccess(key: "vconf_room") {
  329. if Nexilis.checkingAccessAlert(key: "vconf_room") != "|" && !Nexilis.checkingAccessAlert(key: "vconf_room").isEmpty {
  330. let title = Nexilis.checkingAccessAlert(key: "vconf_room").components(separatedBy: "|")[0]
  331. let message = Nexilis.checkingAccessAlert(key: "vconf_room").components(separatedBy: "|")[1]
  332. APIS.nexilisShowAlertWithHTMLMessage(on: UIApplication.shared.visibleViewController ?? UIViewController(), title: title, message: message)
  333. } else {
  334. UIApplication.shared.visibleViewController?.view.makeToast("Feature disabled".localized(), duration: 5)
  335. }
  336. return
  337. }
  338. let navigationController = CustomNavigationController(rootViewController: CreateSeminarViewController())
  339. navigationController.defaultStyle()
  340. if UIApplication.shared.visibleViewController?.navigationController != nil {
  341. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  342. } else {
  343. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  344. }
  345. }
  346. public static func openAudioCall() {
  347. let isChangeProfile = Utils.getSetProfile()
  348. if !isChangeProfile {
  349. APIS.showChangeProfile()
  350. return
  351. }
  352. if !Nexilis.checkingAccess(key: "audio_call") {
  353. UIApplication.shared.visibleViewController?.view.makeToast("Feature disabled".localized(), duration: 5)
  354. return
  355. }
  356. let callContact = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "contactSID") as! ContactCallViewController
  357. callContact.onlyAudioOrVideo = 1
  358. let navigationController = CustomNavigationController(rootViewController: callContact)
  359. navigationController.defaultStyle()
  360. if UIApplication.shared.visibleViewController?.navigationController != nil {
  361. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  362. } else {
  363. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  364. }
  365. }
  366. public static func startAudioCall(name: String) {
  367. if name.isEmpty {
  368. UIApplication.shared.visibleViewController?.view.makeToast("92:Username is empty".localized(), duration: 3)
  369. return
  370. }
  371. if !Nexilis.checkingAccess(key: "audio_call") {
  372. UIApplication.shared.visibleViewController?.view.makeToast("Feature disabled".localized(), duration: 5)
  373. return
  374. }
  375. let user = User.getDataFromNameCanNil(name: name)
  376. if user == nil {
  377. UIApplication.shared.visibleViewController?.view.makeToast("91:Invalid name or you must add Username to your contact first".localized(), duration: 3)
  378. return
  379. }
  380. if !CheckConnection.isConnectedToNetwork() {
  381. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  382. imageView.tintColor = .white
  383. let banner = FloatingNotificationBanner(title: "Check your connection".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
  384. banner.show()
  385. return
  386. }
  387. let controller = QmeraAudioViewController()
  388. controller.user = user
  389. controller.isOutgoing = true
  390. controller.modalPresentationStyle = .overFullScreen
  391. if UIApplication.shared.visibleViewController?.navigationController != nil {
  392. UIApplication.shared.visibleViewController?.navigationController?.present(controller, animated: true, completion: nil)
  393. } else {
  394. UIApplication.shared.visibleViewController?.present(controller, animated: true, completion: nil)
  395. }
  396. }
  397. public static func openVideoCall() {
  398. let isChangeProfile = Utils.getSetProfile()
  399. if !isChangeProfile {
  400. APIS.showChangeProfile()
  401. return
  402. }
  403. if !Nexilis.checkingAccess(key: "video_call") {
  404. UIApplication.shared.visibleViewController?.view.makeToast("Feature disabled".localized(), duration: 5)
  405. return
  406. }
  407. let callContact = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "contactSID") as! ContactCallViewController
  408. callContact.onlyAudioOrVideo = 2
  409. let navigationController = CustomNavigationController(rootViewController: callContact)
  410. navigationController.defaultStyle()
  411. if UIApplication.shared.visibleViewController?.navigationController != nil {
  412. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  413. } else {
  414. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  415. }
  416. }
  417. public static func startVideoCall(name: String) {
  418. if name.isEmpty {
  419. UIApplication.shared.visibleViewController?.view.makeToast("92:Username is empty".localized(), duration: 3)
  420. return
  421. }
  422. if !Nexilis.checkingAccess(key: "video_call") {
  423. UIApplication.shared.visibleViewController?.view.makeToast("Feature disabled".localized(), duration: 5)
  424. return
  425. }
  426. let user = User.getDataFromNameCanNil(name: name)
  427. if user == nil {
  428. UIApplication.shared.visibleViewController?.view.makeToast("91:Invalid name or you must add Username to your contact first".localized(), duration: 3)
  429. return
  430. }
  431. if !CheckConnection.isConnectedToNetwork() {
  432. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  433. imageView.tintColor = .white
  434. let banner = FloatingNotificationBanner(title: "Check your connection".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
  435. banner.show()
  436. return
  437. }
  438. let videoVC = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "videoVCQmera") as! QmeraVideoViewController
  439. var data: [String: String?] = [:]
  440. data["f_pin"] = user!.pin
  441. data["name"] = user!.fullName
  442. data["picture"] = user!.thumb
  443. data["isOfficial"] = user!.official
  444. data["deviceId"] = user!.device_id
  445. data["isOffline"] = user!.offline_mode
  446. data["user_type"] = user!.userType
  447. videoVC.dataPerson.append(data)
  448. videoVC.isPresent = true
  449. videoVC.modalPresentationStyle = .overFullScreen
  450. if UIApplication.shared.visibleViewController?.navigationController != nil {
  451. UIApplication.shared.visibleViewController?.navigationController?.present(videoVC, animated: true, completion: nil)
  452. } else {
  453. UIApplication.shared.visibleViewController?.present(videoVC, animated: true, completion: nil)
  454. }
  455. }
  456. public static func openBroadcastForm() {
  457. let isChangeProfile = Utils.getSetProfile()
  458. if !isChangeProfile {
  459. APIS.showChangeProfile()
  460. return
  461. }
  462. if !Nexilis.checkingAccess(key: "broadcast_message") {
  463. UIApplication.shared.visibleViewController?.view.makeToast("Feature disabled".localized(), duration: 5)
  464. return
  465. }
  466. let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "broadcastNav")
  467. if UIApplication.shared.visibleViewController?.navigationController != nil {
  468. UIApplication.shared.visibleViewController?.navigationController?.present(controller, animated: true, completion: nil)
  469. } else {
  470. UIApplication.shared.visibleViewController?.present(controller, animated: true, completion: nil)
  471. }
  472. }
  473. public static func openConversation() {
  474. let isChangeProfile = Utils.getSetProfile()
  475. if !isChangeProfile {
  476. APIS.showChangeProfile()
  477. return
  478. }
  479. let navigationController = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "contactChatNav") as! UINavigationController
  480. Utils.addBackground(view: navigationController.view)
  481. navigationController.defaultStyle()
  482. if UIApplication.shared.visibleViewController?.navigationController != nil {
  483. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  484. } else {
  485. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  486. }
  487. }
  488. public static func openFavoriteMessage() {
  489. let isChangeProfile = Utils.getSetProfile()
  490. if !isChangeProfile {
  491. APIS.showChangeProfile()
  492. return
  493. }
  494. let editorStaredVC = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "staredVC") as! EditorStarMessages
  495. editorStaredVC.fromNotification = true
  496. let navigationController = CustomNavigationController(rootViewController: editorStaredVC)
  497. navigationController.defaultStyle()
  498. if UIApplication.shared.visibleViewController?.navigationController != nil {
  499. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  500. } else {
  501. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  502. }
  503. }
  504. public static func openSecureFolder() {
  505. let isChangeProfile = Utils.getSetProfile()
  506. if !isChangeProfile {
  507. APIS.showChangeProfile()
  508. return
  509. }
  510. let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "secureFolderView") as! SecureFolderViewController
  511. let navigationController = CustomNavigationController(rootViewController: controller)
  512. navigationController.defaultStyle()
  513. if UIApplication.shared.visibleViewController?.navigationController != nil {
  514. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  515. } else {
  516. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  517. }
  518. }
  519. /*
  520. 0
  521. Success
  522. 1
  523. Invalid PIN/Password
  524. 2
  525. Auth Failure
  526. 3
  527. Device Key Signature Mismatch
  528. 4
  529. Policy Level Not Met
  530. 5
  531. PPKey Generated Failed
  532. 6
  533. Challenge-Response Failed
  534. 7
  535. TOTOP Mismatch
  536. 9
  537. Server Error Code
  538. 10
  539. Invalid Face ID or Face ID mismatch
  540. 11
  541. Invalid Fingerprint
  542. 12
  543. Invalid SIM Card does not match the one registered in our system
  544. 13
  545. Unable to access servers. Check your internet connection and try again later
  546. 99
  547. Back / Cancel
  548. */
  549. private static var mfaCallback: ((Int) -> Void)?
  550. private static var methodSetted = ""
  551. public static func setTxnAuthActivity(activity: String) {
  552. methodSetted = activity
  553. }
  554. static func getMFACallback() -> ((Int) -> Void)? {
  555. return mfaCallback
  556. }
  557. static func setMFACallback(mfaCallback: @escaping (Int) -> Void) {
  558. self.mfaCallback = mfaCallback
  559. }
  560. public static func signUp(userId: String, mfaCallback: @escaping (Int) -> Void) {
  561. self.mfaCallback = mfaCallback
  562. let method = "Sign Up"
  563. let policyLevel = Utils.getSignUpLevel()
  564. // print("signUp: \(policyLevel)")
  565. signUpSignInMFA(method: method, userId: userId, policyLevel: policyLevel)
  566. }
  567. public static func signIn(userId: String, mfaCallback: @escaping (Int) -> Void) {
  568. self.mfaCallback = mfaCallback
  569. let method = "Sign In"
  570. let policyLevel = Utils.getSignInLevel()
  571. // print("signIn: \(policyLevel)")
  572. signUpSignInMFA(method: method, userId: userId, policyLevel: policyLevel)
  573. }
  574. public static func txnAuth(userId: String, txnId: String, amount: Double, mfaCallback: @escaping (Int) -> Void) {
  575. self.mfaCallback = mfaCallback
  576. var method = "Transaction"
  577. if !methodSetted.isEmpty {
  578. method = methodSetted
  579. }
  580. var dataTxn = Utils.getTxnLevel()
  581. dataTxn = dataTxn.replacingOccurrences(of: "\\\"", with: "\"")
  582. .replacingOccurrences(of: "\"[", with: "[")
  583. .replacingOccurrences(of: "]\"", with: "]")
  584. var policyLevel = "1,2"
  585. // print("txnAuth: \(dataTxn)")
  586. if !dataTxn.isEmpty {
  587. if let data = dataTxn.data(using: .utf8) {
  588. do {
  589. // Parse to generic JSON array
  590. if let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
  591. for json in jsonArray {
  592. let min = json["min"] as? Double ?? 0
  593. let max = json["max"] as? Double ?? 0
  594. let policy = json["policy"] as? String ?? ""
  595. if max == -1 {
  596. if amount >= min {
  597. policyLevel = policy
  598. break
  599. }
  600. } else {
  601. if amount >= min && amount <= max {
  602. policyLevel = policy
  603. break
  604. }
  605. }
  606. }
  607. openMFA(method: method, flag: policyLevel)
  608. }
  609. } catch {
  610. print("Error converting string to JSONArray:", error)
  611. }
  612. }
  613. }
  614. }
  615. private static func signUpSignInMFA(method: String, userId: String, policyLevel: String) {
  616. Nexilis.showLoader()
  617. DispatchQueue.global().async {
  618. var id = ""
  619. if Utils.isMiddleMode() || Utils.isHSAMode() {
  620. id = Nexilis.justInit()
  621. } else {
  622. id = User.getMyPin() ?? ""
  623. }
  624. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getSignUpSignInAPI(p_name: userId, p_password: "", xPin: id), timeout: 15 * 1000) {
  625. if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "20" {
  626. DispatchQueue.main.async {
  627. Nexilis.hideLoader {
  628. let errMessage = "Invalid user / Username and password does not match".localized()
  629. UIApplication.shared.visibleViewController?.view.makeToast(errMessage, duration: 3)
  630. APIS.getMFACallback()?(2)
  631. }
  632. }
  633. } else if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "11" {
  634. DispatchQueue.main.async {
  635. Nexilis.hideLoader {
  636. let errMessage = "Failed, unknown user".localized()
  637. UIApplication.shared.visibleViewController?.view.makeToast(errMessage, duration: 3)
  638. APIS.getMFACallback()?(2)
  639. }
  640. }
  641. } else if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "4u" {
  642. DispatchQueue.main.async {
  643. Nexilis.hideLoader {
  644. let errMessage = "Failed, blocked user".localized()
  645. UIApplication.shared.visibleViewController?.view.makeToast(errMessage, duration: 3)
  646. APIS.getMFACallback()?(2)
  647. }
  648. }
  649. } else if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "13" {
  650. DispatchQueue.main.async {
  651. Nexilis.hideLoader {
  652. let errMessage = "Failed, This user is not registered on this device".localized()
  653. UIApplication.shared.visibleViewController?.view.makeToast(errMessage, duration: 3)
  654. APIS.getMFACallback()?(2)
  655. }
  656. }
  657. } else if !response.isOk() {
  658. DispatchQueue.main.async {
  659. Nexilis.hideLoader {
  660. let errMessage = "Failed".localized()
  661. UIApplication.shared.visibleViewController?.view.makeToast(errMessage, duration: 3)
  662. APIS.getMFACallback()?(2)
  663. }
  664. }
  665. } else {
  666. if Database.shared.openDatabase() == 0 {
  667. APIS.showRestartApp()
  668. KeyManagerNexilis.deleteKey()
  669. KeyManagerNexilis.deleteMarker()
  670. return
  671. }
  672. let sign = response.getBody(key: CoreMessage_TMessageKey.SIGN, default_value: "")
  673. if sign == "1" {
  674. let id = response.getBody(key: CoreMessage_TMessageKey.F_PIN, default_value: "")
  675. let f_pin = response.getBody(key: CoreMessage_TMessageKey.F_PIN_REAL, default_value: "")
  676. let device_id = response.getBody(key: CoreMessage_TMessageKey.IMEI, default_value: id)
  677. let last_sign = response.getBody(key: CoreMessage_TMessageKey.LAST_SIGN, default_value: "0")
  678. if last_sign != "0" {
  679. Utils.setLoginMultipleFPin(value: f_pin)
  680. DispatchQueue.main.async {
  681. let errMessage = "Multiple Login Detected...".localized()
  682. UIApplication.shared.visibleViewController?.view.makeToast(errMessage, duration: 3)
  683. if Nexilis.showFB {
  684. Nexilis.floatingButton.removeFromSuperview()
  685. FloatingButton.datePull = nil
  686. Nexilis.floatingButton = FloatingButton()
  687. Nexilis.addFB()
  688. }
  689. DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
  690. let dialog = DialogUnableAccess()
  691. dialog.modalTransitionStyle = .crossDissolve
  692. dialog.modalPresentationStyle = .overCurrentContext
  693. UIApplication.shared.visibleViewController?.present(dialog, animated: true)
  694. })
  695. }
  696. return
  697. }
  698. DispatchQueue.main.async {
  699. UIApplication.shared.visibleViewController?.deleteAllRecordDatabase()
  700. }
  701. if(!id.isEmpty) {
  702. SecureUserDefaults.shared.set(device_id, forKey: "device_id")
  703. Utils.setProfile(value: true)
  704. // pos registration
  705. _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: id))
  706. DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
  707. Nexilis.hideLoader(completion: {
  708. if Nexilis.showFB {
  709. Nexilis.floatingButton.removeFromSuperview()
  710. FloatingButton.datePull = nil
  711. Nexilis.floatingButton = FloatingButton()
  712. Nexilis.addFB()
  713. }
  714. Nexilis.getFeatureAccess()
  715. openMFA(method: method, flag: policyLevel)
  716. })
  717. })
  718. }
  719. } else {
  720. let idMe = User.getMyPin()!
  721. _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: idMe))
  722. Utils.setProfile(value: true)
  723. DispatchQueue.main.async {
  724. Nexilis.hideLoader(completion: {
  725. openMFA(method: method, flag: policyLevel)
  726. })
  727. }
  728. }
  729. }
  730. } else {
  731. DispatchQueue.main.async {
  732. Nexilis.hideLoader {
  733. let errMessage = "Unable to access servers. Check your internet connection and try again later".localized()
  734. UIApplication.shared.visibleViewController?.view.makeToast(errMessage, duration: 3)
  735. APIS.getMFACallback()?(13)
  736. }
  737. }
  738. }
  739. }
  740. }
  741. private static func openMFA(method: String, flag: String) {
  742. let isChangeProfile = Utils.getSetProfile()
  743. if !isChangeProfile {
  744. APIS.showChangeProfile()
  745. return
  746. }
  747. if flag == MFAViewController.STEP_FIDO || flag == MFAViewController.STEP_FIDO_BIOFACE || flag == MFAViewController.STEP_FIDO_BIOFINGER {
  748. checkFidoWithOrBIO(method: method, flag: flag)
  749. } else {
  750. let controller = MFAViewController()
  751. controller.METHOD = method
  752. controller.STEP_NEEDED = flag
  753. let navigationController = CustomNavigationController(rootViewController: controller)
  754. navigationController.defaultStyle()
  755. if UIApplication.shared.visibleViewController?.navigationController != nil {
  756. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  757. } else {
  758. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  759. }
  760. }
  761. }
  762. private static func checkFidoWithOrBIO(method: String, flag: String) {
  763. DispatchQueue.global().async {
  764. if let me = User.getMyPin() {
  765. do {
  766. let message = CoreMessage_TMessageBank.getMFAValidation(data: me)
  767. var hasKey = false
  768. if !KeyManagerNexilis.hasGeneratedKey() {
  769. KeyManagerNexilis.generateKey()
  770. KeyManagerNexilis.saveMarker()
  771. } else {
  772. hasKey = true
  773. }
  774. guard let privateKey = KeyManagerNexilis.getPrivateKey(useBiometric: false) else {
  775. KeyManagerNexilis.deleteKey()
  776. KeyManagerNexilis.deleteMarker()
  777. DispatchQueue.main.async {
  778. let errorMessage = "PPKey Generated Failed".localized()
  779. let dialog = DialogErrorMFA()
  780. dialog.modalTransitionStyle = .crossDissolve
  781. dialog.modalPresentationStyle = .overCurrentContext
  782. dialog.errorDesc = errorMessage
  783. dialog.method = method
  784. UIApplication.shared.visibleViewController?.present(dialog, animated: true)
  785. APIS.getMFACallback()?(5)
  786. }
  787. return
  788. }
  789. var id = ""
  790. if Utils.isMiddleMode() || Utils.isHSAMode() {
  791. id = Nexilis.justInit()
  792. } else {
  793. id = User.getMyPin() ?? ""
  794. }
  795. if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getChalanger(xPin: id)) {
  796. if response.isOk() {
  797. let data = response.getBody(key: CoreMessage_TMessageKey.DATA, default_value: "")
  798. if data.isEmpty {
  799. KeyManagerNexilis.deleteKey()
  800. KeyManagerNexilis.deleteMarker()
  801. DispatchQueue.main.async {
  802. let errorMessage = "Auth Failure".localized()
  803. let dialog = DialogErrorMFA()
  804. dialog.modalTransitionStyle = .crossDissolve
  805. dialog.modalPresentationStyle = .overCurrentContext
  806. dialog.errorDesc = errorMessage
  807. dialog.method = method
  808. UIApplication.shared.visibleViewController?.present(dialog, animated: true)
  809. APIS.getMFACallback()?(2)
  810. }
  811. return
  812. }
  813. let df = HMACDeviceFingerprintNexilis.generate()
  814. message.mBodies[CoreMessage_TMessageKey.FINGERPRINT] = df
  815. if hasKey {
  816. var sign = ""
  817. if let dataSign = "\(data)!\(df)".data(using: .utf8) {
  818. if let signature = KeyManagerNexilis.sign(data: dataSign, privateKey: privateKey) {
  819. sign = signature.base64EncodedString()
  820. }
  821. }
  822. message.mBodies[CoreMessage_TMessageKey.SIGNATURE] = sign
  823. } else {
  824. if let publicKey = KeyManagerNexilis.getRSAX509PublicKeyBase64(privateKey: privateKey) {
  825. message.mBodies[CoreMessage_TMessageKey.PUBLIC_KEY] = publicKey
  826. }
  827. }
  828. // let secret = "JBSWY3DPEHPK3PXP" // Google Authenticator example
  829. let otp = try TOTPGenerator.generateTOTP(base32Secret: TOTPGenerator.getTOTP(), digits: 6, timeStepSeconds: 300)
  830. message.mBodies[CoreMessage_TMessageKey.TOTP] = otp
  831. if let response = Nexilis.writeAndWait(message: message) {
  832. if response.isOk() {
  833. if flag == MFAViewController.STEP_FIDO_BIOFACE || flag == MFAViewController.STEP_FIDO_BIOFINGER {
  834. let semaphore = DispatchSemaphore(value: 0)
  835. var result = true
  836. var stateErr = 0
  837. let manager = BiometricStateManager()
  838. if method == "Sign Up" {
  839. manager.authenticateAndSaveState { res in
  840. result = res
  841. semaphore.signal()
  842. }
  843. } else {
  844. manager.hasBiometricStateChanged { (res, state) in
  845. result = res
  846. stateErr = state
  847. semaphore.signal()
  848. }
  849. }
  850. semaphore.wait()
  851. if result {
  852. DispatchQueue.main.async {
  853. UIApplication.shared.visibleViewController?.view.makeToast("Successfully Authenticated".localized(), duration: 3)
  854. }
  855. APIS.getMFACallback()?(0)
  856. } else {
  857. KeyManagerNexilis.deleteKey()
  858. KeyManagerNexilis.deleteMarker()
  859. DispatchQueue.main.async {
  860. var errorMessage = "Gagal mendeteksi Biometric (Touch/Face ID)"
  861. var errCode = 10
  862. if stateErr == 1 {
  863. errorMessage = "Terjadi Perubahan Biometric (Touch/Face ID)"
  864. errCode = 14
  865. }
  866. let dialog = DialogErrorMFA()
  867. dialog.modalTransitionStyle = .crossDissolve
  868. dialog.modalPresentationStyle = .overCurrentContext
  869. dialog.errorDesc = errorMessage
  870. dialog.method = method
  871. dialog.hideTryAgain = (stateErr == 1)
  872. dialog.isDismiss = { res in
  873. if res == 0 {
  874. APIS.logOut()
  875. APIS.getMFACallback()?(errCode)
  876. }
  877. }
  878. UIApplication.shared.visibleViewController?.present(dialog, animated: true)
  879. }
  880. }
  881. } else {
  882. DispatchQueue.main.async {
  883. UIApplication.shared.visibleViewController?.view.makeToast("Successfully Authenticated".localized(), duration: 3)
  884. }
  885. APIS.getMFACallback()?(0)
  886. }
  887. }
  888. else {
  889. KeyManagerNexilis.deleteKey()
  890. KeyManagerNexilis.deleteMarker()
  891. let errorMessage = response.getBody(key: CoreMessage_TMessageKey.MESSAGE_TEXT, default_value: "Auth Failure".localized())
  892. let errCode = response.getBodyAsInteger(key: CoreMessage_TMessageKey.ERRAPICOD, default_value: 2)
  893. DispatchQueue.main.async {
  894. let dialog = DialogErrorMFA()
  895. dialog.modalTransitionStyle = .crossDissolve
  896. dialog.modalPresentationStyle = .overCurrentContext
  897. dialog.errorDesc = errorMessage
  898. dialog.method = method
  899. UIApplication.shared.visibleViewController?.present(dialog, animated: true)
  900. APIS.getMFACallback()?(errCode)
  901. }
  902. }
  903. } else {
  904. KeyManagerNexilis.deleteKey()
  905. KeyManagerNexilis.deleteMarker()
  906. DispatchQueue.main.async {
  907. let errorMessage = "Unable to access servers. Check your internet connection and try again later".localized()
  908. let dialog = DialogErrorMFA()
  909. dialog.modalTransitionStyle = .crossDissolve
  910. dialog.modalPresentationStyle = .overCurrentContext
  911. dialog.errorDesc = errorMessage
  912. dialog.method = method
  913. UIApplication.shared.visibleViewController?.present(dialog, animated: true)
  914. APIS.getMFACallback()?(13)
  915. }
  916. }
  917. }
  918. } else {
  919. KeyManagerNexilis.deleteKey()
  920. KeyManagerNexilis.deleteMarker()
  921. DispatchQueue.main.async {
  922. let errorMessage = "Unable to access servers. Check your internet connection and try again later".localized()
  923. let dialog = DialogErrorMFA()
  924. dialog.modalTransitionStyle = .crossDissolve
  925. dialog.modalPresentationStyle = .overCurrentContext
  926. dialog.errorDesc = errorMessage
  927. dialog.method = method
  928. UIApplication.shared.visibleViewController?.present(dialog, animated: true)
  929. APIS.getMFACallback()?(13)
  930. }
  931. }
  932. } catch {
  933. }
  934. }
  935. }
  936. }
  937. public static func setFloatingButton(isShow: Bool) {
  938. DispatchQueue.main.async {
  939. Nexilis.floatingButton.removeFromSuperview()
  940. FloatingButton.datePull = nil
  941. if isShow {
  942. Nexilis.floatingButton = FloatingButton()
  943. Nexilis.addFB()
  944. }
  945. }
  946. }
  947. public static func openSecureBrowser() {
  948. let isChangeProfile = Utils.getSetProfile()
  949. if !isChangeProfile {
  950. APIS.showChangeProfile()
  951. return
  952. }
  953. let controller = BNIBookingWebView()
  954. controller.isSecureBrowser = true
  955. let navigationController = CustomNavigationController(rootViewController: controller)
  956. navigationController.defaultStyle()
  957. if UIApplication.shared.visibleViewController?.navigationController != nil {
  958. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  959. } else {
  960. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  961. }
  962. }
  963. public static func createCommunity() {
  964. let isChangeProfile = Utils.getSetProfile()
  965. if !isChangeProfile {
  966. APIS.showChangeProfile()
  967. return
  968. }
  969. let startedNewCommunity = UIViewController()
  970. if let viewComm = startedNewCommunity.view {
  971. viewComm.backgroundColor = .black.withAlphaComponent(0.1)
  972. let containerView = UIView()
  973. viewComm.addSubview(containerView)
  974. containerView.anchor(left: viewComm.leftAnchor, bottom: viewComm.bottomAnchor, right: viewComm.rightAnchor, minHeight: 40)
  975. containerView.backgroundColor = .white
  976. containerView.layer.cornerRadius = 15
  977. containerView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
  978. let closeButton = UIButton(type: .close)
  979. containerView.addSubview(closeButton)
  980. closeButton.anchor(top: containerView.topAnchor, right: containerView.rightAnchor, paddingTop: 10, paddingRight: 10, width: 30, height: 30)
  981. closeButton.layer.cornerRadius = 15
  982. closeButton.clipsToBounds = true
  983. closeButton.backgroundColor = .lightGray.withAlphaComponent(0.1)
  984. let config = UIImage.SymbolConfiguration(pointSize: 18, weight: .semibold)
  985. closeButton.setImage(UIImage(systemName: "xmark", withConfiguration: config), for: .normal)
  986. closeButton.addAction(UIAction { _ in
  987. startedNewCommunity.dismiss(animated: true)
  988. }, for: .touchUpInside)
  989. let imageComm = UIImageView(image: UIImage(named: "pb_community_social", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  990. containerView.addSubview(imageComm)
  991. imageComm.anchor(top: closeButton.bottomAnchor, paddingTop: -40, centerX: containerView.centerXAnchor, width: 350, height: 250)
  992. let titleComm = UILabel()
  993. containerView.addSubview(titleComm)
  994. titleComm.anchor(top: imageComm.bottomAnchor, left: containerView.leftAnchor, right: containerView.rightAnchor, paddingLeft: 20, paddingRight: 20)
  995. titleComm.font = .boldSystemFont(ofSize: 30)
  996. titleComm.textColor = .label
  997. titleComm.numberOfLines = 0
  998. titleComm.textAlignment = .center
  999. titleComm.text = "Create a new community".localized()
  1000. let descComm = UILabel()
  1001. containerView.addSubview(descComm)
  1002. descComm.anchor(top: titleComm.bottomAnchor, left: containerView.leftAnchor, right: containerView.rightAnchor, paddingTop: 8, paddingLeft: 20, paddingRight: 20)
  1003. descComm.font = .systemFont(ofSize: 16)
  1004. descComm.textColor = .label
  1005. descComm.numberOfLines = 0
  1006. descComm.textAlignment = .center
  1007. descComm.text = "Bring together a neighborhood, school or more. Create topic-based groups for members, and easily send them admin anouncements.".localized()
  1008. let buttonComm = UIButton(type: .custom)
  1009. containerView.addSubview(buttonComm)
  1010. buttonComm.anchor(top: descComm.bottomAnchor, left: containerView.leftAnchor, bottom: containerView.bottomAnchor, right: containerView.rightAnchor, paddingTop: 20, paddingLeft: 20, paddingBottom: 20, paddingRight: 20, height: 45)
  1011. buttonComm.backgroundColor = .whatsappGreenColor
  1012. buttonComm.layer.cornerRadius = 15
  1013. buttonComm.clipsToBounds = true
  1014. buttonComm.setTitle("Get started".localized(), for: .normal)
  1015. buttonComm.setTitleColor(.white, for: .normal)
  1016. buttonComm.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
  1017. buttonComm.addAction(UIAction { _ in
  1018. startedNewCommunity.dismiss(animated: true) {
  1019. let navigationController = UINavigationController(rootViewController: CommunityNew())
  1020. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  1021. }
  1022. }, for: .touchUpInside)
  1023. }
  1024. startedNewCommunity.modalPresentationStyle = .overCurrentContext
  1025. if UIApplication.shared.visibleViewController?.navigationController != nil {
  1026. UIApplication.shared.visibleViewController?.navigationController?.present(startedNewCommunity, animated: true, completion: nil)
  1027. } else {
  1028. UIApplication.shared.visibleViewController?.present(startedNewCommunity, animated: true, completion: nil)
  1029. }
  1030. }
  1031. public static func openCreateGroup() {
  1032. let isChangeProfile = Utils.getSetProfile()
  1033. if !isChangeProfile {
  1034. APIS.showChangeProfile()
  1035. return
  1036. }
  1037. let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "createGroupNav") as! UINavigationController
  1038. Utils.addBackground(view: controller.view)
  1039. let vc = controller.topViewController as! GroupCreateViewController
  1040. vc.isDismiss = { id in
  1041. let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "groupDetailView") as! GroupDetailViewController
  1042. controller.data = id
  1043. controller.fromNotification = true
  1044. let navigationController = CustomNavigationController(rootViewController: controller)
  1045. navigationController.defaultStyle()
  1046. DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
  1047. if UIApplication.shared.visibleViewController?.navigationController != nil {
  1048. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  1049. } else {
  1050. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  1051. }
  1052. })
  1053. }
  1054. controller.defaultStyle()
  1055. if UIApplication.shared.visibleViewController?.navigationController != nil {
  1056. UIApplication.shared.visibleViewController?.navigationController?.present(controller, animated: true, completion: nil)
  1057. } else {
  1058. UIApplication.shared.visibleViewController?.present(controller, animated: true, completion: nil)
  1059. }
  1060. }
  1061. public static func openAddFriend() {
  1062. let isChangeProfile = Utils.getSetProfile()
  1063. if !isChangeProfile {
  1064. APIS.showChangeProfile()
  1065. return
  1066. }
  1067. let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "addFriendNav") as! UINavigationController
  1068. Utils.addBackground(view: controller.view)
  1069. controller.defaultStyle()
  1070. if UIApplication.shared.visibleViewController?.navigationController != nil {
  1071. UIApplication.shared.visibleViewController?.navigationController?.present(controller, animated: true, completion: nil)
  1072. } else {
  1073. UIApplication.shared.visibleViewController?.present(controller, animated: true, completion: nil)
  1074. }
  1075. }
  1076. public static func openSignUpOrSignIn() {
  1077. let isChangeProfile = Utils.getSetProfile()
  1078. if !isChangeProfile {
  1079. APIS.showChangeProfile()
  1080. return
  1081. }
  1082. guard let controller = APIS.getControllerSign() else { return }
  1083. if let controller = controller as? SignUpSignIn {
  1084. controller.forceLogin = true
  1085. } else if let controller = controller as? SignInOption {
  1086. controller.forceLogin = true
  1087. }
  1088. let navigationController = CustomNavigationController(rootViewController: controller)
  1089. navigationController.defaultStyle()
  1090. if UIApplication.shared.visibleViewController?.navigationController != nil {
  1091. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  1092. } else {
  1093. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  1094. }
  1095. }
  1096. public static func openSetting() {
  1097. let navigationController = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "settingNav") as! UINavigationController
  1098. let vc = navigationController.rootViewController as! SettingTableViewController
  1099. vc.fromAPI = true
  1100. Utils.addBackground(view: navigationController.view)
  1101. navigationController.defaultStyle()
  1102. if UIApplication.shared.visibleViewController is UINavigationController && (UIApplication.shared.visibleViewController as! UINavigationController).rootViewController is SettingTableViewController {
  1103. return
  1104. }
  1105. if UIApplication.shared.visibleViewController?.navigationController != nil {
  1106. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  1107. } else {
  1108. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  1109. }
  1110. }
  1111. public static func openProfile() {
  1112. let isChangeProfile = Utils.getSetProfile()
  1113. if !isChangeProfile {
  1114. APIS.showChangeProfile()
  1115. return
  1116. }
  1117. let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "profileView") as! ProfileViewController
  1118. controller.data = User.getMyPin()!
  1119. controller.flag = .me
  1120. controller.fromAPI = true
  1121. controller.dismissImage = { image, imageName in
  1122. var dataImage: [AnyHashable : Any] = [:]
  1123. dataImage["name"] = imageName
  1124. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "imageFBUpdate"), object: nil, userInfo: dataImage)
  1125. }
  1126. let navigationController = CustomNavigationController(rootViewController: controller)
  1127. navigationController.defaultStyle()
  1128. if UIApplication.shared.visibleViewController?.navigationController != nil {
  1129. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  1130. } else {
  1131. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  1132. }
  1133. }
  1134. public static func openChatWallpaper(){
  1135. let isChangeProfile = Utils.getSetProfile()
  1136. if !isChangeProfile {
  1137. APIS.showChangeProfile()
  1138. return
  1139. }
  1140. let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "chatWallpaper") as! ChatWallpaperViewController
  1141. let navigationController = CustomNavigationController(rootViewController: controller)
  1142. navigationController.defaultStyle()
  1143. if UIApplication.shared.visibleViewController?.navigationController != nil {
  1144. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  1145. } else {
  1146. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  1147. }
  1148. }
  1149. public static func openWhiteboard() {
  1150. let isChangeProfile = Utils.getSetProfile()
  1151. if !isChangeProfile {
  1152. APIS.showChangeProfile()
  1153. return
  1154. }
  1155. let callContact = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "contactSID") as! ContactCallViewController
  1156. callContact.startWhiteBoard = true
  1157. let navigationController = CustomNavigationController(rootViewController: callContact)
  1158. navigationController.defaultStyle()
  1159. if UIApplication.shared.visibleViewController?.navigationController != nil {
  1160. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  1161. } else {
  1162. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  1163. }
  1164. }
  1165. public static func startWhiteboard(name: String) {
  1166. if name.isEmpty {
  1167. UIApplication.shared.visibleViewController?.view.makeToast("92:Username is empty".localized(), duration: 3)
  1168. return
  1169. }
  1170. let user = User.getDataFromNameCanNil(name: name)
  1171. if user == nil {
  1172. UIApplication.shared.visibleViewController?.view.makeToast("91:Invalid name or you must add Username to your contact first".localized(), duration: 3)
  1173. return
  1174. }
  1175. if !CheckConnection.isConnectedToNetwork() {
  1176. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  1177. imageView.tintColor = .white
  1178. let banner = FloatingNotificationBanner(title: "Check your connection".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
  1179. banner.show()
  1180. return
  1181. }
  1182. let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "wbVC") as! WhiteboardViewController
  1183. controller.modalPresentationStyle = .overFullScreen
  1184. controller.fromContact = 0
  1185. controller.user = user
  1186. if UIApplication.shared.visibleViewController?.navigationController != nil {
  1187. UIApplication.shared.visibleViewController?.navigationController?.present(controller, animated: true, completion: nil)
  1188. } else {
  1189. UIApplication.shared.visibleViewController?.present(controller, animated: true, completion: nil)
  1190. }
  1191. }
  1192. // public static func openScreenSharing() {
  1193. // let isChangeProfile = Utils.getSetProfile()
  1194. // if !isChangeProfile {
  1195. // APIS.showChangeProfile()
  1196. // return
  1197. // }
  1198. // let callContact = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "contactSID") as! ContactCallViewController
  1199. // callContact.startSS = true
  1200. // let navigationController = CustomNavigationController(rootViewController: callContact)
  1201. // navigationController.defaultStyle()
  1202. // if UIApplication.shared.visibleViewController?.navigationController != nil {
  1203. // UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  1204. // } else {
  1205. // UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  1206. // }
  1207. // }
  1208. public static func startScreenSharing(name: String) {
  1209. if name.isEmpty {
  1210. UIApplication.shared.visibleViewController?.view.makeToast("92:Username is empty".localized(), duration: 3)
  1211. return
  1212. }
  1213. let user = User.getDataFromNameCanNil(name: name)
  1214. if user == nil {
  1215. UIApplication.shared.visibleViewController?.view.makeToast("91:Invalid name or you must add Username to your contact first".localized(), duration: 3)
  1216. return
  1217. }
  1218. if !CheckConnection.isConnectedToNetwork() {
  1219. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  1220. imageView.tintColor = .white
  1221. let banner = FloatingNotificationBanner(title: "Check your connection".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
  1222. banner.show()
  1223. return
  1224. }
  1225. let controller = ScreenSharingViewController()
  1226. controller.modalPresentationStyle = .overFullScreen
  1227. controller.fromContact = 0
  1228. controller.user = user
  1229. if UIApplication.shared.visibleViewController?.navigationController != nil {
  1230. UIApplication.shared.visibleViewController?.navigationController?.present(controller, animated: true, completion: nil)
  1231. } else {
  1232. UIApplication.shared.visibleViewController?.present(controller, animated: true, completion: nil)
  1233. }
  1234. }
  1235. public static func openWhiteboardAndScreenSharing() {
  1236. let isChangeProfile = Utils.getSetProfile()
  1237. if !isChangeProfile {
  1238. APIS.showChangeProfile()
  1239. return
  1240. }
  1241. let callContact = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "contactSID") as! ContactCallViewController
  1242. callContact.startSS = true
  1243. callContact.startWhiteBoard = true
  1244. let navigationController = CustomNavigationController(rootViewController: callContact)
  1245. navigationController.defaultStyle()
  1246. if UIApplication.shared.visibleViewController?.navigationController != nil {
  1247. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  1248. } else {
  1249. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  1250. }
  1251. }
  1252. public static func signInAdmin(password: String) {
  1253. if password.isEmpty {
  1254. UIApplication.shared.visibleViewController?.view.makeToast("113:Password is empty".localized(), duration: 3)
  1255. return
  1256. }
  1257. let isChangeProfile = Utils.getSetProfile()
  1258. if !isChangeProfile {
  1259. APIS.showChangeProfile()
  1260. return
  1261. }
  1262. let isAdmin = User.isAdmin()
  1263. if isAdmin {
  1264. UIApplication.shared.visibleViewController?.view.makeToast("112:You already login or registered as Admin".localized(), duration: 3)
  1265. return
  1266. }
  1267. if !CheckConnection.isConnectedToNetwork() || API.nGetCLXConnState() == 0 {
  1268. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  1269. imageView.tintColor = .white
  1270. let banner = FloatingNotificationBanner(title: "Check your connection".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
  1271. banner.show()
  1272. return
  1273. }
  1274. Nexilis.showLoader()
  1275. self.signInAdmin(password: password, completion: { result in
  1276. if result {
  1277. DispatchQueue.main.async {
  1278. Nexilis.hideLoader {
  1279. let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
  1280. imageView.tintColor = .white
  1281. let banner = FloatingNotificationBanner(title: "Successfully Sign-In Admin".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .success, colors: nil, iconPosition: .center)
  1282. banner.show()
  1283. }
  1284. }
  1285. } else {
  1286. DispatchQueue.main.async {
  1287. Nexilis.hideLoader {}
  1288. }
  1289. }
  1290. })
  1291. }
  1292. private static func signInAdmin(password: String, completion: @escaping (Bool) -> ()) {
  1293. DispatchQueue.global().async {
  1294. let idMe = User.getMyPin() as String?
  1295. let p_password = password
  1296. let md5Hex = p_password
  1297. var result: Bool = false
  1298. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getSignInApiAdmin(p_name: idMe!, p_password: md5Hex)) {
  1299. if response.isOk() {
  1300. result = true
  1301. }
  1302. DispatchQueue.main.async {
  1303. if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "11" {
  1304. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  1305. imageView.tintColor = .white
  1306. let banner = FloatingNotificationBanner(title: "Username or password does not match".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .top)
  1307. banner.show()
  1308. } else if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "20" {
  1309. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  1310. imageView.tintColor = .white
  1311. let banner = FloatingNotificationBanner(title: "Invalid password".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .top)
  1312. banner.show()
  1313. }
  1314. }
  1315. } else {
  1316. DispatchQueue.main.async {
  1317. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  1318. imageView.tintColor = .white
  1319. let banner = FloatingNotificationBanner(title: "Unable to access servers".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .top)
  1320. banner.show()
  1321. }
  1322. }
  1323. completion(result)
  1324. }
  1325. }
  1326. public static func openSetAsOfficerForm() {
  1327. let isChangeProfile = Utils.getSetProfile()
  1328. if !isChangeProfile {
  1329. APIS.showChangeProfile()
  1330. return
  1331. }
  1332. let isAdmin = User.isAdmin()
  1333. if !isAdmin {
  1334. UIApplication.shared.visibleViewController?.view.makeToast("111:You must Sign In as Admin to use this feature".localized(), duration: 3)
  1335. return
  1336. }
  1337. let controller = SetInternalCSAccount()
  1338. controller.isSetCS = true
  1339. controller.fromNotification = true
  1340. let navigationController = CustomNavigationController(rootViewController: controller)
  1341. navigationController.defaultStyle()
  1342. if UIApplication.shared.visibleViewController?.navigationController != nil {
  1343. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  1344. } else {
  1345. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  1346. }
  1347. }
  1348. public static func logOut() {
  1349. let isChangeProfile = Utils.getSetProfile()
  1350. if !isChangeProfile {
  1351. APIS.showChangeProfile()
  1352. return
  1353. }
  1354. Nexilis.destroyAll()
  1355. _ = Nexilis.write(message: CoreMessage_TMessageBank.getLogout())
  1356. }
  1357. public static func openPPOB() {
  1358. let isChangeProfile = Utils.getSetProfile()
  1359. if !isChangeProfile {
  1360. APIS.showChangeProfile()
  1361. return
  1362. }
  1363. let idx = Nexilis.IDX_PPOB
  1364. let url = getURLFB(idx: idx)
  1365. Nexilis.buttonClicked(index: idx, id: url)
  1366. }
  1367. public static func openWallet() {
  1368. let isChangeProfile = Utils.getSetProfile()
  1369. if !isChangeProfile {
  1370. APIS.showChangeProfile()
  1371. return
  1372. }
  1373. let idx = Nexilis.IDX_WALLET
  1374. let url = getURLFB(idx: idx)
  1375. Nexilis.buttonClicked(index: idx, id: url)
  1376. }
  1377. public static func openSocialCommerce() {
  1378. let isChangeProfile = Utils.getSetProfile()
  1379. if !isChangeProfile {
  1380. APIS.showChangeProfile()
  1381. return
  1382. }
  1383. let idx = Nexilis.IDX_SOCIAL_COMMERCE
  1384. let url = getURLFB(idx: idx)
  1385. Nexilis.buttonClicked(index: idx, id: url)
  1386. }
  1387. private static func getURLFB(idx: Int) -> String {
  1388. let data = Utils.getHistoryPullFB()
  1389. if !data.isEmpty {
  1390. if let jsonArray = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [AnyObject] {
  1391. let filteredData = jsonArray.filter({
  1392. let package_id = ($0["package_id"] as! String)
  1393. if package_id.contains("_fb") {
  1394. let listSplit = package_id.split(separator: "_", maxSplits: 2, omittingEmptySubsequences: false).map { String($0) }
  1395. let numIdx = listSplit[listSplit.firstIndex(where: { $0.contains("fb") }) ?? 0]
  1396. let indexTap = Int(String(numIdx).substring(from: 2, to: numIdx.count)) ?? 0
  1397. return indexTap == idx
  1398. }
  1399. return package_id.isEmpty
  1400. })
  1401. if filteredData.count != 0 {
  1402. let data = filteredData[0] as? [String: Any]
  1403. let package_id = data?["package_id"] as! String
  1404. let listSplit = package_id.split(separator: "_", maxSplits: 2, omittingEmptySubsequences: false).map { String($0) }
  1405. return String(listSplit[2])
  1406. }
  1407. }
  1408. }
  1409. return ""
  1410. }
  1411. public static func sendSMS(phoneNumber: String, message: String = ""){
  1412. let formattedNumber = phoneNumber.replacingOccurrences(of: "-", with: "")
  1413. let urlStringEncoded = message.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)
  1414. let paramMessage = message.isEmpty ? "" : "&body=\(urlStringEncoded!)"
  1415. let url = URL(string: "sms:\(formattedNumber)\(paramMessage)")
  1416. if UIApplication.shared.canOpenURL(url!) {
  1417. UIApplication.shared.open(url!)
  1418. }
  1419. }
  1420. public static func sendWhatsapp(phoneNumber: String, message: String = "") {
  1421. let formattedNumber = phoneNumber.replacingOccurrences(of: "+", with: "").replacingOccurrences(of: "-", with: "")
  1422. let urlStringEncoded = message.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)
  1423. let paramMessage = message.isEmpty ? "" : "?text=\(urlStringEncoded!)"
  1424. let url = URL(string: "https://wa.me/\(formattedNumber)\(paramMessage)")
  1425. if UIApplication.shared.canOpenURL(url!) {
  1426. UIApplication.shared.open(url!, options: [:]) { (success) in
  1427. // if success {
  1428. // //print("WhatsApp accessed successfully")
  1429. // } else {
  1430. // //print("Error accessing WhatsApp")
  1431. // }
  1432. }
  1433. }
  1434. }
  1435. public static func changeUsername(uname: String) {
  1436. let isChangeProfile = Utils.getSetProfile()
  1437. if !isChangeProfile {
  1438. APIS.showChangeProfile()
  1439. return
  1440. }
  1441. let finalUname = uname.replacingOccurrences(of: "[\\n\\r\\t~%()\"]", with: "", options: .regularExpression)
  1442. if finalUname == User.getData(pin: User.getMyPin())?.fullName {
  1443. UIApplication.shared.visibleViewController?.view.makeToast("102:Duplicate username".localized(), duration: 3)
  1444. return
  1445. }
  1446. if finalUname.count == 0 {
  1447. UIApplication.shared.visibleViewController?.view.makeToast("103:Username is empty".localized(), duration: 3)
  1448. return
  1449. }
  1450. if finalUname.count < 3 {
  1451. UIApplication.shared.visibleViewController?.view.makeToast("104:Username length is too short".localized(), duration: 3)
  1452. return
  1453. }
  1454. let a = finalUname.split(separator: " ", maxSplits: 1)
  1455. let first = String(a[0])
  1456. let last = a.count == 2 ? String(a[1]) : ""
  1457. DispatchQueue.global().async {
  1458. if let resp = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getChangePersonInfoName(firstname: first, lastname: last)) {
  1459. if resp.isOk() {
  1460. Database.shared.database?.inTransaction({ fmdb, rollback in
  1461. do {
  1462. _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: ["first_name": first , "last_name": last], _where: "f_pin = '\(User.getMyPin())'")
  1463. } catch {
  1464. rollback.pointee = true
  1465. print("Access database error: \(error.localizedDescription)")
  1466. }
  1467. })
  1468. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateFifthTab"), object: nil, userInfo: nil)
  1469. DispatchQueue.main.async {
  1470. Nexilis.hideLoader {
  1471. let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
  1472. imageView.tintColor = .white
  1473. let banner = FloatingNotificationBanner(title: "Successfully changed name".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .success, colors: nil, iconPosition: .center)
  1474. banner.show()
  1475. }
  1476. }
  1477. } else if resp.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "1a" {
  1478. DispatchQueue.main.async {
  1479. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  1480. imageView.tintColor = .white
  1481. let banner = FloatingNotificationBanner(title: "Username has been registered, please use another name".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
  1482. banner.show()
  1483. }
  1484. }
  1485. }
  1486. }
  1487. }
  1488. public static func openMail() {
  1489. Nexilis.openmailAction()
  1490. }
  1491. public static func sendPushToken(_ token: String, isResend: Bool = false, isCall: Bool = false) {
  1492. if !isCall {
  1493. if Utils.getTokenAPN().isEmpty || token != Utils.getTokenAPN() {
  1494. Utils.setTokenAPN(value: token)
  1495. }
  1496. DispatchQueue.global().async {
  1497. while API.nGetCLXConnState() == 0 {
  1498. Thread.sleep(forTimeInterval: 1)
  1499. }
  1500. _ = Nexilis.write(message: CoreMessage_TMessageBank.getToken(token: token, tokenCall: Utils.getTokenCall()))
  1501. }
  1502. }
  1503. else {
  1504. if Utils.getTokenCall().isEmpty || token != Utils.getTokenCall() {
  1505. Utils.setTokenCall(value: token)
  1506. }
  1507. // DispatchQueue.global().async {
  1508. // while API.nGetCLXConnState() == 0 {
  1509. // Thread.sleep(forTimeInterval: 1)
  1510. // }
  1511. // print("SEND TOKEN CALL")
  1512. // _ = Nexilis.write(message: CoreMessage_TMessageBank.getToken(token: token, isCall: true))
  1513. // }
  1514. }
  1515. }
  1516. public static var uuidCall: UUID?
  1517. public static var fpinCall: String?
  1518. public static func showNotificationNexilis(_ userInfo: [AnyHashable : Any]) {
  1519. DispatchQueue.main.async {
  1520. if checkAppStateisBackground() {
  1521. DispatchQueue.global(qos: .background).async {
  1522. if let payload = userInfo["payload"] as? [String: Any] {
  1523. if let messagePayload = payload["message"] as? [String: Any] {
  1524. if let data = messagePayload["data"] as? [String: Any] {
  1525. let code = data["nx_code"] as? String ?? ""
  1526. if code == "CL01" {
  1527. if let message = data["bodies"] as? [String: String] {
  1528. let idAck = data["message_id"] as? String ?? ""
  1529. let messageToSave = TMessage()
  1530. messageToSave.mBodies = message
  1531. do {
  1532. var messageExist = false
  1533. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  1534. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select message_id from MESSAGE where message_id = '\(message[CoreMessage_TMessageKey.MESSAGE_ID] ?? "")'"), cursor.next() {
  1535. messageExist = true
  1536. cursor.close()
  1537. }
  1538. })
  1539. if messageExist {
  1540. ackAPN(id: idAck)
  1541. return
  1542. }
  1543. } catch {
  1544. print("error saving message: \(error)")
  1545. }
  1546. APIS.addNotificationNexilis(messageToSave)
  1547. ackAPN(id: idAck)
  1548. Nexilis.saveMessage(message: messageToSave, withStatus: false, fromAPNS: true)
  1549. }
  1550. } else if code == "CL03" {
  1551. let callFromName = data["call-from-name"] as? String ?? ""
  1552. let callFrom = data["call-from"] as? String ?? ""
  1553. let callType = data["call-type"] as? String ?? ""
  1554. // uuidCall = UUID()
  1555. fpinCall = callFrom
  1556. Nexilis.callAPNActivated = true
  1557. let center = UNUserNotificationCenter.current()
  1558. let content = UNMutableNotificationContent()
  1559. content.title = callFromName
  1560. if callType == "1" {
  1561. content.body = "Incoming Audio Call".localized()
  1562. } else {
  1563. content.body = "Incoming Video Call".localized()
  1564. }
  1565. content.userInfo = ["id" : callFrom, "type" : code, "callType": callType]
  1566. content.sound = nil
  1567. let request = UNNotificationRequest(identifier: callFrom, content: content, trigger: nil)
  1568. center.add(request) { error in
  1569. if let error = error {
  1570. print("Error scheduling notification: \(error.localizedDescription)")
  1571. }
  1572. }
  1573. let session = AVAudioSession.sharedInstance()
  1574. do {
  1575. try session.setCategory(.playback, options: [.duckOthers])
  1576. try session.setActive(true)
  1577. } catch {
  1578. print("Audio session error: \(error)")
  1579. }
  1580. Nexilis.playRingtoneCall()
  1581. } else if code == "CL02" {
  1582. print("data \(data)")
  1583. let callFromName = data["call-cancel-name"] as? String ?? ""
  1584. let callFrom = data["call-cancel"] as? String ?? ""
  1585. let callType = data["call-type"] as? String ?? ""
  1586. // if let uuidCall = uuidCall {
  1587. Nexilis.stopRingtoneCall()
  1588. Nexilis.callAPNActivated = false
  1589. let center = UNUserNotificationCenter.current()
  1590. center.removeDeliveredNotifications(withIdentifiers: [callFrom])
  1591. var textCall = ""
  1592. if callType == "1" {
  1593. textCall = "audio"
  1594. } else {
  1595. textCall = "video"
  1596. }
  1597. let content = UNMutableNotificationContent()
  1598. content.title = callFromName
  1599. content.body = "☎️ Missed \(textCall) call".localized()
  1600. content.userInfo = ["id" : callFrom, "type" : code, "callType": callType]
  1601. content.sound = nil
  1602. let request = UNNotificationRequest(identifier: callFrom, content: content, trigger: nil)
  1603. center.add(request) { error in
  1604. if let error = error {
  1605. print("Error scheduling notification: \(error.localizedDescription)")
  1606. }
  1607. }
  1608. Nexilis.saveMessageCall(idCall: (User.getMyPin() ?? "") + CoreMessage_TMessageUtil.getTID(), textMessage: "Missed \(textCall) call".localized() + " at 0", fPin: callFrom, lPin: (User.getMyPin() ?? ""), timeCall: String(Date().currentTimeMillis()), attachment_type: MessageScope.MISSED_CALL)
  1609. }
  1610. }
  1611. }
  1612. } else if let message_id = userInfo["message_id"] as? String {
  1613. DispatchQueue.main.async {
  1614. let lastBadgeNumber = UIApplication.shared.applicationIconBadgeNumber
  1615. UIApplication.shared.applicationIconBadgeNumber = lastBadgeNumber + 1
  1616. }
  1617. getMessageById(id: message_id)
  1618. }
  1619. }
  1620. }
  1621. }
  1622. }
  1623. public static func showNotificationCallKitNexilis(payload: [AnyHashable : Any], completion: @escaping () -> ()) {
  1624. if let messagePayload = payload["payload"] as? [String: Any] {
  1625. if let message = messagePayload["message"] as? [String: Any] {
  1626. if let data = message["data"] as? [String: Any] {
  1627. let nxCode = data["nx_code"] as? String ?? ""
  1628. let callFromName = data["call-from-name"] as? String ?? ""
  1629. let callCancelName = data["call-cancel-name"] as? String ?? ""
  1630. let callFrom = data["call-from"] as? String ?? ""
  1631. let callCancel = data["call-cancel"] as? String ?? ""
  1632. let callType = data["call-type"] as? String ?? ""
  1633. if nxCode == "CL03" {
  1634. Nexilis.callAPNActivated = true
  1635. APIS.uuidCall = UUID()
  1636. CallManager.shared.reportIncomingCall(uuid: APIS.uuidCall ?? UUID(), callerName: callFromName, callerId: callFrom, isVideo: callType != "1")
  1637. } else {
  1638. if APIS.uuidCall != nil {
  1639. CallManager.shared.endCall(uuid: APIS.uuidCall!) {
  1640. Nexilis.callAPNActivated = false
  1641. APIS.uuidCall = nil
  1642. let center = UNUserNotificationCenter.current()
  1643. var textCall = ""
  1644. if callType == "1" {
  1645. textCall = "audio"
  1646. } else {
  1647. textCall = "video"
  1648. }
  1649. let content = UNMutableNotificationContent()
  1650. content.title = callCancelName
  1651. content.body = "☎️ Missed \(textCall) call".localized()
  1652. content.userInfo = ["id" : callFrom, "type" : nxCode, "callType": callType]
  1653. content.sound = nil
  1654. let request = UNNotificationRequest(identifier: callCancel, content: content, trigger: nil)
  1655. center.add(request) { error in
  1656. if let error = error {
  1657. print("Error scheduling notification: \(error.localizedDescription)")
  1658. }
  1659. }
  1660. Nexilis.saveMessageCall(idCall: (User.getMyPin() ?? "") + CoreMessage_TMessageUtil.getTID(), textMessage: "Missed \(textCall) call".localized() + " at 0", fPin: callCancel, lPin: (User.getMyPin() ?? ""), timeCall: String(Date().currentTimeMillis()), attachment_type: MessageScope.MISSED_CALL)
  1661. }
  1662. } else if UIApplication.shared.visibleViewController is QmeraAudioViewController || UIApplication.shared.visibleViewController is QmeraVideoViewController {
  1663. var dataMessage: [AnyHashable : Any] = [:]
  1664. dataMessage["call_cancel"] = true
  1665. NotificationCenter.default.post(name: NSNotification.Name(rawValue: Nexilis.callFCM), object: nil, userInfo: dataMessage)
  1666. }
  1667. }
  1668. }
  1669. }
  1670. }
  1671. }
  1672. static func ackAPN(id: String) {
  1673. DispatchQueue.global(qos: .background).async {
  1674. // Nexilis.sendStateToServer(s: "send ack from apn")
  1675. // if API.nGetCLXConnState() == 0 {
  1676. // do {
  1677. // let id = Utils.getConnectionID()
  1678. // try API.initConnection(sAPIK: Nexilis.sAPIKey, cbiI: Callback(), sTCPAddr: Nexilis.ADDRESS, nTCPPort: Nexilis.PORT, sUserID: id, sStartWH: "09:00")
  1679. // } catch {}
  1680. // }
  1681. // while API.nGetCLXConnState() == 0 {
  1682. // Thread.sleep(forTimeInterval: 0.5)
  1683. // }
  1684. // let _ = Nexilis.writeSync(message: CoreMessage_TMessageBank.getAckMessage(messageId: id), timeout: 30000)
  1685. //HTTPS
  1686. let parameter: [String : Any] = [
  1687. "pin": User.getMyPin() ?? "",
  1688. "message_id": id
  1689. ]
  1690. Utils.postDataWithCookiesAndUserAgent(from: URL(string: Utils.getDomainOpr() + "ack_message")!, parameter: parameter, isFormData: true) { data, response, error in
  1691. }
  1692. }
  1693. }
  1694. private static func getMessageById(id: String, retry: Int = 0) {
  1695. // if API.nGetCLXConnState() == 0 {
  1696. // do {
  1697. // let id = Utils.getConnectionID()
  1698. // try API.initConnection(sAPIK: Nexilis.sAPIKey, cbiI: Callback(), sTCPAddr: Nexilis.ADDRESS, nTCPPort: Nexilis.PORT, sUserID: id, sStartWH: "09:00")
  1699. // } catch {}
  1700. // }
  1701. // while API.nGetCLXConnState() == 0 {
  1702. // Thread.sleep(forTimeInterval: 0.5)
  1703. // }
  1704. // if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getMessageById(messageId: id), timeout: 30000) {
  1705. // if response.isOk() {
  1706. // let data = response.getBody(key: CoreMessage_TMessageKey.DATA)
  1707. // if let decodedData = Data(base64Encoded: data, options: .ignoreUnknownCharacters) {
  1708. // if let respData = String(data: decodedData, encoding: .utf8) {
  1709. // let message = TMessage(data: respData)
  1710. // if Utils.getSecureFolderOffline() == "0" && IncomingThread.dispatch == nil {
  1711. // if FileEncryption.shared.aesKey == nil {
  1712. // IncomingThread.dispatch = DispatchGroup()
  1713. // IncomingThread.dispatch?.enter()
  1714. // Nexilis.getFeatureAccess()
  1715. // IncomingThread.dispatch?.wait()
  1716. // IncomingThread.dispatch = nil
  1717. // }
  1718. // }
  1719. //// print("save from APIS")
  1720. // Nexilis.saveMessage(message: message, withStatus: false, fromAPNS: true)
  1721. // ackAPN(id: id)
  1722. // DispatchQueue.main.async {
  1723. // UIApplication.shared.applicationIconBadgeNumber = Int(APIS.getTotalCounter())
  1724. // }
  1725. // }
  1726. // }
  1727. // } else {
  1728. // let ret = retry + 1
  1729. // if ret <= 5 {
  1730. // getMessageById(id: id, retry: ret)
  1731. // }
  1732. // }
  1733. // } else {
  1734. // let ret = retry + 1
  1735. // if ret <= 5 {
  1736. // getMessageById(id: id, retry: ret)
  1737. // }
  1738. // }
  1739. //HTTPS
  1740. let parameter: [String : Any] = [
  1741. "pin": User.getMyPin() ?? "",
  1742. "message_id": id
  1743. ]
  1744. Utils.postDataWithCookiesAndUserAgent(from: URL(string: Utils.getDomainOpr() + "pull_notification")!, parameter: parameter, isFormData: true) { data, response, error in
  1745. if let error = error {
  1746. print("Error: \(error.localizedDescription)")
  1747. let ret = retry + 1
  1748. if ret <= 5 {
  1749. let delay = pow(2.0, Double(ret)) // 2, 4, 8, 16...
  1750. DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + delay) {
  1751. getMessageById(id: id, retry: ret)
  1752. }
  1753. }
  1754. return
  1755. }
  1756. guard let data = data else {
  1757. let ret = retry + 1
  1758. if ret <= 5 {
  1759. DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 1) {
  1760. getMessageById(id: id, retry: ret)
  1761. }
  1762. }
  1763. return
  1764. }
  1765. DispatchQueue.main.async {
  1766. if !APIS.checkAppStateisBackground() {
  1767. return
  1768. }
  1769. do {
  1770. if let jsonObj = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
  1771. let dataObj = jsonObj["data"] as? String ?? ""
  1772. let message = TMessage(data: dataObj)
  1773. // simpan message
  1774. Nexilis.saveMessage(message: message, withStatus: false, fromAPNS: true)
  1775. ackAPN(id: id)
  1776. DispatchQueue.main.async {
  1777. UIApplication.shared.applicationIconBadgeNumber = Int(APIS.getTotalCounter())
  1778. }
  1779. } else {
  1780. throw NSError(domain: "Invalid JSON", code: -1)
  1781. }
  1782. } catch {
  1783. print("Parsing error: \(error)")
  1784. let ret = retry + 1
  1785. if ret <= 5 {
  1786. DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
  1787. getMessageById(id: id, retry: ret)
  1788. }
  1789. }
  1790. }
  1791. }
  1792. }
  1793. }
  1794. public static func addNotificationNexilis(_ message: TMessage) {
  1795. var text = message.getBody(key: CoreMessage_TMessageKey.MESSAGE_TEXT)
  1796. text = text.toNormalString()
  1797. let nameUser = message.getBody(key: CoreMessage_TMessageKey.F_DISPLAY_NAME)
  1798. var threadIdentifier = message.getBody(key: CoreMessage_TMessageKey.OPPOSITE_PIN)
  1799. let scope = message.getBody(key: CoreMessage_TMessageKey.MESSAGE_SCOPE_ID)
  1800. if threadIdentifier.isEmpty {
  1801. if scope == "4" {
  1802. threadIdentifier = message.getBody(key: CoreMessage_TMessageKey.CHAT_ID).isEmpty ? message.getBody(key: CoreMessage_TMessageKey.L_PIN) : message.getBody(key: CoreMessage_TMessageKey.CHAT_ID)
  1803. } else {
  1804. threadIdentifier = message.getBody(key: CoreMessage_TMessageKey.F_PIN)
  1805. }
  1806. }
  1807. let messageId = message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)
  1808. var nameSubtitle = ""
  1809. let imageId = CoreMessage_TMessageKey.IMAGE_ID
  1810. let videoId = CoreMessage_TMessageKey.VIDEO_ID
  1811. let fileId = CoreMessage_TMessageKey.FILE_ID
  1812. let audioId = CoreMessage_TMessageKey.AUDIO_ID
  1813. let attachmentFlag = CoreMessage_TMessageKey.ATTACHMENT_FLAG
  1814. let messageScopeId = CoreMessage_TMessageKey.MESSAGE_SCOPE_ID
  1815. let credential = CoreMessage_TMessageKey.CREDENTIAL
  1816. let gif_id = CoreMessage_TMessageKey.GIF_ID
  1817. let is_secret = CoreMessage_TMessageKey.IS_SECRET
  1818. if message.getBody(key: is_secret) == "1" {
  1819. text = "You got messages..."
  1820. } else if message.getBody(key: gif_id) != "" {
  1821. text = "Sent GIF 🎬"
  1822. } else if !message.getBody(key: imageId).isEmpty {
  1823. text = "Sent Image 📷"
  1824. } else if message.getBody(key: attachmentFlag) == "11" {
  1825. text = "Sent Sticker ❤️"
  1826. } else if !message.getBody(key: videoId).isEmpty {
  1827. text = "Sent Video 📹"
  1828. } else if !message.getBody(key: fileId).isEmpty {
  1829. if message.getBody(key: messageScopeId) == "18" {
  1830. text = "Sent Form 📄"
  1831. } else {
  1832. text = "Sent File 📄"
  1833. }
  1834. } else if !message.getBody(key: audioId).isEmpty {
  1835. text = "Sent Audio ♫"
  1836. } else if text.contains("Share%20location%20") {
  1837. text = "Sent Location 📌"
  1838. } else if message.getBody(key: attachmentFlag) == "27" {
  1839. text = "Sent Live Streaming"
  1840. } else if message.getBody(key: attachmentFlag) == "26" {
  1841. text = "Sent Seminar"
  1842. } else if message.getBody(key: attachmentFlag) == "25" {
  1843. text = "Sent Video Conference Room"
  1844. } else if message.getBody(key: attachmentFlag) == "24" {
  1845. text = "Sent Quiz"
  1846. } else if message.getBody(key: credential) == "1" {
  1847. text = "Sent Confidential Message"
  1848. }
  1849. var type = "1"
  1850. var nameTopic = "Lounge".localized()
  1851. var idGroup = ""
  1852. if scope == "3" || scope == "18" || scope == "5"{
  1853. type = "0"
  1854. }
  1855. var soundId: String = SecureUserDefaults.shared.value(forKey: "newNotifSoundPersonal") ?? "001:Nexilis Message (Default)"
  1856. if type == "1" {
  1857. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  1858. do {
  1859. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "SELECT title, group_id FROM DISCUSSION_FORUM WHERE chat_id='\(threadIdentifier)'"), cursor.next() {
  1860. nameTopic = cursor.string(forColumnIndex: 0) ?? ""
  1861. idGroup = cursor.string(forColumnIndex: 1) ?? ""
  1862. cursor.close()
  1863. }
  1864. if idGroup.isEmpty {
  1865. idGroup = threadIdentifier
  1866. }
  1867. if let cursorGroup = Database.shared.getRecords(fmdb: fmdb, query: "SELECT f_name, image_id FROM GROUPZ WHERE group_id='\(idGroup)'"), cursorGroup.next() {
  1868. let nameGroup = cursorGroup.string(forColumnIndex: 0) ?? ""
  1869. nameSubtitle = "\(nameGroup) (\(nameTopic))"
  1870. cursorGroup.close()
  1871. }
  1872. } catch {
  1873. rollback.pointee = true
  1874. print("Access database error: \(error.localizedDescription)")
  1875. }
  1876. })
  1877. soundId = SecureUserDefaults.shared.value(forKey: "newNotifSoundGroup") ?? "001:Nexilis Message (Default)"
  1878. if idGroup.isEmpty {
  1879. return
  1880. }
  1881. }
  1882. var nameSound = soundId.components(separatedBy: ":")[1].replacingOccurrences(of: " ", with: "_")
  1883. var fromPref = false
  1884. if nameSound.contains("_(Default)") {
  1885. if !Utils.getDefaultIncomingMsg().isEmpty {
  1886. nameSound = Utils.getDefaultIncomingMsg()
  1887. fromPref = true
  1888. } else {
  1889. nameSound = nameSound.replacingOccurrences(of: "_(Default)", with: "")
  1890. }
  1891. }
  1892. copySoundToLocalPath(nameSound, fromPref)
  1893. let center = UNUserNotificationCenter.current()
  1894. let content = UNMutableNotificationContent()
  1895. content.title = nameUser
  1896. if type == "1" {
  1897. content.body = text.richText(group_id: idGroup).string
  1898. content.subtitle = nameSubtitle
  1899. } else {
  1900. content.body = text.richText().string
  1901. }
  1902. content.userInfo = ["id" : threadIdentifier, "type" : type]
  1903. content.sound = UNNotificationSound(named: UNNotificationSoundName("\(nameSound).mp3"))
  1904. let request = UNNotificationRequest(identifier: messageId, content: content, trigger: nil)
  1905. center.add(request) { error in
  1906. if let error = error {
  1907. print("Error scheduling notification: \(error.localizedDescription)")
  1908. }
  1909. }
  1910. DispatchQueue.main.async {
  1911. UIApplication.shared.applicationIconBadgeNumber = Int(APIS.getTotalCounter())
  1912. }
  1913. }
  1914. private static func copySoundToLocalPath(_ nameSound: String, _ fromPref: Bool) {
  1915. var sourceURL: URL?
  1916. if fromPref {
  1917. let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
  1918. let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
  1919. let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
  1920. if let dirPath = paths.first {
  1921. let audioURL = URL(fileURLWithPath: dirPath).appendingPathComponent(nameSound)
  1922. if FileManager.default.fileExists(atPath: audioURL.path) {
  1923. sourceURL = audioURL
  1924. } else if FileEncryption.shared.isSecureExists(filename: nameSound) {
  1925. do {
  1926. if var audioData = try FileEncryption.shared.readSecure(filename: nameSound) {
  1927. let dataDecrypt = FileEncryption.shared.decryptFileFromServer(data: audioData)
  1928. if dataDecrypt != nil {
  1929. audioData = dataDecrypt!
  1930. }
  1931. let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
  1932. let tempPath = cachesDirectory.appendingPathComponent(nameSound)
  1933. try audioData.write(to: tempPath)
  1934. sourceURL = tempPath
  1935. }
  1936. } catch {
  1937. }
  1938. } else {
  1939. sourceURL = Bundle.resourceBundle(for: Nexilis.self).url(forResource: nameSound, withExtension: "mp3")
  1940. if sourceURL == nil {
  1941. sourceURL = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: nameSound, withExtension: "mp3")
  1942. }
  1943. }
  1944. }
  1945. } else {
  1946. sourceURL = Bundle.resourceBundle(for: Nexilis.self).url(forResource: nameSound, withExtension: "mp3")
  1947. if sourceURL == nil {
  1948. sourceURL = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: nameSound, withExtension: "mp3")
  1949. }
  1950. }
  1951. if sourceURL == nil {
  1952. return
  1953. }
  1954. let fileManager = FileManager.default
  1955. let soundDirectory = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!.appendingPathComponent("Sounds", isDirectory: true)
  1956. if !fileManager.fileExists(atPath: soundDirectory.path) {
  1957. do {
  1958. try fileManager.createDirectory(at: soundDirectory, withIntermediateDirectories: true, attributes: nil)
  1959. } catch {
  1960. print("Error creating Sounds directory: \(error)")
  1961. return
  1962. }
  1963. }
  1964. let destinationURL = soundDirectory.appendingPathComponent("\(nameSound).mp3")
  1965. if !fileManager.fileExists(atPath: destinationURL.path) {
  1966. do {
  1967. try fileManager.copyItem(at: sourceURL!, to: destinationURL)
  1968. } catch {
  1969. }
  1970. }
  1971. }
  1972. public static func openNotificationNexilis(_ response: UNNotificationResponse) {
  1973. DispatchQueue.main.async{
  1974. if let userInfo = response.notification.request.content.userInfo as? [String: String] {
  1975. let id = userInfo["id"] ?? ""
  1976. let type = userInfo["type"] ?? ""
  1977. let callType = userInfo["callType"] ?? ""
  1978. if let navigationC = UIApplication.shared.visibleViewController as? UINavigationController {
  1979. if navigationC.viewControllers[navigationC.viewControllers.count - 1] is EditorPersonal || navigationC.viewControllers[navigationC.viewControllers.count - 1] is EditorGroup {
  1980. navigationC.popViewController(animated: true)
  1981. }
  1982. }
  1983. showEditorOrCallFromAPN(id, type, callType)
  1984. } else {
  1985. let userInfo = response.notification.request.content.userInfo
  1986. DispatchQueue.main.async {
  1987. if let message_id = userInfo[CoreMessage_TMessageKey.MESSAGE_ID] as? String {
  1988. var f_pin = ""
  1989. var l_pin = ""
  1990. var message_scope_id = ""
  1991. var pin = ""
  1992. var chat_id = ""
  1993. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  1994. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select f_pin, l_pin, message_scope_id, chat_id from MESSAGE where message_id = '\(message_id)'"), cursor.next() {
  1995. f_pin = cursor.string(forColumnIndex: 0) ?? ""
  1996. l_pin = cursor.string(forColumnIndex: 1) ?? ""
  1997. message_scope_id = cursor.string(forColumnIndex: 2) ?? ""
  1998. chat_id = cursor.string(forColumnIndex: 3) ?? ""
  1999. pin = f_pin == User.getMyPin() ? l_pin : f_pin
  2000. if message_scope_id == "4" {
  2001. pin = chat_id.isEmpty ? l_pin : chat_id
  2002. }
  2003. cursor.close()
  2004. }
  2005. })
  2006. if let navigationC = UIApplication.shared.visibleViewController as? UINavigationController {
  2007. if navigationC.viewControllers[navigationC.viewControllers.count - 1] is EditorPersonal || navigationC.viewControllers[navigationC.viewControllers.count - 1] is EditorGroup {
  2008. navigationC.popViewController(animated: false)
  2009. }
  2010. }
  2011. showEditorOrCallFromAPN(pin, message_scope_id == "4" ? "1" : !message_scope_id.isEmpty ? "0" : "", "CL01")
  2012. }
  2013. }
  2014. }
  2015. }
  2016. // UNUserNotificationCenter.current().removeAllDeliveredNotifications()
  2017. }
  2018. private static func showEditorOrCallFromAPN(_ id: String, _ type: String, _ callType: String) {
  2019. if type.isEmpty {
  2020. return
  2021. }
  2022. if type == "0" {
  2023. if User.getDataCanNil(pin: id) == nil && id != "-999" && id != "-997" {
  2024. return
  2025. }
  2026. let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
  2027. editorPersonalVC.hidesBottomBarWhenPushed = true
  2028. editorPersonalVC.unique_l_pin = id
  2029. editorPersonalVC.fromNotification = true
  2030. let navigationController = CustomNavigationController(rootViewController: editorPersonalVC)
  2031. navigationController.modalPresentationStyle = .fullScreen
  2032. navigationController.navigationBar.tintColor = .white
  2033. navigationController.navigationBar.barTintColor = UIApplication.shared.visibleViewController?.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  2034. navigationController.navigationBar.isTranslucent = false
  2035. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  2036. navigationController.navigationBar.barStyle = .black
  2037. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  2038. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  2039. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  2040. navigationController.navigationBar.titleTextAttributes = textAttributes
  2041. if UIApplication.shared.visibleViewController is UINavigationController && Nexilis.fromMAB {
  2042. editorPersonalVC.fromNotification = false
  2043. UIApplication.shared.visibleViewController?.show(editorPersonalVC, sender: nil)
  2044. } else {
  2045. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  2046. }
  2047. } else if type == "1" {
  2048. var groupExist = false
  2049. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  2050. var idGroup = ""
  2051. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "SELECT title, group_id FROM DISCUSSION_FORUM WHERE chat_id='\(id)'"), cursor.next() {
  2052. groupExist = true
  2053. cursor.close()
  2054. } else {
  2055. if idGroup.isEmpty {
  2056. idGroup = id
  2057. }
  2058. if let cursorGroup = Database.shared.getRecords(fmdb: fmdb, query: "SELECT f_name, image_id FROM GROUPZ WHERE group_id='\(idGroup)'"), cursorGroup.next() {
  2059. groupExist = true
  2060. cursorGroup.close()
  2061. }
  2062. }
  2063. })
  2064. if !groupExist {
  2065. return
  2066. }
  2067. let editorGroupVC = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "editorGroupVC") as! EditorGroup
  2068. editorGroupVC.hidesBottomBarWhenPushed = true
  2069. editorGroupVC.unique_l_pin = id
  2070. editorGroupVC.fromNotification = true
  2071. let navigationController = CustomNavigationController(rootViewController: editorGroupVC)
  2072. navigationController.modalPresentationStyle = .fullScreen
  2073. navigationController.navigationBar.tintColor = .white
  2074. navigationController.navigationBar.barTintColor = UIApplication.shared.visibleViewController?.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  2075. navigationController.navigationBar.isTranslucent = false
  2076. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  2077. navigationController.navigationBar.barStyle = .black
  2078. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  2079. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  2080. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  2081. navigationController.navigationBar.titleTextAttributes = textAttributes
  2082. if UIApplication.shared.visibleViewController is UINavigationController && Nexilis.fromMAB {
  2083. editorGroupVC.fromNotification = false
  2084. UIApplication.shared.visibleViewController?.show(editorGroupVC, sender: nil)
  2085. } else {
  2086. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  2087. }
  2088. } else if type == "CL03" {
  2089. Nexilis.stopRingtoneCall()
  2090. if !Nexilis.callAPNActivated {
  2091. return
  2092. }
  2093. if callType == "1" {
  2094. if let user = User.getData(pin: id), user.firstName == "User".localized() {
  2095. return
  2096. }
  2097. let controller = QmeraAudioViewController()
  2098. controller.isOutgoing = false
  2099. controller.user = User.getData(pin: id)
  2100. controller.autoAcceptAPN = true
  2101. controller.modalPresentationStyle = .overCurrentContext
  2102. if UIApplication.shared.visibleViewController is UIAlertController {
  2103. let vc = UIApplication.shared.visibleViewController as! UIAlertController
  2104. vc.dismiss(animated: true, completion: {
  2105. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2106. UIApplication.shared.visibleViewController?.navigationController?.present(controller, animated: true, completion: nil)
  2107. } else {
  2108. UIApplication.shared.visibleViewController?.present(controller, animated: true, completion: nil)
  2109. }
  2110. })
  2111. return
  2112. }
  2113. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2114. UIApplication.shared.visibleViewController?.navigationController?.present(controller, animated: true, completion: nil)
  2115. } else {
  2116. UIApplication.shared.visibleViewController?.present(controller, animated: true, completion: nil)
  2117. }
  2118. } else {
  2119. if let user = User.getData(pin: id), user.firstName == "User".localized() {
  2120. return
  2121. }
  2122. let videoController = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "videoVCQmera") as! QmeraVideoViewController
  2123. videoController.fPin = id
  2124. videoController.isInisiator = false
  2125. videoController.autoAcceptAPN = true
  2126. let navigationController = CustomNavigationController(rootViewController: videoController)
  2127. navigationController.modalPresentationStyle = .fullScreen
  2128. if UIApplication.shared.visibleViewController is UIAlertController {
  2129. let vc = UIApplication.shared.visibleViewController as! UIAlertController
  2130. vc.dismiss(animated: true, completion: {
  2131. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2132. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  2133. } else {
  2134. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  2135. }
  2136. })
  2137. return
  2138. }
  2139. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2140. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
  2141. } else {
  2142. UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
  2143. }
  2144. }
  2145. }
  2146. }
  2147. // public static func checkClone(window: inout UIWindow?) {
  2148. // CloneCheck.enforceAllChecks(window: &window)
  2149. // }
  2150. public static func checkAppStateisBackground() -> Bool {
  2151. let state = UIApplication.shared.applicationState
  2152. switch state {
  2153. case .active:
  2154. return false
  2155. case .inactive:
  2156. return false
  2157. case .background:
  2158. return true
  2159. @unknown default:
  2160. return false
  2161. }
  2162. }
  2163. public static func enterBackground() {
  2164. // if !API.bAVisOngoing() {
  2165. // API.deinitConnection()
  2166. // }
  2167. notifTimer.invalidate()
  2168. stopNotif = true
  2169. if Utils.getSecureFolderOffline() == "0" {
  2170. Database.shared.database = nil
  2171. FileEncryption.shared.aesKey = nil
  2172. FileEncryption.shared.aesIV = nil
  2173. }
  2174. FloatingButton.datePull = nil
  2175. }
  2176. public static var notifTimer = Timer()
  2177. public static var stopNotif = false
  2178. public static var afterEnterBackground = false
  2179. public static func enterForeground() {
  2180. APIS.checkNotificationPermission(completion: { isAllowed in
  2181. if !isAllowed {
  2182. showEnableNotificationsAlert()
  2183. } else {
  2184. UIApplication.shared.registerForRemoteNotifications()
  2185. }
  2186. })
  2187. DispatchQueue.main.async {
  2188. stopNotif = true
  2189. self.notifTimer = Timer.scheduledTimer(withTimeInterval: 30, repeats: false) { _ in
  2190. stopNotif = false
  2191. }
  2192. if !Utils.isHSAMode() && !Utils.isMiddleMode(){
  2193. _ = Nexilis.justInit(isChecking: true)
  2194. }
  2195. }
  2196. checkDataForShareExtension()
  2197. UIApplication.shared.applicationIconBadgeNumber = 0
  2198. UNUserNotificationCenter.current().removeAllDeliveredNotifications()
  2199. if Utils.getSecureFolderOffline() == "0" && afterEnterBackground && Database.shared.database == nil && Utils.getSetProfile() && !Utils.isHSAMode() {
  2200. Database.recreateInstance()
  2201. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "disconnected_nexilis"), object: nil, userInfo: nil)
  2202. if let navigationC = UIApplication.shared.visibleViewController as? UINavigationController {
  2203. if navigationC.viewControllers[navigationC.viewControllers.count - 1] is EditorPersonal || navigationC.viewControllers[navigationC.viewControllers.count - 1] is EditorGroup {
  2204. navigationC.popViewController(animated: true)
  2205. }
  2206. }
  2207. // Nexilis.getFeatureAccessWithKey(key: ["secure_folder_encrypt_key", "secure_folder_encrypt_iv", "secure_folder_offline"])
  2208. Nexilis.getFeatureAccess()
  2209. }
  2210. if (FloatingButton.datePull == nil || !afterEnterBackground) && Utils.getSetProfile() {
  2211. DispatchQueue.global().async {
  2212. while API.nGetCLXConnState() == 0 || User.getMyPin() == nil {
  2213. Thread.sleep(forTimeInterval: 0.5)
  2214. }
  2215. if let vers = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.checkVersion()) {
  2216. let dataVersion = vers.getBody(key: CoreMessage_TMessageKey.DATA)
  2217. let type = vers.getBody(key: CoreMessage_TMessageKey.TYPE)
  2218. if dataVersion != "1" {
  2219. DispatchQueue.main.async {
  2220. showExpiredVersion(mandatory: type == "1")
  2221. }
  2222. }
  2223. }
  2224. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "checkNewMessagesNexilis"), object: nil, userInfo: nil)
  2225. }
  2226. DispatchQueue.global(qos: .userInitiated).async {
  2227. if Utils.shouldRequestAuthentication() && Utils.getSetProfile() && (Utils.isMiddleMode() || Utils.isHSAMode()) && Nexilis.hasInit {
  2228. DispatchQueue.main.async {
  2229. var viewController = UIApplication.shared.windows.first?.rootViewController
  2230. var notNull = false
  2231. while !notNull {
  2232. viewController = UIApplication.shared.windows.first?.rootViewController
  2233. if viewController != nil {
  2234. notNull = true
  2235. }
  2236. }
  2237. Nexilis.showPassSignIn()
  2238. }
  2239. }
  2240. }
  2241. }
  2242. afterEnterBackground = true
  2243. }
  2244. public static func willEnterForeground() {
  2245. // if APIS.uuidCall != nil {
  2246. // CallManager.shared.endCall(uuid: APIS.uuidCall!) {
  2247. // APIS.uuidCall = nil
  2248. // }
  2249. // }
  2250. }
  2251. private static func checkNotificationPermission(completion: @escaping (Bool) -> Void) {
  2252. let center = UNUserNotificationCenter.current()
  2253. center.getNotificationSettings { settings in
  2254. DispatchQueue.main.async {
  2255. switch settings.authorizationStatus {
  2256. case .authorized, .provisional, .notDetermined:
  2257. completion(true) // Notifications are allowed
  2258. case .denied, .ephemeral:
  2259. completion(false) // Notifications are disabled or not requested
  2260. @unknown default:
  2261. completion(false)
  2262. }
  2263. }
  2264. }
  2265. }
  2266. public static func nexilisShowAlertWithHTMLMessage(on viewController: UIViewController, title: String, message: String = "<b>Bold</b> and <i>italic</i> text in an alert") {
  2267. let alert = UIAlertController(title: title, message: "", preferredStyle: .alert)
  2268. let titleFont = UIFont.boldSystemFont(ofSize: 16)
  2269. let titleAttributes = [NSAttributedString.Key.font: titleFont]
  2270. alert.setValue(NSAttributedString(string: title, attributes: titleAttributes), forKey: "attributedTitle")
  2271. var message = message
  2272. message = message.replacingOccurrences(of: "<b>", with: "*")
  2273. message = message.replacingOccurrences(of: "</b>", with: "*")
  2274. message = message.replacingOccurrences(of: "<i>", with: "_")
  2275. message = message.replacingOccurrences(of: "</i>", with: "_")
  2276. alert.setValue(message.richText(fontSize: 14), forKey: "attributedMessage")
  2277. alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
  2278. viewController.present(alert, animated: true, completion: nil)
  2279. }
  2280. static func showWarningFile(type: Int) {
  2281. alertControllerExpired = LibAlertController(
  2282. title: type == -1 ? "⚠️ Suspicious File Detected".localized() : "⚠️ Unrecognized File Type".localized(),
  2283. message: type == -1 ? "The file appears to have a mismatched name and extension, which may indicate a malicious file. Please verify the file’s source and format before uploading it.".localized() : "The selected item is not listed in the system dashboard.".localized(),
  2284. preferredStyle: .alert
  2285. )
  2286. alertControllerExpired.addAction(UIAlertAction(title: "OK".localized(), style: .default, handler: nil))
  2287. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2288. UIApplication.shared.visibleViewController?.navigationController?.present(alertControllerExpired, animated: true, completion: nil)
  2289. } else {
  2290. UIApplication.shared.visibleViewController?.present(alertControllerExpired, animated: true, completion: nil)
  2291. }
  2292. }
  2293. static func showMessageGuardFile(mime: String) {
  2294. alertControllerExpired = LibAlertController(
  2295. title: "⚠️ Message Guard Announcement".localized(),
  2296. message: mime == "image/jpeg" ? "Your image have been blocked by Message Guard. Please attach valid image.".localized() : "Your pdf file have been blocked by Message Guard. Please attach valid file.".localized() ,
  2297. preferredStyle: .alert
  2298. )
  2299. alertControllerExpired.addAction(UIAlertAction(title: "OK".localized(), style: .default, handler: nil))
  2300. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2301. UIApplication.shared.visibleViewController?.navigationController?.present(alertControllerExpired, animated: true, completion: nil)
  2302. } else {
  2303. UIApplication.shared.visibleViewController?.present(alertControllerExpired, animated: true, completion: nil)
  2304. }
  2305. }
  2306. private static func showEnableNotificationsAlert() {
  2307. guard !isAlertPresented else { return }
  2308. isAlertPresented = true
  2309. let alertController = LibAlertController(
  2310. title: "Enable Notification".localized(),
  2311. message: "To stay updated, please enable notification in the Settings.".localized(),
  2312. preferredStyle: .alert
  2313. )
  2314. alertController.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: { _ in
  2315. isAlertPresented = false
  2316. }))
  2317. alertController.addAction(UIAlertAction(title: "Go to Settings".localized(), style: .default, handler: { _ in
  2318. isAlertPresented = false
  2319. openAppSettings()
  2320. }))
  2321. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2322. UIApplication.shared.visibleViewController?.navigationController?.present(alertController, animated: true, completion: nil)
  2323. } else {
  2324. UIApplication.shared.visibleViewController?.present(alertController, animated: true, completion: nil)
  2325. }
  2326. }
  2327. static func showRestartApp() {
  2328. alertControllerExpired = LibAlertController(
  2329. title: "Restart Required".localized(),
  2330. message: "Oops! Something went wrong. Please restart the app to continue.".localized(),
  2331. preferredStyle: .alert
  2332. )
  2333. alertControllerExpired.addAction(UIAlertAction(title: "OK".localized(), style: .default, handler: { _ in
  2334. exit(0)
  2335. }))
  2336. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2337. UIApplication.shared.visibleViewController?.navigationController?.present(alertControllerExpired, animated: true, completion: nil)
  2338. } else {
  2339. UIApplication.shared.visibleViewController?.present(alertControllerExpired, animated: true, completion: nil)
  2340. }
  2341. }
  2342. private static var alertControllerExpired: LibAlertController!
  2343. public static func showExpiredVersion(mandatory: Bool) {
  2344. func showAl() {
  2345. alertControllerExpired = LibAlertController(
  2346. title: "Update Available".localized(),
  2347. message: "A new version is now available. Please update to the latest version to enjoy new features and important improvements.".localized(),
  2348. preferredStyle: .alert
  2349. )
  2350. if !mandatory {
  2351. alertControllerExpired.addAction(UIAlertAction(title: "Later".localized(), style: .cancel, handler: nil))
  2352. }
  2353. alertControllerExpired.addAction(UIAlertAction(title: "Update Now".localized(), style: .default, handler: { _ in
  2354. if APIS.appNm == "OneApp" {
  2355. let appStoreURL = URL(string: "https://apps.apple.com/app/id6741251571")!
  2356. UIApplication.shared.open(appStoreURL)
  2357. } else {
  2358. let appStoreURL = URL(string: "https://apps.apple.com/app/")!
  2359. UIApplication.shared.open(appStoreURL)
  2360. }
  2361. }))
  2362. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2363. UIApplication.shared.visibleViewController?.navigationController?.present(alertControllerExpired, animated: true, completion: nil)
  2364. } else {
  2365. UIApplication.shared.visibleViewController?.present(alertControllerExpired, animated: true, completion: nil)
  2366. }
  2367. }
  2368. if alertControllerExpired != nil {
  2369. alertControllerExpired.dismiss(animated: true) {
  2370. showAl()
  2371. }
  2372. } else {
  2373. showAl()
  2374. }
  2375. }
  2376. private static func openAppSettings() {
  2377. if let settingsURL = URL(string: UIApplication.openSettingsURLString) {
  2378. if UIApplication.shared.canOpenURL(settingsURL) {
  2379. UIApplication.shared.open(settingsURL, options: [:], completionHandler: nil)
  2380. }
  2381. }
  2382. }
  2383. public static func willTerminate() {
  2384. Nexilis.destroyAll()
  2385. }
  2386. private static var isCheckingDataForShare = false
  2387. public static func checkDataForShareExtension() {
  2388. DispatchQueue.global().async {
  2389. if let userDefaults = UserDefaults(suiteName: nameGroupShared) {
  2390. if let value = userDefaults.string(forKey: "sharedItem") {
  2391. if !value.isEmpty {
  2392. if isCheckingDataForShare {
  2393. return
  2394. }
  2395. isCheckingDataForShare = true
  2396. if let jsonData = value.data(using: .utf8) {
  2397. do {
  2398. if let json = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
  2399. let typeImage = 2
  2400. let typeVideo = 3
  2401. let typeFile = 4
  2402. let typeAudio = 5
  2403. let typeContact = json["typeContact"] as? String ?? "0"
  2404. var data = json["data"] as? String ?? ""
  2405. let idContact = json["idContact"] as? String ?? ""
  2406. let typeShare = json["typeShare"] as? Int ?? 1
  2407. var message = TMessage()
  2408. var groupId = ""
  2409. var chatId = ""
  2410. let scopeId = typeContact == "1" ? "4" : "3"
  2411. let thumb = json["thumb"] as? String ?? ""
  2412. let imageId = json["image"] as? String ?? ""
  2413. let videoId = json["video"] as? String ?? ""
  2414. let fileId = json["file"] as? String ?? ""
  2415. let audioId = json["audio"] as? String ?? ""
  2416. var renamedFileId = ""
  2417. var renamedAudioId = ""
  2418. var attachmentFlag = ""
  2419. if scopeId == "4" {
  2420. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  2421. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "SELECT group_id id FROM DISCUSSION_FORUM WHERE chat_id = '\(idContact)'"), cursor.next() {
  2422. groupId = cursor.string(forColumnIndex: 0) ?? ""
  2423. chatId = idContact
  2424. cursor.close()
  2425. } else {
  2426. groupId = idContact
  2427. }
  2428. })
  2429. }
  2430. if typeShare == typeImage {
  2431. attachmentFlag = "1"
  2432. if let appGroupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: nameGroupShared) {
  2433. let sharedImageURL = appGroupURL.appendingPathComponent(imageId)
  2434. let sharedThumbURL = appGroupURL.appendingPathComponent(thumb)
  2435. if Nexilis.checkingAccess(key: "content_inspection") {
  2436. DispatchQueue.main.async {
  2437. Nexilis.showLoader(text: "Scanning File...".localized())
  2438. }
  2439. let result = sharedImageURL.validateFile()
  2440. DispatchQueue.main.async {
  2441. Nexilis.hideLoader {
  2442. if result == 1 {
  2443. if copyData() {
  2444. sendIt()
  2445. }
  2446. } else {
  2447. APIS.showWarningFile(type: result)
  2448. resetPrefs()
  2449. }
  2450. }
  2451. }
  2452. } else {
  2453. if copyData() {
  2454. sendIt()
  2455. }
  2456. }
  2457. func copyData() -> Bool {
  2458. var dataSanitized: Data!
  2459. func sanitizeFile(sanitizeAction: (Data) -> MessageGuardLite.Result) -> Data? {
  2460. DispatchQueue.main.async {
  2461. Nexilis.showLoader(text: "Sanitizing your image (Message Guard)".localized())
  2462. }
  2463. let res = sanitizeAction(try! Data(contentsOf: sharedImageURL))
  2464. defer {
  2465. DispatchQueue.main.async { Nexilis.hideLoader {} }
  2466. }
  2467. if res.verdict == .block {
  2468. DispatchQueue.main.async {
  2469. Nexilis.hideLoader {
  2470. APIS.showMessageGuardFile(mime: res.mime)
  2471. }
  2472. }
  2473. return nil
  2474. }
  2475. return res.data ?? Data()
  2476. }
  2477. func processIt() {
  2478. do {
  2479. let documentDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
  2480. if FileManager.default.fileExists(atPath: sharedImageURL.path) {
  2481. let file = documentDir.appendingPathComponent(imageId)
  2482. if !FileManager().fileExists(atPath: file.path) {
  2483. if dataSanitized != nil {
  2484. let file = documentDir.appendingPathComponent(imageId)
  2485. try? dataSanitized.write(to: file)
  2486. } else {
  2487. try? FileManager.default.copyItem(at: sharedImageURL, to: file)
  2488. }
  2489. }
  2490. }
  2491. if FileManager.default.fileExists(atPath: sharedThumbURL.path) {
  2492. let file = documentDir.appendingPathComponent(thumb)
  2493. if !FileManager().fileExists(atPath: file.path) {
  2494. try? FileManager.default.copyItem(at: sharedThumbURL, to: file)
  2495. }
  2496. }
  2497. } catch {
  2498. }
  2499. }
  2500. if Nexilis.checkingAccess(key: "message_guard") {
  2501. DispatchQueue.global().async {
  2502. let guardLite = MessageGuardLite(limits: .defaults())
  2503. if let sanitized = sanitizeFile(sanitizeAction: guardLite.sanitizeImage) {
  2504. dataSanitized = sanitized
  2505. } else { return }
  2506. processIt()
  2507. sendIt()
  2508. }
  2509. return false
  2510. } else {
  2511. processIt()
  2512. return true
  2513. }
  2514. }
  2515. }
  2516. } else if typeShare == typeVideo {
  2517. attachmentFlag = "2"
  2518. if let appGroupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: nameGroupShared) {
  2519. let sharedVideoURL = appGroupURL.appendingPathComponent(videoId)
  2520. let sharedThumbURL = appGroupURL.appendingPathComponent(thumb)
  2521. if Nexilis.checkingAccess(key: "content_inspection") {
  2522. DispatchQueue.main.async {
  2523. Nexilis.showLoader(text: "Scanning File...".localized())
  2524. }
  2525. let result = sharedVideoURL.validateFile()
  2526. DispatchQueue.main.async {
  2527. Nexilis.hideLoader {
  2528. if result == 1 {
  2529. copyData()
  2530. sendIt()
  2531. } else {
  2532. APIS.showWarningFile(type: result)
  2533. resetPrefs()
  2534. }
  2535. }
  2536. }
  2537. } else {
  2538. copyData()
  2539. sendIt()
  2540. }
  2541. func copyData() {
  2542. do {
  2543. let documentDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
  2544. if FileManager.default.fileExists(atPath: sharedVideoURL.path) {
  2545. let file = documentDir.appendingPathComponent(videoId)
  2546. if !FileManager().fileExists(atPath: file.path) {
  2547. try? FileManager.default.copyItem(at: sharedVideoURL, to: file)
  2548. }
  2549. }
  2550. if FileManager.default.fileExists(atPath: sharedThumbURL.path) {
  2551. let file = documentDir.appendingPathComponent(thumb)
  2552. if !FileManager().fileExists(atPath: file.path) {
  2553. try? FileManager.default.copyItem(at: sharedThumbURL, to: file)
  2554. }
  2555. }
  2556. } catch {
  2557. }
  2558. }
  2559. }
  2560. } else if typeShare == typeFile {
  2561. attachmentFlag = "6"
  2562. if let appGroupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: nameGroupShared) {
  2563. renamedFileId = "Nexilis_\(Date().currentTimeMillis())_" + fileId
  2564. let sharedFileURL = appGroupURL.appendingPathComponent(fileId)
  2565. if Nexilis.checkingAccess(key: "content_inspection") {
  2566. DispatchQueue.main.async {
  2567. Nexilis.showLoader(text: "Scanning File...".localized())
  2568. }
  2569. let result = sharedFileURL.validateFile()
  2570. DispatchQueue.main.async {
  2571. Nexilis.hideLoader {
  2572. if result == 1 {
  2573. if copyData() {
  2574. sendIt()
  2575. }
  2576. } else {
  2577. APIS.showWarningFile(type: result)
  2578. resetPrefs()
  2579. }
  2580. }
  2581. }
  2582. } else {
  2583. if copyData() {
  2584. sendIt()
  2585. }
  2586. }
  2587. func copyData() -> Bool {
  2588. var dataSanitized: Data!
  2589. func sanitizeFile(sanitizeAction: (Data) -> MessageGuardLite.Result) -> Data? {
  2590. DispatchQueue.main.async {
  2591. Nexilis.showLoader(text: "Sanitizing your pdf file (Message Guard)".localized())
  2592. }
  2593. let res = sanitizeAction(try! Data(contentsOf: sharedFileURL))
  2594. defer {
  2595. DispatchQueue.main.async { Nexilis.hideLoader {} }
  2596. }
  2597. if res.verdict == .block {
  2598. DispatchQueue.main.async {
  2599. Nexilis.hideLoader {
  2600. APIS.showMessageGuardFile(mime: res.mime)
  2601. }
  2602. }
  2603. return nil
  2604. }
  2605. return res.data ?? Data()
  2606. }
  2607. func processIt() {
  2608. do {
  2609. let documentDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
  2610. if FileManager.default.fileExists(atPath: sharedFileURL.path) {
  2611. let file = documentDir.appendingPathComponent(renamedFileId)
  2612. if !FileManager().fileExists(atPath: file.path) {
  2613. if dataSanitized != nil {
  2614. let file = documentDir.appendingPathComponent(renamedFileId)
  2615. try? dataSanitized.write(to: file)
  2616. } else {
  2617. try? FileManager.default.copyItem(at: sharedFileURL, to: file)
  2618. }
  2619. }
  2620. }
  2621. data = "\(fileId)|\(data)"
  2622. } catch {
  2623. }
  2624. }
  2625. if Nexilis.checkingAccess(key: "message_guard") {
  2626. DispatchQueue.global().async {
  2627. let guardLite = MessageGuardLite(limits: .defaults())
  2628. let mimeType = MessageGuardLite.sniffMime(try! Data(contentsOf: sharedFileURL))
  2629. if mimeType == "application/pdf" {
  2630. if let sanitized = sanitizeFile(sanitizeAction: guardLite.sanitizePdf) {
  2631. dataSanitized = sanitized
  2632. } else { return }
  2633. }
  2634. processIt()
  2635. sendIt()
  2636. }
  2637. return false
  2638. } else {
  2639. processIt()
  2640. return true
  2641. }
  2642. }
  2643. }
  2644. } else if typeShare == typeAudio {
  2645. attachmentFlag = "5"
  2646. if let appGroupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: nameGroupShared) {
  2647. renamedAudioId = "Nexilis_\(Date().currentTimeMillis())_" + audioId
  2648. let sharedFileURL = appGroupURL.appendingPathComponent(audioId)
  2649. if Nexilis.checkingAccess(key: "content_inspection") {
  2650. DispatchQueue.main.async {
  2651. Nexilis.showLoader(text: "Scanning File...".localized())
  2652. }
  2653. let result = sharedFileURL.validateFile()
  2654. DispatchQueue.main.async {
  2655. Nexilis.hideLoader {
  2656. if result == 1 {
  2657. copyData()
  2658. sendIt()
  2659. } else {
  2660. APIS.showWarningFile(type: result)
  2661. resetPrefs()
  2662. }
  2663. }
  2664. }
  2665. } else {
  2666. copyData()
  2667. sendIt()
  2668. }
  2669. func copyData() {
  2670. do {
  2671. let documentDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
  2672. if FileManager.default.fileExists(atPath: sharedFileURL.path) {
  2673. let file = documentDir.appendingPathComponent(renamedAudioId)
  2674. if !FileManager().fileExists(atPath: file.path) {
  2675. try? FileManager.default.copyItem(at: sharedFileURL, to: file)
  2676. }
  2677. }
  2678. data = "\(audioId)|\(data)"
  2679. } catch {
  2680. }
  2681. }
  2682. }
  2683. } else {
  2684. sendIt()
  2685. }
  2686. func sendIt() {
  2687. message = CoreMessage_TMessageBank.sendMessage(l_pin: groupId.isEmpty ? idContact : groupId, message_scope_id: scopeId, status: scopeId == "3" ? "1" : "2", message_text: data, credential: "0", attachment_flag: attachmentFlag, ex_blog_id: "", message_large_text: "", ex_format: "", image_id: imageId, audio_id: renamedAudioId, video_id: videoId, file_id: renamedFileId, thumb_id: thumb, reff_id: "", read_receipts: "4", chat_id: chatId, is_call_center: "0", call_center_id: "", opposite_pin: scopeId == "3" ? (User.getMyPin() ?? "") : idContact, gif_id: "", isForwarded: "0", isSecret: "0", specFile: "")
  2688. Nexilis.addQueueMessage(message: message)
  2689. resetPrefs()
  2690. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
  2691. }
  2692. func resetPrefs() {
  2693. userDefaults.set("", forKey: "sharedItem")
  2694. userDefaults.synchronize()
  2695. isCheckingDataForShare = false
  2696. }
  2697. }
  2698. } catch {
  2699. print("Error parsing JSON: \(error)")
  2700. }
  2701. }
  2702. }
  2703. }
  2704. }
  2705. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
  2706. }
  2707. }
  2708. public static func setDataForShareExtension() {
  2709. DispatchQueue.global().async {
  2710. if let userDefaults = UserDefaults(suiteName: nameGroupShared) {
  2711. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  2712. var dataShared: [[String: Any]] = []
  2713. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "SELECT f_pin id, image_id image, first_name || ' ' || ifnull(last_name, '') name FROM BUDDY WHERE f_pin != '\(User.getMyPin() ?? "")' AND f_pin != '-997' AND official_account != '1'") {
  2714. while cursor.next() {
  2715. var dataTemp: [String: Any] = [:]
  2716. for columnIndex in 0..<cursor.columnCount {
  2717. if let columnName = cursor.columnName(for: columnIndex) {
  2718. if let value = cursor.object(forColumn: columnName) {
  2719. if columnName == "image" {
  2720. dataTemp[columnName] = value
  2721. if let imageString = dataTemp[columnName] as? String, !imageString.isEmpty {
  2722. do {
  2723. if FileEncryption.shared.isSecureExists(filename: imageString) {
  2724. if var data = try FileEncryption.shared.readSecure(filename: imageString) {
  2725. let dataDecrypt = FileEncryption.shared.decryptFileFromServer(data: data)
  2726. if dataDecrypt != nil {
  2727. data = dataDecrypt!
  2728. }
  2729. if let appGroupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: nameGroupShared) {
  2730. let sharedFileURL = appGroupURL.appendingPathComponent(imageString)
  2731. if !FileManager.default.fileExists(atPath: sharedFileURL.path) {
  2732. try? data.write(to: sharedFileURL)
  2733. }
  2734. }
  2735. }
  2736. }
  2737. } catch {
  2738. }
  2739. }
  2740. } else {
  2741. dataTemp[columnName] = value
  2742. }
  2743. dataTemp["type"] = 0
  2744. }
  2745. }
  2746. }
  2747. dataShared.append(dataTemp)
  2748. }
  2749. cursor.close()
  2750. }
  2751. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "SELECT group_id id, image_id image, f_name name FROM GROUPZ WHERE official != 1") {
  2752. while cursor.next() {
  2753. var dataTemp: [String: Any] = [:]
  2754. for columnIndex in 0..<cursor.columnCount {
  2755. if let columnName = cursor.columnName(for: columnIndex) {
  2756. if let value = cursor.object(forColumn: columnName) {
  2757. if columnName == "name" {
  2758. dataTemp[columnName] = "\(value) (Lounge)"
  2759. } else if columnName == "image" {
  2760. dataTemp[columnName] = value
  2761. if let imageString = dataTemp[columnName] as? String, !imageString.isEmpty {
  2762. do {
  2763. if FileEncryption.shared.isSecureExists(filename: imageString) {
  2764. if var data = try FileEncryption.shared.readSecure(filename: imageString) {
  2765. let dataDecrypt = FileEncryption.shared.decryptFileFromServer(data: data)
  2766. if dataDecrypt != nil {
  2767. data = dataDecrypt!
  2768. }
  2769. if let appGroupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: nameGroupShared) {
  2770. let sharedFileURL = appGroupURL.appendingPathComponent(imageString)
  2771. if !FileManager.default.fileExists(atPath: sharedFileURL.path) {
  2772. try? data.write(to: sharedFileURL)
  2773. }
  2774. }
  2775. }
  2776. }
  2777. } catch {
  2778. }
  2779. }
  2780. } else {
  2781. dataTemp[columnName] = value
  2782. }
  2783. dataTemp["type"] = 1
  2784. }
  2785. }
  2786. }
  2787. dataShared.append(dataTemp)
  2788. let group_id = cursor.string(forColumnIndex: 0) ?? ""
  2789. let image_group = cursor.string(forColumnIndex: 1) ?? ""
  2790. let name_group = cursor.string(forColumnIndex: 2) ?? ""
  2791. if let cursorTopic = Database.shared.getRecords(fmdb: fmdb, query: "SELECT chat_id id, thumb image, title name FROM DISCUSSION_FORUM WHERE group_id = '\(group_id)'") {
  2792. while cursorTopic.next() {
  2793. var dataTempTopic: [String: Any] = [:]
  2794. for columnIndex in 0..<cursorTopic.columnCount {
  2795. if let columnName = cursorTopic.columnName(for: columnIndex) {
  2796. if let value = cursorTopic.object(forColumn: columnName) {
  2797. if columnName == "name" {
  2798. dataTempTopic[columnName] = "\(name_group) (\(value))"
  2799. } else if columnName == "image" {
  2800. dataTempTopic[columnName] = "\(value)".isEmpty ? image_group : "\(value)"
  2801. if let imageString = dataTempTopic[columnName] as? String, !imageString.isEmpty {
  2802. do {
  2803. if FileEncryption.shared.isSecureExists(filename: imageString) {
  2804. if var data = try FileEncryption.shared.readSecure(filename: imageString) {
  2805. let dataDecrypt = FileEncryption.shared.decryptFileFromServer(data: data)
  2806. if dataDecrypt != nil {
  2807. data = dataDecrypt!
  2808. }
  2809. if let appGroupURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: nameGroupShared) {
  2810. let sharedFileURL = appGroupURL.appendingPathComponent(imageString)
  2811. if !FileManager.default.fileExists(atPath: sharedFileURL.path) {
  2812. try? data.write(to: sharedFileURL)
  2813. }
  2814. }
  2815. }
  2816. }
  2817. } catch {
  2818. }
  2819. }
  2820. } else {
  2821. dataTempTopic[columnName] = value
  2822. }
  2823. dataTempTopic["type"] = 1
  2824. }
  2825. }
  2826. }
  2827. dataShared.append(dataTempTopic)
  2828. }
  2829. cursorTopic.close()
  2830. }
  2831. }
  2832. cursor.close()
  2833. }
  2834. do {
  2835. let jsonData = try JSONSerialization.data(withJSONObject: dataShared, options: .prettyPrinted)
  2836. if let jsonString = String(data: jsonData, encoding: .utf8) {
  2837. userDefaults.set(jsonString, forKey: "shareContacts")
  2838. userDefaults.synchronize()
  2839. }
  2840. } catch {
  2841. print("Error converting to JSON: \(error)")
  2842. }
  2843. })
  2844. }
  2845. }
  2846. }
  2847. public static func setCheckEmulator(isActive: Bool) {
  2848. // Utils.bCheckEmulator = isActive
  2849. }
  2850. public static func setCheckRootedDevice(isActive: Bool) {
  2851. // Utils.bCheckRooted = isActive
  2852. }
  2853. public static func setPreventScreenCapture(isActive: Bool) {
  2854. // Utils.bPreventScreenCapture = isActive
  2855. }
  2856. public static func setNameGroupShare(_ name: String) {
  2857. nameGroupShared = name
  2858. }
  2859. public static func openImageNexilis(imageView: UIImageView, data: Data? = nil, isGIF: Bool = false) {
  2860. let image = UIImage(data: data ?? Data())
  2861. let imageViewer = MediaViewerViewController()
  2862. if !isGIF {
  2863. imageViewer.media = .image(image ?? UIImage())
  2864. } else {
  2865. imageViewer.media = .gif(UIImage.gifImageWithData(data ?? Data()) ?? UIImage())
  2866. }
  2867. let navigationController = UINavigationController(rootViewController: imageViewer)
  2868. navigationController.defaultStyle()
  2869. navigationController.view.backgroundColor = .clear
  2870. navigationController.modalPresentationCapturesStatusBarAppearance = true
  2871. navigationController.modalPresentationStyle = .overFullScreen
  2872. let backAction = UIAction { _ in
  2873. navigationController.dismiss(animated: true)
  2874. }
  2875. let backButton = UIBarButtonItem(title: nil, image: UIImage(systemName: "chevron.backward"), primaryAction: backAction, menu: nil)
  2876. imageViewer.navigationItem.leftBarButtonItem = backButton
  2877. let name = ""
  2878. imageViewer.title = name
  2879. let transitionDelegate = ZoomTransitioningDelegate()
  2880. transitionDelegate.originImageView = imageView
  2881. navigationController.transitioningDelegate = transitionDelegate
  2882. self.transitioningDelegateRef = transitionDelegate
  2883. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2884. UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true) {
  2885. imageViewer.animateBackgroundIn()
  2886. }
  2887. } else {
  2888. UIApplication.shared.visibleViewController?.present(navigationController, animated: true) {
  2889. imageViewer.animateBackgroundIn()
  2890. }
  2891. }
  2892. }
  2893. public static func openVideoNexilis(videoURL: URL) {
  2894. let player = AVPlayer(url: videoURL)
  2895. let playerVC = AVPlayerViewController()
  2896. playerVC.modalPresentationStyle = .custom
  2897. playerVC.player = player
  2898. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2899. UIApplication.shared.visibleViewController?.navigationController?.present(playerVC, animated: true, completion: nil)
  2900. } else {
  2901. UIApplication.shared.visibleViewController?.present(playerVC, animated: true, completion: nil)
  2902. }
  2903. }
  2904. public static func setAppMode(mode: Int) {
  2905. Utils.selectedAppMode = mode
  2906. }
  2907. public static func checkSignMethod() -> (Int, Int) {
  2908. var countMethod = 0
  2909. var typeMethod = 0
  2910. if Nexilis.checkingAccess(key: "sign_in_up_msisdn") {
  2911. countMethod+=1
  2912. typeMethod = 0
  2913. }
  2914. if Nexilis.checkingAccess(key: "sign_in_up_email") {
  2915. countMethod+=1
  2916. typeMethod = 1
  2917. }
  2918. if Nexilis.checkingAccess(key: "sign_in_up_username") {
  2919. countMethod+=1
  2920. typeMethod = 2
  2921. }
  2922. return (countMethod,typeMethod)
  2923. }
  2924. public static func getControllerSign(forceSignIn: Bool = false) -> UIViewController? {
  2925. let data = APIS.checkSignMethod()
  2926. let count = data.0
  2927. let type = data.1
  2928. if count > 0 {
  2929. var controller: UIViewController!
  2930. if count == 1 {
  2931. if forceSignIn {
  2932. let vc = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "changeDevice") as! ChangeDeviceViewController
  2933. if type == 0 {
  2934. vc.isMSISDN = true
  2935. controller = vc
  2936. } else if type == 1 {
  2937. vc.isEmail = true
  2938. }
  2939. controller = vc
  2940. } else {
  2941. let vc = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "signupsignin") as! SignUpSignIn
  2942. if type == 0 {
  2943. vc.isMSISDN = true
  2944. controller = vc
  2945. } else if type == 1 {
  2946. vc.isEmail = true
  2947. }
  2948. controller = vc
  2949. }
  2950. } else {
  2951. let vc = SignInOption()
  2952. vc.forceSignIn = forceSignIn
  2953. controller = vc
  2954. }
  2955. return controller
  2956. }
  2957. return nil
  2958. }
  2959. public static func monitoredActivity() {
  2960. UIViewController.swizzleViewDidAppearImplementation
  2961. UINavigationController.swizzlePushViewControllerImplementation
  2962. UINavigationController.swizzlePopViewControllerImplementation
  2963. _ = DataCaptured()
  2964. UIApplication.swizzleSendAction
  2965. }
  2966. private static var appNm = "";
  2967. public static func getAppNm() -> String {
  2968. return appNm
  2969. }
  2970. private static var nameGroupShared = "group.nexilis.share";
  2971. public static func getnameGroupShared() -> String {
  2972. return nameGroupShared
  2973. }
  2974. public static func openQris() {
  2975. let scannerVC = QRScannerViewController()
  2976. scannerVC.modalPresentationStyle = .fullScreen
  2977. if UIApplication.shared.visibleViewController?.navigationController != nil {
  2978. UIApplication.shared.visibleViewController?.navigationController?.present(scannerVC, animated: true, completion: nil)
  2979. } else {
  2980. UIApplication.shared.visibleViewController?.present(scannerVC, animated: true, completion: nil)
  2981. }
  2982. }
  2983. }
  2984. extension UINavigationController {
  2985. func defaultStyle() {
  2986. self.view.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .black : .white
  2987. self.modalPresentationStyle = .fullScreen
  2988. self.navigationBar.tintColor = .white
  2989. self.navigationBar.barTintColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  2990. self.navigationBar.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
  2991. self.navigationBar.isTranslucent = false
  2992. self.navigationBar.overrideUserInterfaceStyle = .dark
  2993. self.navigationBar.barStyle = .black
  2994. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  2995. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  2996. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  2997. self.navigationBar.titleTextAttributes = textAttributes
  2998. }
  2999. }