Utils.swift 181 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137
  1. //
  2. // Utils.swift
  3. // Runner
  4. //
  5. // Created by Rifqy Fakhrul Rijal on 13/08/20.
  6. // Copyright © 2020 The Chromium Authors. All rights reserved.
  7. //
  8. import Foundation
  9. import UIKit
  10. import NotificationBannerSwift
  11. import nuSDKService
  12. import CoreLocation
  13. import CryptoKit
  14. import LocalAuthentication
  15. import AVFoundation
  16. import PDFKit
  17. //import var CommonCrypto.CC_MD5_DIGEST_LENGTH
  18. //import func CommonCrypto.CC_MD5
  19. //import typealias CommonCrypto.CC_LONG
  20. public final class Utils {
  21. public static let M_USER_ANDROID_ID = "UNK"
  22. public static let CPAAS_VERSION = "UCPaaS-Nexilis.\(Nexilis.cpaasVersion)"
  23. public static func getCurrentTime()->Int64 {
  24. return Int64(Date().timeIntervalSince1970)
  25. }
  26. public static func getCurrentTimeMillis()->Int64 {
  27. return Int64(Date().timeIntervalSince1970 * 1000)
  28. }
  29. public static func getCurrentTimeNanos()->Int64 {
  30. return Int64(Date().timeIntervalSince1970 * 1000_000_000)
  31. }
  32. public static func getElapsedRealtime() -> Int64 {
  33. return Int64((ProcessInfo().systemUptime).rounded()) // SystemClock.elapsedRealtime();
  34. }
  35. public static func getElapsedRealtimeMillis() -> Int64 {
  36. return Int64((ProcessInfo().systemUptime * 1000).rounded()) // SystemClock.elapsedRealtime();
  37. }
  38. public static func getElapsedRealtimeNanos() -> Int64 {
  39. return Int64((ProcessInfo().systemUptime * 1000_000_000).rounded()) // SystemClock.elapsedRealtimeNano();
  40. }
  41. public static func getForceAnonymous() -> Bool {
  42. if let value: Bool = SecureUserDefaults.shared.value(forKey: "force_anonymous") {
  43. return value
  44. }
  45. return false
  46. }
  47. public static func setForceAnonymous(value: Bool){
  48. SecureUserDefaults.shared.set(value, forKey: "force_anonymous")
  49. }
  50. public static func getSetProfile() -> Bool {
  51. if let value: Bool = SecureUserDefaults.shared.value(forKey: "is_change_profile") {
  52. return value
  53. }
  54. return false
  55. }
  56. public static func setProfile(value: Bool){
  57. SecureUserDefaults.shared.set(value, forKey: "is_change_profile")
  58. }
  59. static func setIconCenter(value: String){
  60. SecureUserDefaults.shared.set(value, forKey: "pb_fb_icon_center_self")
  61. }
  62. static func getIconCenter() -> String {
  63. if let value: String = SecureUserDefaults.shared.value(forKey: "pb_fb_icon_center_self") {
  64. return value
  65. }
  66. return ""
  67. }
  68. static func setIconCenterAnim2(value: String){
  69. SecureUserDefaults.shared.set(value, forKey: "pb_fb_icon_center_self_mode2")
  70. }
  71. static func getIconCenterAnim2() -> String {
  72. if let value: String = SecureUserDefaults.shared.value(forKey: "pb_fb_icon_center_self_mode2") {
  73. return value
  74. }
  75. return ""
  76. }
  77. static func setIconCenterAnim4(value: String){
  78. SecureUserDefaults.shared.set(value, forKey: "pb_fb_icon_center_self_mode4")
  79. }
  80. static func getIconCenterAnim4() -> String {
  81. if let value: String = SecureUserDefaults.shared.value(forKey: "pb_fb_icon_center_self_mode4") {
  82. return value
  83. }
  84. return ""
  85. }
  86. static func setURLFirstTab(value: String) {
  87. SecureUserDefaults.shared.set(value, forKey: "app_builder_url_first_tab")
  88. }
  89. static func setURLThirdTab(value: String) {
  90. SecureUserDefaults.shared.set(value, forKey: "app_builder_url_third_tab")
  91. }
  92. static func setURLStatusUpdate(value: String) {
  93. SecureUserDefaults.shared.set(value, forKey: "app_builder_url_status_update")
  94. }
  95. static func setURLBase(value: String) {
  96. SecureUserDefaults.shared.set(value, forKey: "app_builder_url_base")
  97. }
  98. static func setURLQMS(value: String) {
  99. SecureUserDefaults.shared.set(value, forKey: "app_builder_url_qms")
  100. }
  101. static func setIconDock(value: String) {
  102. SecureUserDefaults.shared.set(value, forKey: "app_builder_icon_dock")
  103. }
  104. static func setIconSS(value: String) {
  105. SecureUserDefaults.shared.set(value, forKey: "app_builder_icon_ss")
  106. }
  107. static func setBackground(value: String) {
  108. SecureUserDefaults.shared.set(value, forKey: "app_builder_background")
  109. }
  110. static func setURLPrivacyPolicy(value: String){
  111. SecureUserDefaults.shared.set(value, forKey: "app_builder_url_privacy_policy")
  112. }
  113. static func setEnablePrivacyPolicy(value: Bool){
  114. SecureUserDefaults.shared.set(value, forKey: "app_builder_enable_privacy_policy")
  115. }
  116. static func setCustomTab(cust: String){
  117. SecureUserDefaults.shared.set(cust, forKey: "custom_tab")
  118. }
  119. static func setACTheme(value: String){
  120. SecureUserDefaults.shared.set(value, forKey: "app_builder_ac_theme")
  121. }
  122. static func setButtonURL(value: String){
  123. SecureUserDefaults.shared.set(value, forKey: "app_builder_button_url")
  124. }
  125. static func setCustomButtons(value: String){
  126. SecureUserDefaults.shared.set(value, forKey: "app_builder_custom_buttons")
  127. }
  128. public static func getCustomButtons() -> String {
  129. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_custom_buttons") {
  130. return value
  131. }
  132. return ""
  133. }
  134. static func setCustomFBIcon(value: String){
  135. SecureUserDefaults.shared.set(value, forKey: "app_builder_button_icon")
  136. }
  137. static func getCustomFBIcon() -> String {
  138. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_button_icon") {
  139. return value
  140. }
  141. return ""
  142. }
  143. static func setEnableMobileBuilder(value: String){
  144. SecureUserDefaults.shared.set(value, forKey: "app_builder_enable_mobile_builder")
  145. }
  146. public static func getEnableMobileBuilder() -> String {
  147. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_enable_mobile_builder") {
  148. return value
  149. }
  150. return "0"
  151. }
  152. static func setFinishInitPrefs(value: Bool){
  153. SecureUserDefaults.shared.set(value, forKey: "finish_init_prefs")
  154. }
  155. public static func getFinishInitPrefsr() -> Bool {
  156. if let value: Bool = SecureUserDefaults.shared.value(forKey: "finish_init_prefs") {
  157. return value
  158. }
  159. return false
  160. }
  161. static func setConfigModeFB(value: String) {
  162. SecureUserDefaults.shared.set(value, forKey: "fb_config_mode")
  163. }
  164. static func getConfigModeFB() -> String {
  165. if let value: String = SecureUserDefaults.shared.value(forKey: "fb_config_mode") {
  166. return value
  167. }
  168. return "1"
  169. }
  170. static func setAfterConfigFB(value: Bool) {
  171. SecureUserDefaults.shared.set(value, forKey: "after_fb_config_mode")
  172. }
  173. static func getAfterConfigFB() -> Bool {
  174. if let value: Bool = SecureUserDefaults.shared.value(forKey: "after_fb_config_mode") {
  175. return value
  176. }
  177. return false
  178. }
  179. static func setCookiesMobile(value: String) {
  180. SecureUserDefaults.shared.set(value, forKey: "cookies_mobile")
  181. }
  182. public static func getCookiesMobile() -> String {
  183. if let value: String = SecureUserDefaults.shared.value(forKey: "cookies_mobile") {
  184. return value
  185. }
  186. return ""
  187. }
  188. static func setCookiesMobileForStorage(value: String) {
  189. SecureUserDefaults.shared.set(value, forKey: "cookies_mobile_storage")
  190. }
  191. public static func getCookiesMobileForStorage() -> String {
  192. if let value: String = SecureUserDefaults.shared.value(forKey: "cookies_mobile_storage") {
  193. return value
  194. }
  195. return ""
  196. }
  197. static func getBackground() -> String {
  198. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_background") {
  199. return value
  200. }
  201. return ""
  202. }
  203. static func setBackgroundLight(value: String) {
  204. SecureUserDefaults.shared.set(value, forKey: "app_builder_background_light")
  205. }
  206. static func getBackgroundLight() -> String {
  207. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_background_light") {
  208. return value
  209. }
  210. return ""
  211. }
  212. static func setBackgroundDark(value: String) {
  213. SecureUserDefaults.shared.set(value, forKey: "app_builder_background_dark")
  214. }
  215. static func getBackgroundDark() -> String {
  216. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_background_dark") {
  217. return value
  218. }
  219. return ""
  220. }
  221. static func setMaxRetryUpload(value: String) {
  222. SecureUserDefaults.shared.set(value, forKey: "max_retry_upload")
  223. }
  224. static func getMaxRetryUpload() -> String {
  225. if let value: String = SecureUserDefaults.shared.value(forKey: "max_retry_upload") {
  226. return value
  227. }
  228. return "5"
  229. }
  230. static func setAuthenticationDuration(value: String) {
  231. SecureUserDefaults.shared.set(value, forKey: "authentication_duration")
  232. }
  233. static func getAuthenticationDuration() -> String {
  234. if let value: String = SecureUserDefaults.shared.value(forKey: "authentication_duration") {
  235. return value
  236. }
  237. return "5"
  238. }
  239. static func setMaxRetryTimeUpload(value: String) {
  240. SecureUserDefaults.shared.set(value, forKey: "max_retry_time_upload")
  241. }
  242. static func getMaxRetryTimeUpload() -> String {
  243. if let value: String = SecureUserDefaults.shared.value(forKey: "max_retry_time_upload") {
  244. return value
  245. }
  246. return "60000"
  247. }
  248. static func setWhatsappCenter(value: String) {
  249. SecureUserDefaults.shared.set(value, forKey: "whatsapp_center")
  250. }
  251. static func getWhatsappCenter() -> String {
  252. if let value: String = SecureUserDefaults.shared.value(forKey: "whatsapp_center") {
  253. return value
  254. }
  255. return "08115881946"
  256. }
  257. static func setSMSCenter(value: String) {
  258. SecureUserDefaults.shared.set(value, forKey: "sms_center")
  259. }
  260. static func getSMSCenter() -> String {
  261. if let value: String = SecureUserDefaults.shared.value(forKey: "sms_center") {
  262. return value
  263. }
  264. return "081290009799"
  265. }
  266. static func setCallCenter(value: String) {
  267. SecureUserDefaults.shared.set(value, forKey: "call_center")
  268. }
  269. static func getCallCenter() -> String {
  270. if let value: String = SecureUserDefaults.shared.value(forKey: "call_center") {
  271. return value
  272. }
  273. return "1500046"
  274. }
  275. static func setValidTrans(value: String) {
  276. SecureUserDefaults.shared.set(value, forKey: "enable_valid_trans")
  277. }
  278. static func getValidTrans() -> String {
  279. if let value: String = SecureUserDefaults.shared.value(forKey: "enable_valid_trans") {
  280. return value
  281. }
  282. return "0"
  283. }
  284. static func setFeatureAccess(value: String) {
  285. SecureUserDefaults.shared.set(value, forKey: "pb_feature_access")
  286. }
  287. static func getFeatureAccess() -> String {
  288. if let value: String = SecureUserDefaults.shared.value(forKey: "pb_feature_access") {
  289. return value
  290. }
  291. return ""
  292. }
  293. static func setFeatureAccessAlert(value: String) {
  294. SecureUserDefaults.shared.set(value, forKey: "pb_feature_access_alert")
  295. }
  296. static func getFeatureAccessAlert() -> String {
  297. if let value: String = SecureUserDefaults.shared.value(forKey: "pb_feature_access_alert") {
  298. return value
  299. }
  300. return ""
  301. }
  302. static func setChatbotGreetings(value: String) {
  303. SecureUserDefaults.shared.set(value, forKey: "chatbot_greetings")
  304. }
  305. static func getChatbotGreetings() -> String {
  306. if let value: String = SecureUserDefaults.shared.value(forKey: "chatbot_greetings") {
  307. return value
  308. }
  309. return "Welcome..."
  310. }
  311. public static func sGetCurrentDateTime(sFormat: String!) -> String! {
  312. let todaysDate = NSDate()
  313. let dateFormatter = DateFormatter()
  314. dateFormatter.dateFormat = sFormat
  315. return dateFormatter.string(from: todaysDate as Date)
  316. }
  317. public static func setCertificatePinningWebview(value: String) {
  318. SecureUserDefaults.shared.set(value, forKey: "pb_certificate_pinning_webview")
  319. }
  320. public static func getCertificatePinningWebview() -> String {
  321. if let value: String = SecureUserDefaults.shared.value(forKey: "pb_certificate_pinning_webview") {
  322. return value
  323. }
  324. return ""
  325. }
  326. public static func setWhitelistFileExt(value: String) {
  327. SecureUserDefaults.shared.set(value, forKey: "pb_whitelist_file_ext")
  328. }
  329. public static func getWhitelistFileExt() -> String {
  330. if let value: String = SecureUserDefaults.shared.value(forKey: "pb_whitelist_file_ext") {
  331. return value
  332. }
  333. return ""
  334. }
  335. public static func setUserMSISDN(value: String) {
  336. SecureUserDefaults.shared.set(value, forKey: "pb_user_msisdn")
  337. }
  338. public static func getUserMSISDN() -> String {
  339. if let value: String = SecureUserDefaults.shared.value(forKey: "pb_user_msisdn") {
  340. return value
  341. }
  342. return ""
  343. }
  344. // public static func getMD5(string: String) -> Data {
  345. // let length = Int(CC_MD5_DIGEST_LENGTH)
  346. // let messageData = string.data(using:.utf8)!
  347. // var digestData = Data(count: length)
  348. //
  349. // _ = digestData.withUnsafeMutableBytes { digestBytes -> UInt8 in
  350. // messageData.withUnsafeBytes { messageBytes -> UInt8 in
  351. // if let messageBytesBaseAddress = messageBytes.baseAddress, let digestBytesBlindMemory = digestBytes.bindMemory(to: UInt8.self).baseAddress {
  352. // let messageLength = CC_LONG(messageData.count)
  353. // CC_MD5(messageBytesBaseAddress, messageLength, digestBytesBlindMemory)
  354. // }
  355. // return 0
  356. // }
  357. // }
  358. // return digestData
  359. // }
  360. public static let callDurationFormatter: DateComponentsFormatter = {
  361. let dateFormatter: DateComponentsFormatter
  362. dateFormatter = DateComponentsFormatter()
  363. dateFormatter.unitsStyle = .positional
  364. dateFormatter.allowedUnits = [.minute, .second]
  365. dateFormatter.zeroFormattingBehavior = .pad
  366. return dateFormatter
  367. }()
  368. static func getGreetingsTimeDefaultWelcome() -> String {
  369. let calendar = Calendar.current
  370. let hour = calendar.component(.hour, from: Date())
  371. let minute = calendar.component(.minute, from: Date())
  372. var time: String
  373. if hour < 10 || (hour == 10 && minute <= 0) {
  374. time = "1"
  375. } else if hour < 15 || (hour == 15 && minute <= 0) {
  376. time = "2"
  377. } else {
  378. time = "3"
  379. }
  380. return time
  381. }
  382. public static func previewMessageText(chat: Chat) -> Any {
  383. if chat.credential == "1" && chat.lock == "2" {
  384. return ("🚫 _"+"Message has expired".localized()+"_").richText(group_id: chat.pin)
  385. } else if chat.messageScope == MessageScope.CALL || chat.messageScope == MessageScope.MISSED_CALL {
  386. let imageAttachment = NSTextAttachment()
  387. var stringImage = ""
  388. let isVideo = chat.messageText.lowercased().contains("video")
  389. let type = chat.messageText.lowercased().contains("incoming") ? "1" : chat.messageText.lowercased().contains("outgoing") ? "2" : "3"
  390. var textPreview = ""
  391. if isVideo && type == "2" {
  392. stringImage = "arrow.up.right.video.fill"
  393. textPreview = "Video call".localized()
  394. } else if !isVideo && type == "2" {
  395. stringImage = "phone.fill.arrow.up.right"
  396. textPreview = "Audio call".localized()
  397. } else if isVideo {
  398. stringImage = "arrow.down.left.video.fill"
  399. textPreview = type == "3" ? "Missed video call".localized() : "Video call".localized()
  400. } else {
  401. stringImage = "phone.fill.arrow.down.left"
  402. textPreview = type == "3" ? "Missed audio call".localized() : "Audio call".localized()
  403. }
  404. if let image = UIImage(systemName: stringImage)?.withRenderingMode(.alwaysTemplate) {
  405. let imageView = UIImageView(image: image)
  406. if type == "3" {
  407. imageView.tintColor = .red
  408. } else {
  409. imageView.tintColor = .gray
  410. }
  411. // Render the UIImageView to UIImage with tint applied
  412. UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, 0.0)
  413. imageView.layer.render(in: UIGraphicsGetCurrentContext()!)
  414. let tintedImage = UIGraphicsGetImageFromCurrentImageContext()
  415. UIGraphicsEndImageContext()
  416. imageAttachment.image = tintedImage
  417. }
  418. let imageSize = CGSize(width: 18, height: 18)
  419. imageAttachment.bounds = CGRect(x: 0, y: -2, width: isVideo ? imageSize.width + 8 : imageSize.width, height: imageSize.height)
  420. let imageString = NSAttributedString(attachment: imageAttachment)
  421. let textString = NSAttributedString(string: " " + textPreview, attributes: [
  422. .font: UIFont.systemFont(ofSize: 14),
  423. .foregroundColor: UIColor.gray
  424. ])
  425. let finalString = NSMutableAttributedString()
  426. finalString.append(imageString)
  427. finalString.append(textString)
  428. return finalString
  429. } else if chat.credential == "1" {
  430. return showNSMutableAttributedString("Confidential Message".localized())
  431. } else if chat.attachmentFlag == "27" {
  432. return showNSMutableAttributedString(("📄 " + "Live Streaming".localized()))
  433. } else if chat.attachmentFlag == "61" {
  434. let textName = chat.messageText.components(separatedBy: "~")[0]
  435. let textAfterName = chat.messageText.components(separatedBy: "~")[1]
  436. return (textName + " " + textAfterName.localized()).richText(group_id: chat.pin)
  437. } else if chat.attachmentFlag == "26" {
  438. return showNSMutableAttributedString(("📄 " + "Seminar".localized()))
  439. } else if chat.attachmentFlag == "25" {
  440. return showNSMutableAttributedString("📄 " + "Video Conference Room".localized())
  441. } else if !chat.audio.isEmpty {
  442. return showNSMutableAttributedString(("♫ " + "Audio".localized()))
  443. } else if !chat.image.isEmpty {
  444. if !chat.messageText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
  445. return "📷 \(chat.messageText)".richText(group_id: chat.pin)
  446. } else {
  447. return showNSMutableAttributedString(("📷 " + "Photo".localized()))
  448. }
  449. }
  450. else if !chat.gif.isEmpty {
  451. if !chat.messageText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
  452. return "🎬 \(chat.messageText)".richText(group_id: chat.pin)
  453. } else {
  454. return showNSMutableAttributedString("🎬 GIF")
  455. }
  456. }
  457. else if !chat.video.isEmpty {
  458. if !chat.messageText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
  459. return "📹 \(chat.messageText)".richText(group_id: chat.pin)
  460. } else {
  461. return showNSMutableAttributedString(("📹 " + "Video".localized()))
  462. }
  463. }
  464. else if !chat.file.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
  465. if chat.messageScope == "18" {
  466. return showNSMutableAttributedString(("📄 Form"))
  467. }
  468. let nameFile = chat.messageText.components(separatedBy: "|")[0]
  469. let dataText = chat.messageText.components(separatedBy: "|")[1]
  470. if !dataText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
  471. return ("📄 " + dataText).richText(group_id: chat.pin)
  472. }
  473. return showNSMutableAttributedString(("📄 \(nameFile)"))
  474. } else if chat.attachmentFlag == "11" {
  475. return showNSMutableAttributedString(("❤️ " + "Sticker".localized()))
  476. }
  477. else {
  478. return chat.messageText.richText(group_id: chat.pin)
  479. }
  480. }
  481. private static func showNSMutableAttributedString(_ text: String) -> NSMutableAttributedString {
  482. let font = UIFont.systemFont(ofSize: 12)
  483. return NSMutableAttributedString(string: text, attributes: [NSAttributedString.Key.font: font])
  484. }
  485. static func getURLBase() -> String {
  486. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_url_base") {
  487. return value
  488. }
  489. return "https://nexilis.io/"
  490. }
  491. public static func getIconDock() -> String {
  492. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_icon_dock") {
  493. return value
  494. }
  495. return ""
  496. }
  497. public static func getUrlDock() -> String? {
  498. return Utils.getURLBase() + "get_file_from_path?img=" + Utils.getIconDock()
  499. }
  500. static func setDefaultCC(value: String){
  501. SecureUserDefaults.shared.set(value, forKey: "default_cc")
  502. }
  503. static func getDefaultCC() -> String? {
  504. if let value: String = SecureUserDefaults.shared.value(forKey: "default_cc") {
  505. return value
  506. }
  507. return nil
  508. }
  509. static func setFloatingAnim(value: String){
  510. SecureUserDefaults.shared.set(value, forKey: "fb_floating_anim")
  511. }
  512. static func getFloatingAnim() -> String {
  513. if let value: String = SecureUserDefaults.shared.value(forKey: "fb_floating_anim") {
  514. return value
  515. }
  516. return "1~1"
  517. }
  518. static func setFBIconBg(value: String){
  519. SecureUserDefaults.shared.set(value, forKey: "fb_icon_with_bg")
  520. }
  521. static func getFBIconBg() -> String {
  522. if let value: String = SecureUserDefaults.shared.value(forKey: "fb_icon_with_bg") {
  523. return value
  524. }
  525. return "0"
  526. }
  527. static func setHistoryPullFB(value: String){
  528. SecureUserDefaults.shared.set(value, forKey: "history_pull_fb")
  529. }
  530. static func getHistoryPullFB() -> String {
  531. if let value: String = SecureUserDefaults.shared.value(forKey: "history_pull_fb") {
  532. return value
  533. }
  534. return ""
  535. }
  536. static func setFBItemBg(value: String){
  537. SecureUserDefaults.shared.set(value, forKey: "fb_item_with_bg")
  538. }
  539. static func getFBItemBg() -> String {
  540. if let value: String = SecureUserDefaults.shared.value(forKey: "fb_item_with_bg") {
  541. return value
  542. }
  543. return "1"
  544. }
  545. static func setBEId(value: String){
  546. SecureUserDefaults.shared.set(value, forKey: "be_id")
  547. }
  548. static func getBEId() -> String {
  549. if let value: String = SecureUserDefaults.shared.value(forKey: "be_id") {
  550. return value
  551. }
  552. return ""
  553. }
  554. static func setDomainOpr(value: String){
  555. SecureUserDefaults.shared.set(value, forKey: "domain_opr")
  556. }
  557. public static func getDomainOpr() -> String {
  558. if let value: String = SecureUserDefaults.shared.value(forKey: "domain_opr") {
  559. return value
  560. }
  561. return "https://nexilis.io/"
  562. }
  563. static func setIpPortOpr(value: String){
  564. SecureUserDefaults.shared.set(value, forKey: "ip_opr")
  565. }
  566. static func getIpOpr() -> String {
  567. if let value: String = SecureUserDefaults.shared.value(forKey: "ip_opr") {
  568. return value
  569. }
  570. return "34.101.172.194:42823"
  571. }
  572. static func setHarcodedIp(value: String){
  573. SecureUserDefaults.shared.set(value, forKey: "harcoded_ip")
  574. }
  575. static func getHarcodedIp() -> String {
  576. if let value: String = SecureUserDefaults.shared.value(forKey: "harcoded_ip") {
  577. return value
  578. }
  579. return ""
  580. }
  581. static func setUserAgent(value: String){
  582. SecureUserDefaults.shared.set(value, forKey: "user_agent")
  583. }
  584. public static func getUserAgent() -> String {
  585. if let value: String = SecureUserDefaults.shared.value(forKey: "user_agent") {
  586. return value
  587. }
  588. return "easySoftIndonesia"
  589. }
  590. public static func setSecureFolderEncrypt(value: String){
  591. SecureUserDefaults.shared.set(value, forKey: "secure_folder_encrypt_key")
  592. }
  593. public static func getSecureFolderEncrypt() -> String {
  594. if let value: String = SecureUserDefaults.shared.value(forKey: "secure_folder_encrypt_key") {
  595. return value
  596. }
  597. return ""
  598. }
  599. public static func setSecureFolderEncryptIv(value: String){
  600. SecureUserDefaults.shared.set(value, forKey: "secure_folder_encrypt_key_iv")
  601. }
  602. public static func getSecureFolderEncryptIv() -> String {
  603. if let value: String = SecureUserDefaults.shared.value(forKey: "secure_folder_encrypt_key_iv") {
  604. return value
  605. }
  606. return ""
  607. }
  608. public static func setSecureFolderOffline(value: String){
  609. SecureUserDefaults.shared.set(value, forKey: "secure_folder_offline")
  610. }
  611. public static func getSecureFolderOffline() -> String {
  612. if let value: String = SecureUserDefaults.shared.value(forKey: "secure_folder_offline") {
  613. return value
  614. }
  615. return "0"
  616. }
  617. public static func fetchDataWithCookiesAndUserAgent(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
  618. var request = URLRequest(url: url)
  619. request.httpMethod = "GET"
  620. request.setValue(Utils.getUserAgent(), forHTTPHeaderField: "User-Agent")
  621. request.setValue(Utils.getCookiesMobile(), forHTTPHeaderField: "Cookie")
  622. //print("DATA SEND MOBILE \(Utils.getUserAgent()) <> \(Utils.getCookiesMobile())")
  623. let urlConfig = URLSessionConfiguration.default
  624. urlConfig.timeoutIntervalForRequest = 30.0
  625. urlConfig.timeoutIntervalForResource = 60.0
  626. let sessionDelegate = SelfSignedURLSessionDelegate()
  627. let session = URLSession(configuration: urlConfig, delegate: sessionDelegate, delegateQueue: nil)
  628. let task = session.dataTask(with: request, completionHandler: completion)
  629. task.resume()
  630. }
  631. public static func postDataWithCookiesAndUserAgent(from url: URL, parameter: [String: Any] = [:], parameters: [[String: Any]] = [], isFormData: Bool = false, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
  632. let apiKey: String = SecureUserDefaults.shared.value(forKey: "apiKey") ?? ""
  633. var defaultParameter: [String : Any] = [
  634. "app_id": APIS.getAppNm(),
  635. "apikey": apiKey,
  636. ]
  637. if User.getMyPin() != nil {
  638. defaultParameter["f_pin"] = User.getMyPin()
  639. }
  640. var jsonArray: [[String: Any]] = []
  641. if parameters.count == 0 {
  642. jsonArray.append(defaultParameter)
  643. } else {
  644. jsonArray = parameters
  645. }
  646. var jsonData: Data!
  647. if !isFormData {
  648. jsonData = try? JSONSerialization.data(withJSONObject: parameter.count == 0 ? jsonArray : parameter, options: [])
  649. } else {
  650. let formData = parameter.map { "\($0.key)=\($0.value)" }.joined(separator: "&")
  651. jsonData = formData.data(using: .utf8)
  652. }
  653. var request = URLRequest(url: url)
  654. request.httpMethod = "POST"
  655. request.setValue(Utils.getUserAgent(), forHTTPHeaderField: "User-Agent")
  656. request.setValue(Utils.getCookiesMobile(), forHTTPHeaderField: "Cookie")
  657. if isFormData {
  658. request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
  659. } else {
  660. request.setValue("application/json;charset=UTF-8", forHTTPHeaderField: "Content-Type")
  661. request.setValue("application/json", forHTTPHeaderField: "Accept")
  662. }
  663. request.httpBody = jsonData
  664. //print("DATA SEND MOBILE \(Utils.getUserAgent()) <> \(Utils.getCookiesMobile())")
  665. let urlConfig = URLSessionConfiguration.default
  666. urlConfig.timeoutIntervalForRequest = 30.0
  667. urlConfig.timeoutIntervalForResource = 60.0
  668. urlConfig.isDiscretionary = false
  669. urlConfig.sessionSendsLaunchEvents = true
  670. let sessionDelegate = SelfSignedURLSessionDelegate()
  671. let session = URLSession(configuration: urlConfig, delegate: sessionDelegate, delegateQueue: nil)
  672. let task = session.dataTask(with: request, completionHandler: completion)
  673. task.resume()
  674. }
  675. public static func resetValueSuperApp() {
  676. Utils.setURLFirstTab(value: "")
  677. Utils.setURLThirdTab(value: "")
  678. Utils.setURLWv3(value: "")
  679. Utils.setURLWv4(value: "")
  680. Utils.setURLWv5(value: "")
  681. Utils.setURLWv6(value: "")
  682. Utils.setCustomTab(cust: "")
  683. Utils.setIconDock(value: "")
  684. Utils.setBackground(value: "")
  685. Utils.setBackgroundLight(value: "")
  686. Utils.setBackgroundDark(value: "")
  687. Utils.setBackgroundTab1(value: "")
  688. Utils.setBackgroundTab2(value: "")
  689. Utils.setBackgroundTab3(value: "")
  690. Utils.setBackgroundTab4(value: "")
  691. Utils.setBackgroundTab5(value: "")
  692. Utils.setBackgroundTab6(value: "")
  693. Utils.setCpaasMode(mode: 0)
  694. Utils.setCustomButtons(value: "")
  695. Utils.setIconDock(value: "")
  696. Utils.setTab1Icon(value: "")
  697. Utils.setTab2Icon(value: "")
  698. Utils.setTab3Icon(value: "")
  699. Utils.setTab4Icon(value: "")
  700. Utils.setTab5Icon(value: "")
  701. Utils.setTab6Icon(value: "")
  702. Utils.setButtonIcon(value: "")
  703. Utils.setReverseTab(value: "")
  704. Utils.setIconDockSize(value: "")
  705. }
  706. public static func setValueInitialApp(data: String) {
  707. if let jsonArray = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [[String: Any?]] {
  708. do {
  709. let json = Array(jsonArray)[0]
  710. for i in 0..<json.keys.count {
  711. if Array(json.keys)[i] == "app_builder_url_first_tab" {
  712. Utils.setURLFirstTab(value: Array(json.values)[i] as? String ?? "")
  713. }
  714. if Array(json.keys)[i] == "app_builder_url_third_tab" {
  715. Utils.setURLThirdTab(value: Array(json.values)[i] as? String ?? "")
  716. }
  717. if Array(json.keys)[i] == "app_builder_url_status_update" {
  718. Utils.setURLStatusUpdate(value: Array(json.values)[i] as? String ?? "")
  719. }
  720. if Array(json.keys)[i] == "app_builder_custom_tab" {
  721. Utils.setCustomTab(cust: Array(json.values)[i] as? String ?? "")
  722. }
  723. if Array(json.keys)[i] == "app_builder_url_base" {
  724. Utils.setURLBase(value: Array(json.values)[i] as? String ?? "")
  725. }
  726. if Array(json.keys)[i] == "app_builder_url_qms" {
  727. Utils.setURLQMS(value: Array(json.values)[i] as? String ?? "")
  728. }
  729. if Array(json.keys)[i] == "app_builder_icon_dock" {
  730. Utils.setIconDock(value: Array(json.values)[i] as? String ?? "")
  731. }
  732. if Array(json.keys)[i] == "app_builder_icon_ss" {
  733. Utils.setIconSS(value: Array(json.values)[i] as? String ?? "")
  734. }
  735. if Array(json.keys)[i] == "app_builder_background" {
  736. Utils.setBackground(value: Array(json.values)[i] as? String ?? "")
  737. }
  738. if Array(json.keys)[i] == "app_builder_url_privacy_policy" {
  739. Utils.setURLPrivacyPolicy(value: Array(json.values)[i] as? String ?? "")
  740. }
  741. if Array(json.keys)[i] == "app_builder_enable_privacy_policy" {
  742. Utils.setEnablePrivacyPolicy(value: Array(json.values)[i] as? String == "1" ? true : false)
  743. }
  744. if Array(json.keys)[i] == "pb_fb_icon_center_self_mode2" {
  745. Utils.setIconCenterAnim2(value: Array(json.values)[i] as? String ?? "")
  746. }
  747. if Array(json.keys)[i] == "pb_fb_icon_center_self_mode4" {
  748. Utils.setIconCenterAnim4(value: Array(json.values)[i] as? String ?? "")
  749. }
  750. if Array(json.keys)[i] == "app_builder_ac_theme" {
  751. Utils.setACTheme(value: Array(json.values)[i] as? String ?? "")
  752. }
  753. if Array(json.keys)[i] == "app_builder_button_url" {
  754. Utils.setButtonURL(value: Array(json.values)[i] as? String ?? "")
  755. }
  756. if Array(json.keys)[i] == "app_builder_custom_buttons" {
  757. Utils.setCustomButtons(value: Array(json.values)[i] as? String ?? "")
  758. }
  759. if Array(json.keys)[i] == "app_builder_enable_mobile_builder" {
  760. Utils.setEnableMobileBuilder(value: Array(json.values)[i] as? String ?? "")
  761. }
  762. if Array(json.keys)[i] == "app_builder_enable_mobile_builder" {
  763. Utils.setEnableMobileBuilder(value: Array(json.values)[i] as? String ?? "")
  764. }
  765. if Array(json.keys)[i] == "fb_config_mode" {
  766. Utils.setConfigModeFB(value: Array(json.values)[i] as? String ?? "")
  767. }
  768. if Array(json.keys)[i] == "app_builder_button_icon" {
  769. Utils.setCustomFBIcon(value: Array(json.values)[i] as? String ?? "")
  770. }
  771. if Array(json.keys)[i] == "fb_floating_anim" {
  772. Utils.setFloatingAnim(value: Array(json.values)[i] as? String ?? "")
  773. }
  774. if Array(json.keys)[i] == "fb_icon_with_bg" {
  775. Utils.setFBIconBg(value: Array(json.values)[i] as? String ?? "")
  776. }
  777. if Array(json.keys)[i] == "fb_item_with_bg" {
  778. Utils.setFBItemBg(value: Array(json.values)[i] as? String ?? "")
  779. }
  780. if Array(json.keys)[i] == "user_agent" {
  781. Utils.setUserAgent(value: Array(json.values)[i] as? String ?? "")
  782. }
  783. if Array(json.keys)[i] == "app_builder_background_light" {
  784. Utils.setBackgroundLight(value: Array(json.values)[i] as? String ?? "")
  785. }
  786. if Array(json.keys)[i] == "app_builder_background_dark" {
  787. Utils.setBackgroundDark(value: Array(json.values)[i] as? String ?? "")
  788. }
  789. if Array(json.keys)[i] == "sms_center" {
  790. Utils.setSMSCenter(value: Array(json.values)[i] as? String ?? "")
  791. }
  792. if Array(json.keys)[i] == "whatsapp_center" {
  793. Utils.setWhatsappCenter(value: Array(json.values)[i] as? String ?? "")
  794. }
  795. if Array(json.keys)[i] == "call_center" {
  796. Utils.setCallCenter(value: Array(json.values)[i] as? String ?? "")
  797. }
  798. if Array(json.keys)[i] == "enable_valid_trans" {
  799. Utils.setValidTrans(value: Array(json.values)[i] as? String ?? "")
  800. }
  801. if Array(json.keys)[i] == "chatbot_greetings" {
  802. Utils.setValidTrans(value: Array(json.values)[i] as? String ?? "")
  803. }
  804. if Array(json.keys)[i] == "fb_icon_center" {
  805. Utils.setIconCenter(value: Array(json.values)[i] as? String ?? "")
  806. }
  807. if Array(json.keys)[i] == "tab1_icon" {
  808. Utils.setTab1Icon(value: Array(json.values)[i] as? String ?? "")
  809. }
  810. if Array(json.keys)[i] == "tab2_icon" {
  811. Utils.setTab2Icon(value: Array(json.values)[i] as? String ?? "")
  812. }
  813. if Array(json.keys)[i] == "tab3_icon" {
  814. Utils.setTab3Icon(value: Array(json.values)[i] as? String ?? "")
  815. }
  816. if Array(json.keys)[i] == "tab4_icon" {
  817. Utils.setTab4Icon(value: Array(json.values)[i] as? String ?? "")
  818. }
  819. if Array(json.keys)[i] == "indicator_tab_image" {
  820. Utils.setIndicatorTabImage(value: Array(json.values)[i] as? String ?? "")
  821. }
  822. if Array(json.keys)[i] == "gptbot_url" {
  823. Utils.setGPTBotUrl(value: Array(json.values)[i] as? String ?? "")
  824. }
  825. if Array(json.keys)[i] == "default_sound_incmsg" {
  826. Utils.setDefaultIncomingMsg(value: Array(json.values)[i] as? String ?? "")
  827. }
  828. if Array(json.keys)[i] == "default_sound_inccall" {
  829. Utils.setDefaultIncomingCall(value: Array(json.values)[i] as? String ?? "")
  830. }
  831. if Array(json.keys)[i] == "default_sound_rbt" {
  832. Utils.setDefaultIncomingRBT(value: Array(json.values)[i] as? String ?? "")
  833. }
  834. if Array(json.keys)[i] == "icon_size" {
  835. Utils.setIconDockSize(value: Array(json.values)[i] as? String ?? "")
  836. }
  837. }
  838. Utils.setFinishInitPrefs(value: true)
  839. DispatchQueue.main.async {
  840. if Nexilis.showFB && Nexilis.floatingButton.superview != nil {
  841. Nexilis.floatingButton.setImageWithURL(!Utils.getIconDock().isEmpty && Nexilis.fromMAB)
  842. }
  843. }
  844. } catch {
  845. }
  846. }
  847. }
  848. public static var inTabChats = false
  849. public static var longitude = ""
  850. public static var latitude = ""
  851. private static let I_BB = 48 // 0
  852. private static let I_BBT_1 = 57 // 9
  853. private static let I_BAT_1 = 65 // A
  854. private static let I_BBT_2 = 90 // Z
  855. private static let I_BAT_2 = 97 // a
  856. private static let I_BA = 122 // z
  857. private static let IC_BB = 33 // !
  858. private static let IC_BBT_1 = 47 // /
  859. private static let IC_BAT_1 = 58 // :
  860. private static let IC_BBT_2 = 64 // @
  861. private static let IC_BAT_2 = 91 // [
  862. private static let IC_BBT_3 = 96 // @
  863. private static let IC_BAT_3 = 123 // [
  864. private static let IC_BA = 126 // `
  865. private static var icIGNORE = Set<Int>()
  866. private static func initIcIgnore() {
  867. icIGNORE.insert(10)// \r
  868. icIGNORE.insert(13)// \n
  869. icIGNORE.insert(32)// <space>
  870. }
  871. public static func decrypt(str: String) -> String {
  872. var arr: [Character]
  873. var iRandom = 0
  874. var sDecrypt: String
  875. iRandom = Int(str.substring(from: 0, to: 0)) ?? 0
  876. sDecrypt = getPalindrom(str: str.substring(from: 1, to: nil))
  877. arr = Array(sDecrypt)
  878. for i in 0..<arr.count {
  879. if (isSpecialChar(ch: arr[i])) {
  880. arr[i] = getBeforecChar(ch: arr[i], inc: iRandom)
  881. } else {
  882. arr[i] = getBeforeChar(ch: arr[i], inc: iRandom)
  883. }
  884. }
  885. return String(arr)
  886. }
  887. private static func isSpecialChar(ch: Character) -> Bool {
  888. let ch = Int(ch.asciiValue ?? 0)
  889. return (ch >= IC_BB && ch <= IC_BBT_1) || (ch >= IC_BAT_1 && ch <= IC_BBT_2) || (ch >= IC_BAT_2 && ch <= IC_BBT_3) || (ch >= IC_BAT_3 && ch <= IC_BA)
  890. }
  891. private static func getPalindrom(str: String) -> String {
  892. let arr: [Character] = Array(str)
  893. var arr2: [Character] = Array(arr)
  894. for i in 0..<arr.count {
  895. arr2[i] = arr[arr.count - (i + 1)]
  896. }
  897. return String(arr2)
  898. }
  899. private static func getBeforeChar(ch: Character, inc: Int) -> Character {
  900. if icIGNORE.isEmpty {
  901. initIcIgnore()
  902. }
  903. var iAscii = ch
  904. let iAsciiBefore = iAscii
  905. if (icIGNORE.contains(Int(iAscii.asciiValue ?? 0))) {
  906. return iAscii;
  907. }
  908. if Int(iAscii.asciiValue ?? 0) > I_BA || Int(iAscii.asciiValue ?? 0) < I_BB {
  909. } else {
  910. if !icIGNORE.contains(Int(iAscii.asciiValue ?? 0)) {
  911. iAscii = Character(UnicodeScalar(Int(iAscii.asciiValue ?? 0) - inc)!)
  912. if (I_BAT_1 > Int(iAscii.asciiValue ?? 0) && Int(iAsciiBefore.asciiValue ?? 0) >= I_BAT_1) {
  913. iAscii = Character(UnicodeScalar((I_BBT_1 + 1) - (I_BAT_1 - Int(iAscii.asciiValue ?? 0)))!)
  914. }
  915. if (I_BAT_2 > Int(iAscii.asciiValue ?? 0) && Int(iAsciiBefore.asciiValue ?? 0) >= I_BAT_2) {
  916. iAscii = Character(UnicodeScalar((I_BBT_2 + 1) - (I_BAT_2 - Int(iAscii.asciiValue ?? 0)))!)
  917. }
  918. if (Int(iAscii.asciiValue ?? 0) < I_BB) {
  919. iAscii = Character(UnicodeScalar((I_BA + 1) + (Int(iAscii.asciiValue ?? 0) - I_BB))!)
  920. }
  921. }
  922. }
  923. return iAscii
  924. }
  925. private static func getBeforecChar(ch: Character, inc: Int) -> Character {
  926. var iAscii = ch
  927. let iAsciiBefore = iAscii
  928. if (Int(iAscii.asciiValue ?? 0) > IC_BA || Int(iAscii.asciiValue ?? 0) < IC_BB) {
  929. } else {
  930. iAscii = Character(UnicodeScalar(Int(iAscii.asciiValue ?? 0) - inc)!)
  931. if (Int(iAscii.asciiValue ?? 0) < IC_BB) {
  932. iAscii = Character(UnicodeScalar((IC_BA + 1) + (Int(iAscii.asciiValue ?? 0) - IC_BB))!)
  933. if (Int(iAscii.asciiValue ?? 0) < IC_BAT_3 && Int(iAscii.asciiValue ?? 0) > IC_BBT_3) {
  934. iAscii = Character(UnicodeScalar((IC_BBT_3 + 1) - (IC_BAT_3 - Int(iAscii.asciiValue ?? 0)))!)
  935. }
  936. }
  937. if (IC_BAT_3 > Int(iAscii.asciiValue ?? 0) && Int(iAsciiBefore.asciiValue ?? 0) >= IC_BAT_3) {
  938. iAscii = Character(UnicodeScalar((IC_BBT_3 + 1) - (IC_BAT_3 - Int(iAscii.asciiValue ?? 0)))!)
  939. }
  940. if (IC_BAT_2 > Int(iAscii.asciiValue ?? 0) && Int(iAsciiBefore.asciiValue ?? 0) >= IC_BAT_2) {
  941. iAscii = Character(UnicodeScalar((IC_BBT_2 + 1) - (IC_BAT_2 - Int(iAscii.asciiValue ?? 0)))!)
  942. }
  943. if (IC_BAT_1 > Int(iAscii.asciiValue ?? 0) && Int(iAsciiBefore.asciiValue ?? 0) >= IC_BAT_1) {
  944. iAscii = Character(UnicodeScalar((IC_BBT_1 + 1) - (IC_BAT_1 - Int(iAscii.asciiValue ?? 0)))!)
  945. }
  946. }
  947. return iAscii
  948. }
  949. public static func addBackground(view: UIView?) {
  950. do {
  951. if let view = view {
  952. DispatchQueue.global().async {
  953. DispatchQueue.main.async {
  954. let listBg = Utils.getBackgroundLight().isEmpty && Utils.getBackgroundDark().isEmpty ? Utils.getBackground() :
  955. UIApplication.shared.visibleViewController?.traitCollection.userInterfaceStyle == .dark ? Utils.getBackgroundDark() : Utils.getBackgroundLight()
  956. if listBg.isEmpty {
  957. return
  958. }
  959. var bgChoosen = ""
  960. let arrayBg = listBg.split(separator: ",")
  961. bgChoosen = String(arrayBg[Int.random(in: 0..<arrayBg.count)])
  962. let urlString = Utils.getURLBase() + "get_file_from_path?img=" + bgChoosen
  963. if let cachedImage = ImageCache.shared.image(forKey: urlString) {
  964. DispatchQueue.main.async() {
  965. let backgroundImage = cachedImage
  966. let backgroundImageView = UIImageView(frame: view.bounds)
  967. backgroundImageView.image = backgroundImage
  968. backgroundImageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
  969. view.insertSubview(backgroundImageView, at: 0)
  970. view.sendSubviewToBack(backgroundImageView)
  971. }
  972. return
  973. }
  974. Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
  975. guard let data = data, error == nil else { return }
  976. // always update the UI from the main thread
  977. DispatchQueue.main.async() {
  978. if UIImage(data: data) != nil {
  979. let backgroundImage = UIImage(data: data)!
  980. let backgroundImageView = UIImageView(frame: view.bounds)
  981. backgroundImageView.image = backgroundImage
  982. backgroundImageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
  983. view.insertSubview(backgroundImageView, at: 0)
  984. view.sendSubviewToBack(backgroundImageView)
  985. ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
  986. }
  987. }
  988. }
  989. }
  990. }
  991. }
  992. } catch {
  993. }
  994. }
  995. public static func randomizeBackground(view: UIView?) {
  996. do {
  997. if let view = view {
  998. DispatchQueue.global().async {
  999. DispatchQueue.main.async {
  1000. let listBg = Utils.getBackgroundLight().isEmpty && Utils.getBackgroundDark().isEmpty ? Utils.getBackground() :
  1001. UIApplication.shared.visibleViewController?.traitCollection.userInterfaceStyle == .dark ? Utils.getBackgroundDark() : Utils.getBackgroundLight()
  1002. if listBg.isEmpty {
  1003. return
  1004. }
  1005. var bgChoosen = ""
  1006. let arrayBg = listBg.split(separator: ",")
  1007. bgChoosen = String(arrayBg[Int.random(in: 0..<arrayBg.count)])
  1008. let urlString = Utils.getURLBase() + "get_file_from_path?img=" + bgChoosen
  1009. if let cachedImage = ImageCache.shared.image(forKey: urlString) {
  1010. DispatchQueue.main.async() {
  1011. let backgroundImage = cachedImage
  1012. let backgroundImageView = view.subviews[0] as? UIImageView
  1013. backgroundImageView?.image = backgroundImage
  1014. }
  1015. return
  1016. }
  1017. Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
  1018. guard let data = data, error == nil else { return }
  1019. // always update the UI from the main thread
  1020. DispatchQueue.main.async() {
  1021. if UIImage(data: data) != nil {
  1022. let backgroundImage = UIImage(data: data)!
  1023. let backgroundImageView = view.subviews[0] as? UIImageView
  1024. backgroundImageView?.image = backgroundImage
  1025. ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
  1026. }
  1027. }
  1028. }
  1029. }
  1030. }
  1031. }
  1032. } catch {
  1033. }
  1034. }
  1035. public static let ERR83 = "83:App Name is null".localized()
  1036. public static let ERR97 = "97:Account is empty".localized()
  1037. public static let ERR91 = "91:Service not implemented".localized()
  1038. public static let ERR96 = "96:Activity is null".localized()
  1039. public static let ERR23 = "23:Unsupported Android Version".localized()
  1040. public static let ERR101 = "101:Unable to access server. Check your connection and try again later".localized()
  1041. public static let ERR00 = "00:Success".localized()
  1042. public static let ERR85 = "85:You must Sign In or Sign Up to use this feature".localized()
  1043. public static let ERR106 = "106:Illegal State. Be sure call API connect and #callback state onSuccess called".localized()
  1044. public static let ERR92 = "92:Username is empty".localized()
  1045. public static let ERR90 = "90:Invalid Api, you already set userName in API connect".localized()
  1046. public static let ERR84 = "84:Feature Disabled".localized()
  1047. public static func setConnectionID(value: String) {
  1048. SecureUserDefaults.shared.set(value, forKey: "connection_id")
  1049. }
  1050. public static func getConnectionID() -> String {
  1051. if let value: String = SecureUserDefaults.shared.value(forKey: "connection_id") {
  1052. return value
  1053. }
  1054. return ""
  1055. }
  1056. public static func setLimitValidTrans(value: String) {
  1057. SecureUserDefaults.shared.set(value, forKey: "pb_set_valid_trans")
  1058. }
  1059. public static func getLimitValidTrans() -> String {
  1060. if let value: String = SecureUserDefaults.shared.value(forKey: "pb_set_valid_trans") {
  1061. return value
  1062. }
  1063. return "100000"
  1064. }
  1065. public static func setLoginMultipleFPin(value: String) {
  1066. SecureUserDefaults.shared.set(value, forKey: "pb_login_multiple_f_pin")
  1067. }
  1068. public static func getLoginMultipleFPin() -> String {
  1069. if let value: String = SecureUserDefaults.shared.value(forKey: "pb_login_multiple_f_pin") {
  1070. return value
  1071. }
  1072. return ""
  1073. }
  1074. public static func setPrefTheme(value: String) {
  1075. SecureUserDefaults.shared.set(value, forKey: "first_pref_theme")
  1076. }
  1077. public static func getPrefTheme() -> String {
  1078. if let value: String = SecureUserDefaults.shared.value(forKey: "first_pref_theme") {
  1079. return value
  1080. }
  1081. return ""
  1082. }
  1083. public static func setMyTheme(value: String) {
  1084. SecureUserDefaults.shared.set(value, forKey: "my_theme")
  1085. }
  1086. public static func getMyTheme() -> String {
  1087. if let value: String = SecureUserDefaults.shared.value(forKey: "my_theme") {
  1088. return value
  1089. }
  1090. return ""
  1091. }
  1092. public static func setIsLoadThemeFromOther(value: Bool) {
  1093. SecureUserDefaults.shared.set(value, forKey: "load_theme_from_other")
  1094. }
  1095. public static func getIsLoadThemeFromOther() -> Bool {
  1096. if let value: Bool = SecureUserDefaults.shared.value(forKey: "load_theme_from_other") {
  1097. return value
  1098. }
  1099. return false
  1100. }
  1101. public static func setURLWv3(value: String) {
  1102. SecureUserDefaults.shared.set(value, forKey: "app_builder_url_webview_3")
  1103. }
  1104. public static func getURLWv3() -> String {
  1105. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_url_webview_3") {
  1106. return value
  1107. }
  1108. return ""
  1109. }
  1110. public static func setURLWv4(value: String) {
  1111. SecureUserDefaults.shared.set(value, forKey: "app_builder_url_webview_4")
  1112. }
  1113. public static func getURLWv4() -> String {
  1114. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_url_webview_4") {
  1115. return value
  1116. }
  1117. return ""
  1118. }
  1119. public static func setURLWv5(value: String) {
  1120. SecureUserDefaults.shared.set(value, forKey: "app_builder_url_webview_5")
  1121. }
  1122. public static func getURLWv5() -> String {
  1123. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_url_webview_5") {
  1124. return value
  1125. }
  1126. return ""
  1127. }
  1128. public static func setURLWv6(value: String) {
  1129. SecureUserDefaults.shared.set(value, forKey: "app_builder_url_webview_6")
  1130. }
  1131. public static func getURLWv6() -> String {
  1132. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_url_webview_6") {
  1133. return value
  1134. }
  1135. return ""
  1136. }
  1137. public static func setBackgroundTab1(value: String) {
  1138. SecureUserDefaults.shared.set(value, forKey: "app_builder_background_1")
  1139. }
  1140. public static func getBackgroundTab1() -> String {
  1141. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_background_1") {
  1142. return value
  1143. }
  1144. return ""
  1145. }
  1146. public static func setBackgroundTab2(value: String) {
  1147. SecureUserDefaults.shared.set(value, forKey: "app_builder_background_2")
  1148. }
  1149. public static func getBackgroundTab2() -> String {
  1150. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_background_2") {
  1151. return value
  1152. }
  1153. return ""
  1154. }
  1155. public static func setBackgroundTab3(value: String) {
  1156. SecureUserDefaults.shared.set(value, forKey: "app_builder_background_3")
  1157. }
  1158. public static func getBackgroundTab3() -> String {
  1159. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_background_3") {
  1160. return value
  1161. }
  1162. return ""
  1163. }
  1164. public static func setBackgroundTab4(value: String) {
  1165. SecureUserDefaults.shared.set(value, forKey: "app_builder_background_4")
  1166. }
  1167. public static func getBackgroundTab4() -> String {
  1168. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_background_4") {
  1169. return value
  1170. }
  1171. return ""
  1172. }
  1173. public static func setBackgroundTab5(value: String) {
  1174. SecureUserDefaults.shared.set(value, forKey: "app_builder_background_5")
  1175. }
  1176. public static func getBackgroundTab5() -> String {
  1177. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_background_5") {
  1178. return value
  1179. }
  1180. return ""
  1181. }
  1182. public static func setBackgroundTab6(value: String) {
  1183. SecureUserDefaults.shared.set(value, forKey: "app_builder_background_6")
  1184. }
  1185. public static func getBackgroundTab6() -> String {
  1186. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_background_6") {
  1187. return value
  1188. }
  1189. return ""
  1190. }
  1191. public static func setCpaasMode(mode: Int){
  1192. SecureUserDefaults.shared.set(mode+1, forKey: "cpaas_mode")
  1193. }
  1194. public static func setTab1Icon(value: String) {
  1195. SecureUserDefaults.shared.set(value, forKey: "tab1_icon")
  1196. }
  1197. public static func getTab1Icon() -> String {
  1198. if let value: String = SecureUserDefaults.shared.value(forKey: "tab1_icon") {
  1199. return value
  1200. }
  1201. return ""
  1202. }
  1203. public static func setTab2Icon(value: String) {
  1204. SecureUserDefaults.shared.set(value, forKey: "tab2_icon")
  1205. }
  1206. public static func getTab2Icon() -> String {
  1207. if let value: String = SecureUserDefaults.shared.value(forKey: "tab2_icon") {
  1208. return value
  1209. }
  1210. return ""
  1211. }
  1212. public static func setTab3Icon(value: String) {
  1213. SecureUserDefaults.shared.set(value, forKey: "tab3_icon")
  1214. }
  1215. public static func getTab3Icon() -> String {
  1216. if let value: String = SecureUserDefaults.shared.value(forKey: "tab3_icon") {
  1217. return value
  1218. }
  1219. return ""
  1220. }
  1221. public static func setTab4Icon(value: String) {
  1222. SecureUserDefaults.shared.set(value, forKey: "tab4_icon")
  1223. }
  1224. public static func getTab4Icon() -> String {
  1225. if let value: String = SecureUserDefaults.shared.value(forKey: "tab4_icon") {
  1226. return value
  1227. }
  1228. return ""
  1229. }
  1230. public static func setTab5Icon(value: String) {
  1231. SecureUserDefaults.shared.set(value, forKey: "tab5_icon")
  1232. }
  1233. public static func getTab5Icon() -> String {
  1234. if let value: String = SecureUserDefaults.shared.value(forKey: "tab5_icon") {
  1235. return value
  1236. }
  1237. return ""
  1238. }
  1239. public static func setTab6Icon(value: String) {
  1240. SecureUserDefaults.shared.set(value, forKey: "tab6_icon")
  1241. }
  1242. public static func getTab6Icon() -> String {
  1243. if let value: String = SecureUserDefaults.shared.value(forKey: "tab6_icon") {
  1244. return value
  1245. }
  1246. return ""
  1247. }
  1248. public static func setButtonIcon(value: String) {
  1249. SecureUserDefaults.shared.set(value, forKey: "app_builder_button_icon")
  1250. }
  1251. public static func getButtonIcon() -> String {
  1252. if let value: String = SecureUserDefaults.shared.value(forKey: "app_builder_button_icon") {
  1253. return value
  1254. }
  1255. return ""
  1256. }
  1257. public static func setReverseTab(value: String) {
  1258. SecureUserDefaults.shared.set(value, forKey: "reverse_tab_color")
  1259. }
  1260. public static func getReverseTab() -> String {
  1261. if let value: String = SecureUserDefaults.shared.value(forKey: "reverse_tab_color") {
  1262. return value
  1263. }
  1264. return "0"
  1265. }
  1266. public static func setIconDockSize(value: String) {
  1267. SecureUserDefaults.shared.set(value, forKey: "icon_size")
  1268. }
  1269. public static func getIconDockSize() -> String {
  1270. if let value: String = SecureUserDefaults.shared.value(forKey: "icon_size") {
  1271. return value
  1272. }
  1273. return "0"
  1274. }
  1275. public static func setIndicatorTabImage(value: String) {
  1276. SecureUserDefaults.shared.set(value, forKey: "indicator_tab_image")
  1277. }
  1278. public static func getIndicatorTabImage() -> String {
  1279. if let value: String = SecureUserDefaults.shared.value(forKey: "indicator_tab_image") {
  1280. return value
  1281. }
  1282. return ""
  1283. }
  1284. public static func setGPTBotUrl(value: String) {
  1285. SecureUserDefaults.shared.set(value, forKey: "gptbot_url")
  1286. }
  1287. public static func getGPTBotUrl() -> String {
  1288. if let value: String = SecureUserDefaults.shared.value(forKey: "gptbot_url") {
  1289. return value
  1290. }
  1291. return Utils.decrypt(str: "3wsj<B67B=rl;vlol0hq<<=vswwk")
  1292. }
  1293. static func setDebugBC(value: [String: String]) {
  1294. SecureUserDefaults.shared.set(value, forKey: "debugBc")
  1295. }
  1296. static func getDebugBC() -> [String: String]? {
  1297. if let value: [String: String] = SecureUserDefaults.shared.value(forKey: "debugBc") {
  1298. return value
  1299. }
  1300. return nil
  1301. }
  1302. public static func setPassEncDB(value: String) {
  1303. SecureUserDefaults.shared.set(value, forKey: "pb_db_encrypt_pass")
  1304. }
  1305. public static func getPassEncDB() -> String {
  1306. if let value: String = SecureUserDefaults.shared.value(forKey: "pb_db_encrypt_pass") {
  1307. return value
  1308. }
  1309. return ""
  1310. }
  1311. public static func setTokenAPN(value: String) {
  1312. SecureUserDefaults.shared.set(value, forKey: "token_apn")
  1313. }
  1314. public static func getTokenAPN() -> String {
  1315. if let value: String = SecureUserDefaults.shared.value(forKey: "token_apn") {
  1316. return value
  1317. }
  1318. return ""
  1319. }
  1320. public static func setTokenCall(value: String) {
  1321. SecureUserDefaults.shared.set(value, forKey: "token_call")
  1322. }
  1323. public static func getTokenCall() -> String {
  1324. if let value: String = SecureUserDefaults.shared.value(forKey: "token_call") {
  1325. return value
  1326. }
  1327. return ""
  1328. }
  1329. public static func setLastTabSelected(value: Int) {
  1330. SecureUserDefaults.shared.set(value, forKey: "last_selected_tab")
  1331. }
  1332. public static func getLastTabSelected() -> Int {
  1333. if let value: Int = SecureUserDefaults.shared.value(forKey: "last_selected_tab") {
  1334. return value
  1335. }
  1336. return 0
  1337. }
  1338. public static func setDefaultIncomingMsg(value: String) {
  1339. SecureUserDefaults.shared.set(value, forKey: "default_sound_incmsg")
  1340. }
  1341. public static func getDefaultIncomingMsg() -> String {
  1342. if let value: String = SecureUserDefaults.shared.value(forKey: "default_sound_incmsg") {
  1343. return value
  1344. }
  1345. return ""
  1346. }
  1347. public static func setDefaultIncomingCall(value: String) {
  1348. SecureUserDefaults.shared.set(value, forKey: "default_sound_inccall")
  1349. }
  1350. public static func getDefaultIncomingCall() -> String {
  1351. if let value: String = SecureUserDefaults.shared.value(forKey: "default_sound_inccall") {
  1352. return value
  1353. }
  1354. return ""
  1355. }
  1356. public static func setDefaultIncomingRBT(value: String) {
  1357. SecureUserDefaults.shared.set(value, forKey: "default_sound_rbt")
  1358. }
  1359. public static func getDefaultIncomingRBT() -> String {
  1360. if let value: String = SecureUserDefaults.shared.value(forKey: "default_sound_rbt") {
  1361. return value
  1362. }
  1363. return ""
  1364. }
  1365. public static func setIsWATheme(value: Bool) {
  1366. SecureUserDefaults.shared.set(value, forKey: "is_wa_key")
  1367. }
  1368. public static func getIsWATheme() -> Bool {
  1369. let value: Bool = SecureUserDefaults.shared.value(forKey: "is_wa_key") ?? false
  1370. return value
  1371. }
  1372. public static func setBiometricState(value: Data?) {
  1373. SecureUserDefaults.shared.set(value, forKey: "pb_biometric_state")
  1374. }
  1375. public static func getBiometricState() -> Data? {
  1376. let value: Data? = SecureUserDefaults.shared.value(forKey: "pb_biometric_state")
  1377. return value
  1378. }
  1379. static func setSignUpLevel(value: String) {
  1380. SecureUserDefaults.shared.set(value, forKey: "pb_signup_level")
  1381. }
  1382. static func getSignUpLevel() -> String {
  1383. if let value: String = SecureUserDefaults.shared.value(forKey: "pb_signup_level") {
  1384. return value
  1385. }
  1386. return "1,2"
  1387. }
  1388. static func setSignInLevel(value: String) {
  1389. SecureUserDefaults.shared.set(value, forKey: "pb_signin_level")
  1390. }
  1391. static func getSignInLevel() -> String {
  1392. if let value: String = SecureUserDefaults.shared.value(forKey: "pb_signin_level") {
  1393. return value
  1394. }
  1395. return "1,2"
  1396. }
  1397. static func setTxnLevel(value: String) {
  1398. SecureUserDefaults.shared.set(value, forKey: "pb_txn_level")
  1399. }
  1400. static func getTxnLevel() -> String {
  1401. if let value: String = SecureUserDefaults.shared.value(forKey: "pb_txn_level") {
  1402. return value
  1403. }
  1404. return ""
  1405. }
  1406. static func getPasswordDB() -> String? {
  1407. do {
  1408. let p = getPassEncDB()
  1409. if p.isEmpty {
  1410. var keyData = Data(count: 32) // 256-bit key
  1411. let result = keyData.withUnsafeMutableBytes {
  1412. SecRandomCopyBytes(kSecRandomDefault, 32, $0.baseAddress!)
  1413. }
  1414. if result == errSecSuccess {
  1415. let encrypt = try MasterKeyUtil.shared.encryptD(data: keyData)
  1416. setPassEncDB(value: encrypt.base64EncodedString())
  1417. let keyTemp = keyData.base64EncodedString()
  1418. keyData.resetBytes(in: 0..<keyData.count)
  1419. return keyTemp
  1420. } else {
  1421. print("Error generating random bytes: \(result)")
  1422. return nil
  1423. }
  1424. }
  1425. let decrypt = try MasterKeyUtil.shared.decryptD(data: Data(base64Encoded: p)!)
  1426. return decrypt.base64EncodedString()
  1427. } catch {
  1428. return nil
  1429. }
  1430. }
  1431. public static func shouldRequestAuthentication() -> Bool {
  1432. if let lastAuthTime: Date = SecureUserDefaults.shared.value(forKey: "lastAuthenticationTime") {
  1433. let elapsedTime = Date().timeIntervalSince(lastAuthTime)
  1434. let durationAuth = Double(Utils.getAuthenticationDuration()) ?? 5
  1435. // print("durationAuth \(durationAuth)")
  1436. return elapsedTime > durationAuth
  1437. }
  1438. return true
  1439. }
  1440. public static func authenticateWithBiometrics(completion: @escaping (Bool, String?) -> Void) {
  1441. guard shouldRequestAuthentication() else {
  1442. completion(true, nil)
  1443. return
  1444. }
  1445. let context = LAContext()
  1446. let reason = "Authenticate to access secure data".localized()
  1447. if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) {
  1448. context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, error in
  1449. if success {
  1450. // Store the time of successful authentication
  1451. SecureUserDefaults.shared.set(Date(), forKey: "lastAuthenticationTime")
  1452. completion(true, nil)
  1453. } else {
  1454. let errorMessage = error?.localizedDescription ?? "Authentication failed"
  1455. completion(false, errorMessage)
  1456. }
  1457. }
  1458. } else {
  1459. completion(false, "Biometric authentication is not available")
  1460. }
  1461. }
  1462. }
  1463. public extension UIImage {
  1464. var jpeg: Data? { jpegData(compressionQuality: 1) } // QUALITY min = 0 / max = 1
  1465. var png: Data? { pngData() }
  1466. }
  1467. public extension Data {
  1468. var uiImage: UIImage? { UIImage(data: self) }
  1469. }
  1470. public enum ModelIphone : String {
  1471. //Simulator
  1472. case simulator = "simulator/sandbox",
  1473. //iPod
  1474. iPod1 = "iPod 1",
  1475. iPod2 = "iPod 2",
  1476. iPod3 = "iPod 3",
  1477. iPod4 = "iPod 4",
  1478. iPod5 = "iPod 5",
  1479. iPod6 = "iPod 6",
  1480. iPod7 = "iPod 7",
  1481. //iPad
  1482. iPad2 = "iPad 2",
  1483. iPad3 = "iPad 3",
  1484. iPad4 = "iPad 4",
  1485. iPadAir = "iPad Air ",
  1486. iPadAir2 = "iPad Air 2",
  1487. iPadAir3 = "iPad Air 3",
  1488. iPadAir4 = "iPad Air 4",
  1489. iPadAir5 = "iPad Air 5",
  1490. iPad5 = "iPad 5", //iPad 2017
  1491. iPad6 = "iPad 6", //iPad 2018
  1492. iPad7 = "iPad 7", //iPad 2019
  1493. iPad8 = "iPad 8", //iPad 2020
  1494. iPad9 = "iPad 9", //iPad 2021
  1495. iPad10 = "iPad 10", //iPad 2022
  1496. //iPad Mini
  1497. iPadMini = "iPad Mini",
  1498. iPadMini2 = "iPad Mini 2",
  1499. iPadMini3 = "iPad Mini 3",
  1500. iPadMini4 = "iPad Mini 4",
  1501. iPadMini5 = "iPad Mini 5",
  1502. iPadMini6 = "iPad Mini 6",
  1503. //iPad Pro
  1504. iPadPro9_7 = "iPad Pro 9.7\"",
  1505. iPadPro10_5 = "iPad Pro 10.5\"",
  1506. iPadPro11 = "iPad Pro 11\"",
  1507. iPadPro2_11 = "iPad Pro 11\" 2nd gen",
  1508. iPadPro3_11 = "iPad Pro 11\" 3rd gen",
  1509. iPadPro12_9 = "iPad Pro 12.9\"",
  1510. iPadPro2_12_9 = "iPad Pro 2 12.9\"",
  1511. iPadPro3_12_9 = "iPad Pro 3 12.9\"",
  1512. iPadPro4_12_9 = "iPad Pro 4 12.9\"",
  1513. iPadPro5_12_9 = "iPad Pro 5 12.9\"",
  1514. //iPhone
  1515. iPhone4 = "iPhone 4",
  1516. iPhone4S = "iPhone 4S",
  1517. iPhone5 = "iPhone 5",
  1518. iPhone5S = "iPhone 5S",
  1519. iPhone5C = "iPhone 5C",
  1520. iPhone6 = "iPhone 6",
  1521. iPhone6Plus = "iPhone 6 Plus",
  1522. iPhone6S = "iPhone 6S",
  1523. iPhone6SPlus = "iPhone 6S Plus",
  1524. iPhoneSE = "iPhone SE",
  1525. iPhone7 = "iPhone 7",
  1526. iPhone7Plus = "iPhone 7 Plus",
  1527. iPhone8 = "iPhone 8",
  1528. iPhone8Plus = "iPhone 8 Plus",
  1529. iPhoneX = "iPhone X",
  1530. iPhoneXS = "iPhone XS",
  1531. iPhoneXSMax = "iPhone XS Max",
  1532. iPhoneXR = "iPhone XR",
  1533. iPhone11 = "iPhone 11",
  1534. iPhone11Pro = "iPhone 11 Pro",
  1535. iPhone11ProMax = "iPhone 11 Pro Max",
  1536. iPhoneSE2 = "iPhone SE 2nd gen",
  1537. iPhone12Mini = "iPhone 12 Mini",
  1538. iPhone12 = "iPhone 12",
  1539. iPhone12Pro = "iPhone 12 Pro",
  1540. iPhone12ProMax = "iPhone 12 Pro Max",
  1541. iPhone13Mini = "iPhone 13 Mini",
  1542. iPhone13 = "iPhone 13",
  1543. iPhone13Pro = "iPhone 13 Pro",
  1544. iPhone13ProMax = "iPhone 13 Pro Max",
  1545. iPhoneSE3 = "iPhone SE 3nd gen",
  1546. iPhone14 = "iPhone 14",
  1547. iPhone14Plus = "iPhone 14 Plus",
  1548. iPhone14Pro = "iPhone 14 Pro",
  1549. iPhone14ProMax = "iPhone 14 Pro Max",
  1550. iPhone15 = "iPhone 15",
  1551. iPhone15Plus = "iPhone 15 Plus",
  1552. iPhone15Pro = "iPhone 15 Pro",
  1553. iPhone15ProMax = "iPhone 15 Pro Max",
  1554. // Apple Watch
  1555. AppleWatch1 = "Apple Watch 1gen",
  1556. AppleWatchS1 = "Apple Watch Series 1",
  1557. AppleWatchS2 = "Apple Watch Series 2",
  1558. AppleWatchS3 = "Apple Watch Series 3",
  1559. AppleWatchS4 = "Apple Watch Series 4",
  1560. AppleWatchS5 = "Apple Watch Series 5",
  1561. AppleWatchSE = "Apple Watch Special Edition",
  1562. AppleWatchS6 = "Apple Watch Series 6",
  1563. AppleWatchS7 = "Apple Watch Series 7",
  1564. //Apple TV
  1565. AppleTV1 = "Apple TV 1gen",
  1566. AppleTV2 = "Apple TV 2gen",
  1567. AppleTV3 = "Apple TV 3gen",
  1568. AppleTV4 = "Apple TV 4gen",
  1569. AppleTV_4K = "Apple TV 4K",
  1570. AppleTV2_4K = "Apple TV 4K 2gen",
  1571. AppleTV3_4K = "Apple TV 4K 3gen",
  1572. unrecognized = "?unrecognized?"
  1573. }
  1574. // #-#-#-#-#-#-#-#-#-#-#-#-#
  1575. // MARK: UIDevice extensions
  1576. // #-#-#-#-#-#-#-#-#-#-#-#-#
  1577. public extension UIDevice {
  1578. var type: ModelIphone {
  1579. var systemInfo = utsname()
  1580. uname(&systemInfo)
  1581. let modelCode = withUnsafePointer(to: &systemInfo.machine) {
  1582. $0.withMemoryRebound(to: CChar.self, capacity: 1) {
  1583. ptr in String.init(validatingUTF8: ptr)
  1584. }
  1585. }
  1586. let modelMap : [String: ModelIphone] = [
  1587. //Simulator
  1588. "i386" : .simulator,
  1589. "x86_64" : .simulator,
  1590. //iPod
  1591. "iPod1,1" : .iPod1,
  1592. "iPod2,1" : .iPod2,
  1593. "iPod3,1" : .iPod3,
  1594. "iPod4,1" : .iPod4,
  1595. "iPod5,1" : .iPod5,
  1596. "iPod7,1" : .iPod6,
  1597. "iPod9,1" : .iPod7,
  1598. //iPad
  1599. "iPad2,1" : .iPad2,
  1600. "iPad2,2" : .iPad2,
  1601. "iPad2,3" : .iPad2,
  1602. "iPad2,4" : .iPad2,
  1603. "iPad3,1" : .iPad3,
  1604. "iPad3,2" : .iPad3,
  1605. "iPad3,3" : .iPad3,
  1606. "iPad3,4" : .iPad4,
  1607. "iPad3,5" : .iPad4,
  1608. "iPad3,6" : .iPad4,
  1609. "iPad6,11" : .iPad5, //iPad 2017
  1610. "iPad6,12" : .iPad5,
  1611. "iPad7,5" : .iPad6, //iPad 2018
  1612. "iPad7,6" : .iPad6,
  1613. "iPad7,11" : .iPad7, //iPad 2019
  1614. "iPad7,12" : .iPad7,
  1615. "iPad11,6" : .iPad8, //iPad 2020
  1616. "iPad11,7" : .iPad8,
  1617. "iPad12,1" : .iPad9, //iPad 2021
  1618. "iPad12,2" : .iPad9,
  1619. "iPad13,18" : .iPad10,
  1620. "iPad13,19" : .iPad10,
  1621. //iPad Mini
  1622. "iPad2,5" : .iPadMini,
  1623. "iPad2,6" : .iPadMini,
  1624. "iPad2,7" : .iPadMini,
  1625. "iPad4,4" : .iPadMini2,
  1626. "iPad4,5" : .iPadMini2,
  1627. "iPad4,6" : .iPadMini2,
  1628. "iPad4,7" : .iPadMini3,
  1629. "iPad4,8" : .iPadMini3,
  1630. "iPad4,9" : .iPadMini3,
  1631. "iPad5,1" : .iPadMini4,
  1632. "iPad5,2" : .iPadMini4,
  1633. "iPad11,1" : .iPadMini5,
  1634. "iPad11,2" : .iPadMini5,
  1635. "iPad14,1" : .iPadMini6,
  1636. "iPad14,2" : .iPadMini6,
  1637. //iPad Pro
  1638. "iPad6,3" : .iPadPro9_7,
  1639. "iPad6,4" : .iPadPro9_7,
  1640. "iPad7,3" : .iPadPro10_5,
  1641. "iPad7,4" : .iPadPro10_5,
  1642. "iPad6,7" : .iPadPro12_9,
  1643. "iPad6,8" : .iPadPro12_9,
  1644. "iPad7,1" : .iPadPro2_12_9,
  1645. "iPad7,2" : .iPadPro2_12_9,
  1646. "iPad8,1" : .iPadPro11,
  1647. "iPad8,2" : .iPadPro11,
  1648. "iPad8,3" : .iPadPro11,
  1649. "iPad8,4" : .iPadPro11,
  1650. "iPad8,9" : .iPadPro2_11,
  1651. "iPad8,10" : .iPadPro2_11,
  1652. "iPad13,4" : .iPadPro3_11,
  1653. "iPad13,5" : .iPadPro3_11,
  1654. "iPad13,6" : .iPadPro3_11,
  1655. "iPad13,7" : .iPadPro3_11,
  1656. "iPad8,5" : .iPadPro3_12_9,
  1657. "iPad8,6" : .iPadPro3_12_9,
  1658. "iPad8,7" : .iPadPro3_12_9,
  1659. "iPad8,8" : .iPadPro3_12_9,
  1660. "iPad8,11" : .iPadPro4_12_9,
  1661. "iPad8,12" : .iPadPro4_12_9,
  1662. "iPad13,8" : .iPadPro5_12_9,
  1663. "iPad13,9" : .iPadPro5_12_9,
  1664. "iPad13,10" : .iPadPro5_12_9,
  1665. "iPad13,11" : .iPadPro5_12_9,
  1666. //iPad Air
  1667. "iPad4,1" : .iPadAir,
  1668. "iPad4,2" : .iPadAir,
  1669. "iPad4,3" : .iPadAir,
  1670. "iPad5,3" : .iPadAir2,
  1671. "iPad5,4" : .iPadAir2,
  1672. "iPad11,3" : .iPadAir3,
  1673. "iPad11,4" : .iPadAir3,
  1674. "iPad13,1" : .iPadAir4,
  1675. "iPad13,2" : .iPadAir4,
  1676. "iPad13,16" : .iPadAir5,
  1677. "iPad13,17" : .iPadAir5,
  1678. //iPhone
  1679. "iPhone3,1" : .iPhone4,
  1680. "iPhone3,2" : .iPhone4,
  1681. "iPhone3,3" : .iPhone4,
  1682. "iPhone4,1" : .iPhone4S,
  1683. "iPhone5,1" : .iPhone5,
  1684. "iPhone5,2" : .iPhone5,
  1685. "iPhone5,3" : .iPhone5C,
  1686. "iPhone5,4" : .iPhone5C,
  1687. "iPhone6,1" : .iPhone5S,
  1688. "iPhone6,2" : .iPhone5S,
  1689. "iPhone7,1" : .iPhone6Plus,
  1690. "iPhone7,2" : .iPhone6,
  1691. "iPhone8,1" : .iPhone6S,
  1692. "iPhone8,2" : .iPhone6SPlus,
  1693. "iPhone8,4" : .iPhoneSE,
  1694. "iPhone9,1" : .iPhone7,
  1695. "iPhone9,3" : .iPhone7,
  1696. "iPhone9,2" : .iPhone7Plus,
  1697. "iPhone9,4" : .iPhone7Plus,
  1698. "iPhone10,1" : .iPhone8,
  1699. "iPhone10,4" : .iPhone8,
  1700. "iPhone10,2" : .iPhone8Plus,
  1701. "iPhone10,5" : .iPhone8Plus,
  1702. "iPhone10,3" : .iPhoneX,
  1703. "iPhone10,6" : .iPhoneX,
  1704. "iPhone11,2" : .iPhoneXS,
  1705. "iPhone11,4" : .iPhoneXSMax,
  1706. "iPhone11,6" : .iPhoneXSMax,
  1707. "iPhone11,8" : .iPhoneXR,
  1708. "iPhone12,1" : .iPhone11,
  1709. "iPhone12,3" : .iPhone11Pro,
  1710. "iPhone12,5" : .iPhone11ProMax,
  1711. "iPhone12,8" : .iPhoneSE2,
  1712. "iPhone13,1" : .iPhone12Mini,
  1713. "iPhone13,2" : .iPhone12,
  1714. "iPhone13,3" : .iPhone12Pro,
  1715. "iPhone13,4" : .iPhone12ProMax,
  1716. "iPhone14,4" : .iPhone13Mini,
  1717. "iPhone14,5" : .iPhone13,
  1718. "iPhone14,2" : .iPhone13Pro,
  1719. "iPhone14,3" : .iPhone13ProMax,
  1720. "iPhone14,6" : .iPhoneSE3,
  1721. "iPhone14,7" : .iPhone14,
  1722. "iPhone14,8" : .iPhone14Plus,
  1723. "iPhone15,2" : .iPhone14Pro,
  1724. "iPhone15,3" : .iPhone14ProMax,
  1725. "iPhone15,4" : .iPhone15,
  1726. "iPhone15,5" : .iPhone15Plus,
  1727. "iPhone16,1" : .iPhone15Pro,
  1728. "iPhone16,2" : .iPhone15ProMax,
  1729. // Apple Watch
  1730. "Watch1,1" : .AppleWatch1,
  1731. "Watch1,2" : .AppleWatch1,
  1732. "Watch2,6" : .AppleWatchS1,
  1733. "Watch2,7" : .AppleWatchS1,
  1734. "Watch2,3" : .AppleWatchS2,
  1735. "Watch2,4" : .AppleWatchS2,
  1736. "Watch3,1" : .AppleWatchS3,
  1737. "Watch3,2" : .AppleWatchS3,
  1738. "Watch3,3" : .AppleWatchS3,
  1739. "Watch3,4" : .AppleWatchS3,
  1740. "Watch4,1" : .AppleWatchS4,
  1741. "Watch4,2" : .AppleWatchS4,
  1742. "Watch4,3" : .AppleWatchS4,
  1743. "Watch4,4" : .AppleWatchS4,
  1744. "Watch5,1" : .AppleWatchS5,
  1745. "Watch5,2" : .AppleWatchS5,
  1746. "Watch5,3" : .AppleWatchS5,
  1747. "Watch5,4" : .AppleWatchS5,
  1748. "Watch5,9" : .AppleWatchSE,
  1749. "Watch5,10" : .AppleWatchSE,
  1750. "Watch5,11" : .AppleWatchSE,
  1751. "Watch5,12" : .AppleWatchSE,
  1752. "Watch6,1" : .AppleWatchS6,
  1753. "Watch6,2" : .AppleWatchS6,
  1754. "Watch6,3" : .AppleWatchS6,
  1755. "Watch6,4" : .AppleWatchS6,
  1756. "Watch6,6" : .AppleWatchS7,
  1757. "Watch6,7" : .AppleWatchS7,
  1758. "Watch6,8" : .AppleWatchS7,
  1759. "Watch6,9" : .AppleWatchS7,
  1760. //Apple TV
  1761. "AppleTV1,1" : .AppleTV1,
  1762. "AppleTV2,1" : .AppleTV2,
  1763. "AppleTV3,1" : .AppleTV3,
  1764. "AppleTV3,2" : .AppleTV3,
  1765. "AppleTV5,3" : .AppleTV4,
  1766. "AppleTV6,2" : .AppleTV_4K,
  1767. "AppleTV11,1" : .AppleTV2_4K,
  1768. "AppleTV14,1" : .AppleTV3_4K
  1769. ]
  1770. guard let mcode = modelCode, let map = String(validatingUTF8: mcode), let model = modelMap[map] else { return ModelIphone.unrecognized }
  1771. if model == .simulator {
  1772. if let simModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] {
  1773. if let simMap = String(validatingUTF8: simModelCode), let simModel = modelMap[simMap] {
  1774. return simModel
  1775. }
  1776. }
  1777. }
  1778. return model
  1779. }
  1780. }
  1781. public class CustomNavigationController: UINavigationController {
  1782. public override func viewDidLoad() {
  1783. super.viewDidLoad()
  1784. self.view.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .black : .white
  1785. Utils.addBackground(view: self.view)
  1786. }
  1787. public override func viewDidDisappear(_ animated: Bool) {
  1788. super.viewDidDisappear(animated)
  1789. Utils.randomizeBackground(view: self.view)
  1790. }
  1791. public override init(rootViewController: UIViewController) {
  1792. super.init(rootViewController: rootViewController)
  1793. }
  1794. required init?(coder aDecoder: NSCoder) {
  1795. fatalError("init(coder:) has not been implemented")
  1796. }
  1797. }
  1798. public class DialogUnableAccess: UIViewController {
  1799. public let content = "To verify your identity for signing in on a new device, we need access to your main device. Please turn on your primary device. If it's not accessible, contact us to undergo a KYC verification process.".localized()
  1800. public override func viewDidLoad() {
  1801. super.viewDidLoad()
  1802. self.view.backgroundColor = .black.withAlphaComponent(0.5)
  1803. let container = UIView()
  1804. self.view.addSubview(container)
  1805. container.anchor(top: self.view.topAnchor, left: self.view.leftAnchor, right: self.view.rightAnchor, paddingTop: 30, paddingLeft: 20, paddingRight: 20)
  1806. container.layer.cornerRadius = 20.0
  1807. container.clipsToBounds = true
  1808. container.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .white
  1809. let title = UILabel()
  1810. title.text = "Unable to access your primary device".localized()
  1811. title.font = .systemFont(ofSize: 14, weight: .medium)
  1812. title.numberOfLines = 0
  1813. title.textAlignment = .center
  1814. title.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
  1815. container.addSubview(title)
  1816. title.anchor(top: container.topAnchor, paddingTop: 15, centerX: container.centerXAnchor, width: 270)
  1817. let imageWarning = UIImageView(image: UIImage(named: "pb_security_warning", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  1818. container.addSubview(imageWarning)
  1819. imageWarning.anchor(top: container.topAnchor, right: title.leftAnchor, paddingTop: 10, paddingRight: 5, width: 30, height: 30)
  1820. let imageChat = UIImageView(image: UIImage(named: "pb_startup_iconsuffix", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  1821. container.addSubview(imageChat)
  1822. imageChat.anchor(top: container.topAnchor, left: title.rightAnchor, paddingTop: 10, paddingLeft: 5, width: 30, height: 30)
  1823. let contentS = UILabel()
  1824. contentS.text = content
  1825. contentS.font = .systemFont(ofSize: 12)
  1826. contentS.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
  1827. contentS.numberOfLines = 0
  1828. container.addSubview(contentS)
  1829. contentS.anchor(top: title.bottomAnchor, left: container.leftAnchor, right: container.rightAnchor, paddingTop: 15, paddingLeft: 15, paddingRight: 10)
  1830. let buttonKYC = UIButton(type: .custom)
  1831. let backgroundImageKYC = resizeImage(image: UIImage(named: "pb_security_kyc_center", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: UIScreen.main.bounds.width / 3 - 20, height: 35))
  1832. buttonKYC.setBackgroundImage(backgroundImageKYC, for: .normal)
  1833. buttonKYC.imageView?.contentMode = .scaleAspectFill
  1834. buttonKYC.addTarget(self, action: #selector(kycTapped), for: .touchUpInside)
  1835. buttonKYC.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
  1836. container.addSubview(buttonKYC)
  1837. buttonKYC.anchor(top: contentS.bottomAnchor, paddingTop: 15, centerX: container.centerXAnchor, width: UIScreen.main.bounds.width / 3 - 20, height: 35)
  1838. let buttonTryAgain = UIButton(type: .custom)
  1839. let backgroundImageTryAgain = resizeImage(image: UIImage(named: "pb_security_try_again", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: UIScreen.main.bounds.width / 3 - 20, height: 35))
  1840. buttonTryAgain.setBackgroundImage(backgroundImageTryAgain, for: .normal)
  1841. buttonTryAgain.imageView?.contentMode = .scaleAspectFill
  1842. buttonTryAgain.addTarget(self, action: #selector(tryAgainTapped), for: .touchUpInside)
  1843. buttonTryAgain.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
  1844. container.addSubview(buttonTryAgain)
  1845. buttonTryAgain.anchor(top: contentS.bottomAnchor, right: buttonKYC.leftAnchor, paddingTop: 15, width: UIScreen.main.bounds.width / 3 - 20, height: 35)
  1846. let buttonCancel = UIButton(type: .custom)
  1847. let backgroundImageCancel = resizeImage(image: UIImage(named: "pb_security_cancel", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: UIScreen.main.bounds.width / 3 - 20, height: 35))
  1848. buttonCancel.setBackgroundImage(backgroundImageCancel, for: .normal)
  1849. buttonCancel.imageView?.contentMode = .scaleAspectFill
  1850. buttonCancel.addTarget(self, action: #selector(cancelTapped), for: .touchUpInside)
  1851. buttonCancel.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
  1852. container.addSubview(buttonCancel)
  1853. buttonCancel.anchor(top: contentS.bottomAnchor, left: buttonKYC.rightAnchor, paddingTop: 15, width: UIScreen.main.bounds.width / 3 - 20, height: 35)
  1854. let footer = UILabel()
  1855. footer.text = "We value your security".localized()
  1856. footer.font = .systemFont(ofSize: 12)
  1857. footer.textColor = .gray
  1858. footer.numberOfLines = 0
  1859. container.addSubview(footer)
  1860. footer.anchor(top: buttonCancel.bottomAnchor, bottom: container.bottomAnchor, right: container.rightAnchor, paddingBottom: 5, paddingRight: 10)
  1861. }
  1862. @objc func kycTapped() {
  1863. APIS.openContactCenter()
  1864. self.dismiss(animated: true)
  1865. }
  1866. @objc func tryAgainTapped() {
  1867. //print("tryAgainTapped")
  1868. if !CheckConnection.isConnectedToNetwork() || API.nGetCLXConnState() == 0 {
  1869. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  1870. imageView.tintColor = .white
  1871. 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)
  1872. banner.show()
  1873. return
  1874. }
  1875. Nexilis.showLoader()
  1876. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getAlertNewSignIn(brand: "\(UIDevice().type)", latitude: Utils.latitude, longitude: Utils.longitude), timeout: 30 * 1000) {
  1877. if response.isOk() {
  1878. Nexilis.hideLoader(completion: {
  1879. self.dismiss(animated: true) {
  1880. let dialog = DialogVerifyYou()
  1881. dialog.modalTransitionStyle = .crossDissolve
  1882. dialog.modalPresentationStyle = .overCurrentContext
  1883. UIApplication.shared.visibleViewController?.present(dialog, animated: true)
  1884. }
  1885. })
  1886. } else {
  1887. Nexilis.hideLoader(completion: {
  1888. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  1889. imageView.tintColor = .white
  1890. let banner = FloatingNotificationBanner(title: "Unable to access servers. Try again later".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)
  1891. banner.show()
  1892. })
  1893. }
  1894. }
  1895. }
  1896. @objc func cancelTapped() {
  1897. Utils.setLoginMultipleFPin(value: "")
  1898. self.dismiss(animated: true)
  1899. }
  1900. }
  1901. public class DialogVerifyYou: UIViewController {
  1902. public let content = "To help keep your Account safe, We wants to make sure it's really you trying to Sign-In\n\nA secure notification containing a verification code was just sent to your main Device".localized()
  1903. let textFieldCode = UITextField()
  1904. public override func viewDidLoad() {
  1905. super.viewDidLoad()
  1906. self.view.backgroundColor = .black.withAlphaComponent(0.5)
  1907. let container = UIView()
  1908. self.view.addSubview(container)
  1909. container.anchor(top: self.view.topAnchor, left: self.view.leftAnchor, right: self.view.rightAnchor, paddingTop: 30, paddingLeft: 20, paddingRight: 20)
  1910. container.layer.cornerRadius = 20.0
  1911. container.clipsToBounds = true
  1912. container.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .white
  1913. let title = UILabel()
  1914. title.text = "Verify it's you".localized()
  1915. title.font = .systemFont(ofSize: 14, weight: .medium)
  1916. title.numberOfLines = 0
  1917. title.textAlignment = .center
  1918. title.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
  1919. container.addSubview(title)
  1920. title.anchor(top: container.topAnchor, paddingTop: 15, centerX: container.centerXAnchor, maxWidth: 270)
  1921. let imageAsk = UIImageView(image: UIImage(named: "pb_security_ask", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  1922. container.addSubview(imageAsk)
  1923. imageAsk.anchor(top: container.topAnchor, right: title.leftAnchor, paddingTop: 10, paddingRight: 5, width: 30, height: 30)
  1924. let imageChat = UIImageView(image: UIImage(named: "pb_startup_iconsuffix", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  1925. container.addSubview(imageChat)
  1926. imageChat.anchor(top: container.topAnchor, right: container.rightAnchor, paddingTop: 10, paddingRight: 20, width: 30, height: 30)
  1927. let contentS = UILabel()
  1928. contentS.text = content
  1929. contentS.font = .systemFont(ofSize: 12)
  1930. contentS.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
  1931. contentS.numberOfLines = 0
  1932. container.addSubview(contentS)
  1933. contentS.anchor(top: title.bottomAnchor, left: container.leftAnchor, right: container.rightAnchor, paddingTop: 15, paddingLeft: 15, paddingRight: 10)
  1934. let containerText = UIView()
  1935. container.addSubview(containerText)
  1936. containerText.anchor(top: contentS.bottomAnchor, left: container.leftAnchor, right: container.rightAnchor, paddingTop: 10, paddingLeft: 15, paddingRight: 15, height: 40)
  1937. containerText.layer.cornerRadius = 8.0
  1938. containerText.clipsToBounds = true
  1939. containerText.layer.borderWidth = 3
  1940. containerText.layer.borderColor = UIColor.blueTextField.cgColor
  1941. let containerEnterCode = UIView()
  1942. container.addSubview(containerEnterCode)
  1943. containerEnterCode.anchor(top: contentS.bottomAnchor, left: container.leftAnchor, paddingTop: 2, paddingLeft: 30, height: 20, maxWidth: 150)
  1944. containerEnterCode.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .white
  1945. let titleEnterCode = UILabel()
  1946. containerEnterCode.addSubview(titleEnterCode)
  1947. titleEnterCode.text = "Enter Code".localized()
  1948. titleEnterCode.font = .systemFont(ofSize: 12, weight: .medium)
  1949. titleEnterCode.textColor = .blueTextField
  1950. titleEnterCode.textAlignment = .center
  1951. titleEnterCode.anchor(top: containerEnterCode.topAnchor, left: containerEnterCode.leftAnchor, bottom: containerEnterCode.bottomAnchor, right: containerEnterCode.rightAnchor, paddingLeft: 10, paddingRight: 10)
  1952. let buttonSubmit = UIButton(type: .custom)
  1953. containerText.addSubview(buttonSubmit)
  1954. buttonSubmit.anchor(top: containerText.topAnchor, bottom: containerText.bottomAnchor, right: containerText.rightAnchor, paddingTop: 5, paddingBottom: 5, paddingRight: 5, width: 100)
  1955. buttonSubmit.backgroundColor = .blueTextField
  1956. buttonSubmit.setTitle("Submit".localized(), for: .normal)
  1957. buttonSubmit.titleLabel?.font = .systemFont(ofSize: 10, weight: .medium)
  1958. buttonSubmit.layer.cornerRadius = 5.0
  1959. buttonSubmit.clipsToBounds = true
  1960. buttonSubmit.addTarget(self, action: #selector(submitTapped), for: .touchUpInside)
  1961. container.addSubview(textFieldCode)
  1962. textFieldCode.anchor(top: contentS.bottomAnchor, left: container.leftAnchor, right: buttonSubmit.leftAnchor, paddingTop: 20, paddingLeft: 25, paddingRight: 5, height: 25)
  1963. textFieldCode.keyboardType = .numberPad
  1964. let footer = UILabel()
  1965. footer.text = "We value your security".localized()
  1966. footer.font = .systemFont(ofSize: 12)
  1967. footer.textColor = .gray
  1968. footer.numberOfLines = 0
  1969. container.addSubview(footer)
  1970. footer.anchor(top: containerText.bottomAnchor, bottom: container.bottomAnchor, right: container.rightAnchor, paddingTop: 8, paddingBottom: 5, paddingRight: 10)
  1971. let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissView))
  1972. tapGesture.cancelsTouchesInView = false
  1973. self.view.addGestureRecognizer(tapGesture)
  1974. }
  1975. @objc func submitTapped() {
  1976. //print("submitTapped")
  1977. if textFieldCode.text!.isEmpty {
  1978. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  1979. imageView.tintColor = .white
  1980. let banner = FloatingNotificationBanner(title: "Code can't be empty".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)
  1981. banner.show()
  1982. return
  1983. }
  1984. if !CheckConnection.isConnectedToNetwork() || API.nGetCLXConnState() == 0 {
  1985. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  1986. imageView.tintColor = .white
  1987. 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)
  1988. banner.show()
  1989. return
  1990. }
  1991. Nexilis.showLoader()
  1992. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getShieldSecurityValidateToken(token: textFieldCode.text!), timeout: 30 * 1000) {
  1993. if response.isOk() {
  1994. Nexilis.hideLoader(completion: {
  1995. let fPin = response.getBody(key: CoreMessage_TMessageKey.F_PIN, default_value: "")
  1996. let device_id = response.getBody(key: CoreMessage_TMessageKey.IMEI, default_value: "")
  1997. self.deleteAllRecordDatabase()
  1998. if(!fPin.isEmpty) {
  1999. // Nexilis.changeUser(f_pin: device_id)
  2000. Utils.setLoginMultipleFPin(value: "")
  2001. SecureUserDefaults.shared.set(device_id, forKey: "device_id")
  2002. Utils.setProfile(value: true)
  2003. // pos registration
  2004. _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: fPin))
  2005. DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
  2006. Nexilis.hideLoader(completion: {
  2007. let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
  2008. imageView.tintColor = .white
  2009. let banner = FloatingNotificationBanner(title: "Successfully Sign-In".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)
  2010. banner.show()
  2011. if Nexilis.showFB {
  2012. Nexilis.floatingButton.removeFromSuperview()
  2013. FloatingButton.datePull = nil
  2014. Nexilis.floatingButton = FloatingButton()
  2015. Nexilis.addFB()
  2016. }
  2017. NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onRefreshWebView"), object: nil, userInfo: nil)
  2018. self.dismiss(animated: true)
  2019. })
  2020. })
  2021. }
  2022. })
  2023. } else if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "4t" {
  2024. Nexilis.hideLoader(completion: {
  2025. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  2026. imageView.tintColor = .white
  2027. let banner = FloatingNotificationBanner(title: "Invalid Code".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)
  2028. banner.show()
  2029. self.dismiss(animated: true)
  2030. })
  2031. } else if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "3t" {
  2032. Nexilis.hideLoader(completion: {
  2033. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  2034. imageView.tintColor = .white
  2035. let banner = FloatingNotificationBanner(title: "Expired Code".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)
  2036. banner.show()
  2037. self.dismiss(animated: true)
  2038. })
  2039. } else if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "4u" {
  2040. Nexilis.hideLoader(completion: {
  2041. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  2042. imageView.tintColor = .white
  2043. let banner = FloatingNotificationBanner(title: "You have been blocked".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)
  2044. banner.show()
  2045. self.dismiss(animated: true)
  2046. })
  2047. } else {
  2048. Nexilis.hideLoader(completion: {
  2049. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  2050. imageView.tintColor = .white
  2051. let banner = FloatingNotificationBanner(title: "Unable to access servers. Try again later".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)
  2052. banner.show()
  2053. })
  2054. }
  2055. }
  2056. }
  2057. @objc func dismissView() {
  2058. if textFieldCode.isFirstResponder {
  2059. textFieldCode.resignFirstResponder()
  2060. } else {
  2061. self.dismiss(animated: true)
  2062. }
  2063. }
  2064. }
  2065. public class DialogSignIn: UIViewController {
  2066. public var valueDevice = "Galaxy S21 Ultra 5G"
  2067. public var valueTime = "14:02"
  2068. public var valueLocation = "Surakarta, Central Java"
  2069. public var valueToken = ""
  2070. public var valueUser = ""
  2071. public override func viewDidLoad() {
  2072. super.viewDidLoad()
  2073. self.view.backgroundColor = .black.withAlphaComponent(0.5)
  2074. let container = UIView()
  2075. self.view.addSubview(container)
  2076. container.anchor(top: self.view.topAnchor, left: self.view.leftAnchor, right: self.view.rightAnchor, paddingTop: 30, paddingLeft: 20, paddingRight: 20)
  2077. container.layer.cornerRadius = 20.0
  2078. container.clipsToBounds = true
  2079. container.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .white
  2080. let title = UILabel()
  2081. title.text = "New Sign-In Detected".localized()
  2082. title.font = .systemFont(ofSize: 14, weight: .medium)
  2083. title.numberOfLines = 0
  2084. title.textAlignment = .center
  2085. title.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
  2086. container.addSubview(title)
  2087. title.anchor(top: container.topAnchor, paddingTop: 15, centerX: container.centerXAnchor, maxWidth: 270)
  2088. let imageWarning = UIImageView(image: UIImage(named: "pb_security_warning", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  2089. container.addSubview(imageWarning)
  2090. imageWarning.anchor(top: container.topAnchor, right: title.leftAnchor, paddingTop: 10, paddingRight: 5, width: 30, height: 30)
  2091. let imageChat = UIImageView(image: UIImage(named: "pb_startup_iconsuffix", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  2092. container.addSubview(imageChat)
  2093. imageChat.anchor(top: container.topAnchor, right: container.rightAnchor, paddingTop: 10, paddingRight: 20, width: 30, height: 30)
  2094. let lang: String = SecureUserDefaults.shared.value(forKey: "i18n_language") ?? "en"
  2095. let sContent1 = "We detected a new Sign-In to your Account".localized()
  2096. let sContent2 = "Device".localized()
  2097. let sContent3 = "Time".localized()
  2098. let sContent4 = "Location".localized()
  2099. let sContent5 = "Your Account is at risk if this wasn't you.".localized()
  2100. let fullString = sContent1 + "\n\u{2022}\u{00a0}\u{00a0}" + sContent2 + String(repeating: "\u{00a0}", count: (lang == "id" ? 6 : 10)) + ": " + valueDevice + "\n\u{2022}\u{00a0}\u{00a0}" + sContent3 + String(repeating: "\u{00a0}", count: 13) + ": " + valueTime + "\n\u{2022}\u{00a0}\u{00a0}" + sContent4 + String(repeating: "\u{00a0}", count: (lang == "id" ? 13 : 6)) + ": " + valueLocation + "\n\n" + sContent5;
  2101. let contentFull = NSMutableAttributedString(string: fullString)
  2102. contentFull.addAttributes([.font: UIFont.systemFont(ofSize: 12)], range: NSRange(location: 0, length: fullString.count))
  2103. if let range = fullString.range(of: valueDevice) {
  2104. let index = fullString.distance(from: fullString.startIndex, to: range.lowerBound)
  2105. contentFull.addAttributes([.font: UIFont.systemFont(ofSize: 12, weight: .medium)], range: NSRange(location: index, length: valueDevice.count))
  2106. }
  2107. if let range = fullString.range(of: valueTime) {
  2108. let index = fullString.distance(from: fullString.startIndex, to: range.lowerBound)
  2109. contentFull.addAttributes([.font: UIFont.systemFont(ofSize: 12, weight: .medium)], range: NSRange(location: index, length: valueTime.count))
  2110. }
  2111. if let range = fullString.range(of: valueLocation) {
  2112. let index = fullString.distance(from: fullString.startIndex, to: range.lowerBound)
  2113. contentFull.addAttributes([.font: UIFont.systemFont(ofSize: 12, weight: .medium)], range: NSRange(location: index, length: valueLocation.count))
  2114. }
  2115. let contentS = UILabel()
  2116. contentS.attributedText = contentFull
  2117. contentS.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
  2118. contentS.numberOfLines = 0
  2119. container.addSubview(contentS)
  2120. contentS.anchor(top: title.bottomAnchor, left: container.leftAnchor, right: container.rightAnchor, paddingTop: 15, paddingLeft: 15, paddingRight: 10)
  2121. let buttonCC = UIButton(type: .custom)
  2122. let backgroundImageKYC = resizeImage(image: UIImage(named: "pb_startup_cc", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: UIScreen.main.bounds.width / 3 - 20, height: 35))
  2123. buttonCC.setBackgroundImage(backgroundImageKYC, for: .normal)
  2124. buttonCC.imageView?.contentMode = .scaleAspectFill
  2125. buttonCC.addTarget(self, action: #selector(ccTapped), for: .touchUpInside)
  2126. buttonCC.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
  2127. container.addSubview(buttonCC)
  2128. buttonCC.anchor(top: contentS.bottomAnchor, paddingTop: 10, centerX: container.centerXAnchor, width: UIScreen.main.bounds.width / 3 - 20, height: 35)
  2129. let buttonVerify = UIButton(type: .custom)
  2130. let backgroundImageTryAgain = resizeImage(image: UIImage(named: "pb_security_verify_device", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: UIScreen.main.bounds.width / 3 - 20, height: 35))
  2131. buttonVerify.setBackgroundImage(backgroundImageTryAgain, for: .normal)
  2132. buttonVerify.imageView?.contentMode = .scaleAspectFill
  2133. buttonVerify.addTarget(self, action: #selector(verifyTapped), for: .touchUpInside)
  2134. buttonVerify.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
  2135. container.addSubview(buttonVerify)
  2136. buttonVerify.anchor(top: contentS.bottomAnchor, right: buttonCC.leftAnchor, paddingTop: 10, width: UIScreen.main.bounds.width / 3 - 20, height: 35)
  2137. let buttonBlock = UIButton(type: .custom)
  2138. let backgroundImageCancel = resizeImage(image: UIImage(named: "pb_security_block_device", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: UIScreen.main.bounds.width / 3 - 20, height: 35))
  2139. buttonBlock.setBackgroundImage(backgroundImageCancel, for: .normal)
  2140. buttonBlock.imageView?.contentMode = .scaleAspectFill
  2141. buttonBlock.addTarget(self, action: #selector(blockTapped), for: .touchUpInside)
  2142. buttonBlock.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
  2143. container.addSubview(buttonBlock)
  2144. buttonBlock.anchor(top: contentS.bottomAnchor, left: buttonCC.rightAnchor, paddingTop: 10, width: UIScreen.main.bounds.width / 3 - 20, height: 35)
  2145. let footer = UILabel()
  2146. footer.text = "We value your security".localized()
  2147. footer.font = .systemFont(ofSize: 12)
  2148. footer.textColor = .gray
  2149. footer.numberOfLines = 0
  2150. container.addSubview(footer)
  2151. footer.anchor(top: buttonBlock.bottomAnchor, bottom: container.bottomAnchor, right: container.rightAnchor, paddingBottom: 5, paddingRight: 10)
  2152. }
  2153. @objc func ccTapped() {
  2154. //print("ccTapped")
  2155. self.dismiss(animated: true, completion: {
  2156. APIS.openContactCenter()
  2157. })
  2158. }
  2159. @objc func verifyTapped() {
  2160. //print("verifyTapped")
  2161. self.dismiss(animated: true) {
  2162. let dialog = DialogVerificationCode()
  2163. dialog.valueDevice = self.valueDevice
  2164. dialog.valueCode = self.valueToken
  2165. dialog.modalTransitionStyle = .crossDissolve
  2166. dialog.modalPresentationStyle = .overCurrentContext
  2167. UIApplication.shared.visibleViewController?.present(dialog, animated: true)
  2168. }
  2169. }
  2170. @objc func blockTapped() {
  2171. //print("blockTapped")
  2172. if !CheckConnection.isConnectedToNetwork() || API.nGetCLXConnState() == 0 {
  2173. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  2174. imageView.tintColor = .white
  2175. 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)
  2176. banner.show()
  2177. return
  2178. }
  2179. Nexilis.showLoader()
  2180. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getBlockAccess(userId: valueUser), timeout: 30 * 1000) {
  2181. if response.isOk() {
  2182. Nexilis.hideLoader(completion: {
  2183. let imageView = UIImageView(image: UIImage(systemName: "info.circle"))
  2184. imageView.tintColor = .white
  2185. let banner = FloatingNotificationBanner(title: "The other device has been blocked".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)
  2186. banner.show()
  2187. self.dismiss(animated: true)
  2188. })
  2189. } else {
  2190. Nexilis.hideLoader(completion: {
  2191. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  2192. imageView.tintColor = .white
  2193. let banner = FloatingNotificationBanner(title: "Unable to access servers. Try again later".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)
  2194. banner.show()
  2195. })
  2196. }
  2197. }
  2198. }
  2199. }
  2200. public class DialogVerificationCode: UIViewController {
  2201. public var valueDevice = "Galaxy S21 Ultra 5G"
  2202. public var valueAccount = "1001001234."
  2203. public var valueCode = "900214"
  2204. public override func viewDidLoad() {
  2205. super.viewDidLoad()
  2206. self.view.backgroundColor = .black.withAlphaComponent(0.5)
  2207. let container = UIView()
  2208. self.view.addSubview(container)
  2209. container.anchor(top: self.view.topAnchor, left: self.view.leftAnchor, right: self.view.rightAnchor, paddingTop: 30, paddingLeft: 20, paddingRight: 20)
  2210. container.layer.cornerRadius = 20.0
  2211. container.clipsToBounds = true
  2212. container.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .white
  2213. let title = UILabel()
  2214. title.text = "Nexilis Verification Code".localized()
  2215. title.font = .systemFont(ofSize: 14, weight: .medium)
  2216. title.numberOfLines = 0
  2217. title.textAlignment = .center
  2218. title.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
  2219. container.addSubview(title)
  2220. title.anchor(top: container.topAnchor, paddingTop: 15, centerX: container.centerXAnchor, maxWidth: 270)
  2221. let imageInfo = UIImageView(image: UIImage(named: "pb_security_information", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  2222. container.addSubview(imageInfo)
  2223. imageInfo.anchor(top: container.topAnchor, right: title.leftAnchor, paddingTop: 10, paddingRight: 5, width: 30, height: 30)
  2224. let imageMail = UIImageView(image: UIImage(named: "pb_security_message", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  2225. container.addSubview(imageMail)
  2226. imageMail.anchor(top: container.topAnchor, right: container.rightAnchor, paddingTop: 10, paddingRight: 20, width: 30, height: 30)
  2227. let sContent1 = "We received a request to verify the Sign-In from".localized()
  2228. let sContent2 = "to your Account".localized()
  2229. let sContent3 = "Your Nexilis verification code is".localized()
  2230. let sContent4 = "(do not forward or give this code to anyone)".localized()
  2231. let sContent5 = "If you did not request this code, it is possible that someone else is trying to access the Account.".localized()
  2232. let fullString = sContent1 + " " + valueDevice + " " + sContent2 + " " + valueAccount + " " + sContent3 + ":\n\n" + valueCode + " " + sContent4 + "\n\n" + sContent5;
  2233. let contentFull = NSMutableAttributedString(string: fullString)
  2234. contentFull.addAttributes([.font: UIFont.systemFont(ofSize: 12), .foregroundColor: (self.traitCollection.userInterfaceStyle == .dark ? UIColor.white : UIColor.black)], range: NSRange(location: 0, length: fullString.count))
  2235. if let range = fullString.range(of: valueDevice) {
  2236. let index = fullString.distance(from: fullString.startIndex, to: range.lowerBound)
  2237. contentFull.addAttributes([.font: UIFont.systemFont(ofSize: 12, weight: .medium)], range: NSRange(location: index, length: valueDevice.count))
  2238. }
  2239. if let range = fullString.range(of: valueAccount) {
  2240. let index = fullString.distance(from: fullString.startIndex, to: range.lowerBound)
  2241. contentFull.addAttributes([.foregroundColor: UIColor.blueTextField], range: NSRange(location: index, length: valueAccount.count))
  2242. }
  2243. if let range = fullString.range(of: valueCode) {
  2244. let index = fullString.distance(from: fullString.startIndex, to: range.lowerBound)
  2245. contentFull.addAttributes([.font: UIFont.systemFont(ofSize: 18, weight: .medium)], range: NSRange(location: index, length: valueCode.count))
  2246. }
  2247. if let range = fullString.range(of: sContent4) {
  2248. let index = fullString.distance(from: fullString.startIndex, to: range.lowerBound)
  2249. contentFull.addAttributes([.foregroundColor: UIColor.systemRed], range: NSRange(location: index, length: sContent4.count))
  2250. }
  2251. let contentS = UILabel()
  2252. contentS.attributedText = contentFull
  2253. contentS.numberOfLines = 0
  2254. container.addSubview(contentS)
  2255. contentS.anchor(top: title.bottomAnchor, left: container.leftAnchor, right: container.rightAnchor, paddingTop: 15, paddingLeft: 15, paddingRight: 10)
  2256. let footer = UILabel()
  2257. footer.text = "We value your security".localized()
  2258. footer.font = .systemFont(ofSize: 12)
  2259. footer.textColor = .gray
  2260. footer.numberOfLines = 0
  2261. container.addSubview(footer)
  2262. footer.anchor(top: contentS.bottomAnchor, bottom: container.bottomAnchor, right: container.rightAnchor, paddingTop: 10, paddingBottom: 5, paddingRight: 10)
  2263. let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissView))
  2264. tapGesture.cancelsTouchesInView = false
  2265. self.view.addGestureRecognizer(tapGesture)
  2266. }
  2267. @objc func dismissView() {
  2268. self.dismiss(animated: true)
  2269. }
  2270. }
  2271. public class DialogSecurityShield: UIViewController {
  2272. public override func viewDidLoad() {
  2273. super.viewDidLoad()
  2274. self.view.backgroundColor = .black.withAlphaComponent(0.5)
  2275. let container = UIView()
  2276. self.view.addSubview(container)
  2277. container.anchor(top: self.view.topAnchor, left: self.view.leftAnchor, right: self.view.rightAnchor, paddingTop: 30, paddingLeft: 20, paddingRight: 20)
  2278. container.layer.cornerRadius = 20.0
  2279. container.clipsToBounds = true
  2280. container.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .white
  2281. let title = UILabel()
  2282. title.text = "Your Account is Protected".localized()
  2283. title.font = .systemFont(ofSize: 14, weight: .medium)
  2284. title.numberOfLines = 0
  2285. title.textAlignment = .center
  2286. title.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
  2287. container.addSubview(title)
  2288. title.anchor(top: container.topAnchor, paddingTop: 15, centerX: container.centerXAnchor, maxWidth: 270)
  2289. let imageWarning = UIImageView(image: UIImage(named: "pb_security_warning_green", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  2290. container.addSubview(imageWarning)
  2291. imageWarning.anchor(top: container.topAnchor, right: title.leftAnchor, paddingTop: 10, paddingRight: 5, width: 30, height: 30)
  2292. let imageChat = UIImageView(image: UIImage(named: "pb_startup_iconsuffix", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  2293. container.addSubview(imageChat)
  2294. imageChat.anchor(top: container.topAnchor, right: container.rightAnchor, paddingTop: 10, paddingRight: 20, width: 30, height: 30)
  2295. let sContent1 = "Security Shield has been activated for your Peace of Mind...".localized()
  2296. let sContent2 = "Account & Transaction Protection".localized()
  2297. let sContent3 = "Early Threat Detection".localized()
  2298. let sContent4 = "Emergency Data Control".localized()
  2299. let sContent5 = "Please feel free to contact us for more information.".localized()
  2300. let fullString = sContent1 + "\n\u{2022}" + String(repeating: "\u{00a0}", count: 2) + sContent2 + "\n\u{2022}" + String(repeating: "\u{00a0}", count: 2) + sContent3 + "\n\u{2022}" + String(repeating: "\u{00a0}", count: 2) + sContent4 + "\n" + sContent5;
  2301. let contentS = UILabel()
  2302. contentS.text = fullString
  2303. contentS.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
  2304. contentS.numberOfLines = 0
  2305. contentS.font = .systemFont(ofSize: 12)
  2306. container.addSubview(contentS)
  2307. contentS.anchor(top: title.bottomAnchor, left: container.leftAnchor, right: container.rightAnchor, paddingTop: 15, paddingLeft: 15, paddingRight: 10)
  2308. let buttonCC = UIButton(type: .custom)
  2309. let backgroundImageKYC = resizeImage(image: UIImage(named: "pb_startup_cc", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: UIScreen.main.bounds.width / 3 - 20, height: 35))
  2310. buttonCC.setBackgroundImage(backgroundImageKYC, for: .normal)
  2311. buttonCC.imageView?.contentMode = .scaleAspectFill
  2312. buttonCC.addTarget(self, action: #selector(ccTapped), for: .touchUpInside)
  2313. buttonCC.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
  2314. container.addSubview(buttonCC)
  2315. buttonCC.anchor(top: contentS.bottomAnchor, paddingTop: 10, centerX: container.centerXAnchor, width: UIScreen.main.bounds.width / 3 - 20, height: 35)
  2316. let buttonActive = UIButton(type: .custom)
  2317. let backgroundImageTryAgain = resizeImage(image: UIImage(named: "pb_startup_activate", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: UIScreen.main.bounds.width / 3 - 20, height: 35))
  2318. buttonActive.setBackgroundImage(backgroundImageTryAgain, for: .normal)
  2319. buttonActive.imageView?.contentMode = .scaleAspectFill
  2320. buttonActive.addTarget(self, action: #selector(activateTapped), for: .touchUpInside)
  2321. buttonActive.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
  2322. container.addSubview(buttonActive)
  2323. buttonActive.anchor(top: contentS.bottomAnchor, right: buttonCC.leftAnchor, paddingTop: 10, width: UIScreen.main.bounds.width / 3 - 20, height: 35)
  2324. let buttonDeactive = UIButton(type: .custom)
  2325. let backgroundImageCancel = resizeImage(image: UIImage(named: "pb_startup_deactivate", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: UIScreen.main.bounds.width / 3 - 20, height: 35))
  2326. buttonDeactive.setBackgroundImage(backgroundImageCancel, for: .normal)
  2327. buttonDeactive.imageView?.contentMode = .scaleAspectFill
  2328. buttonDeactive.addTarget(self, action: #selector(deactiveTapped), for: .touchUpInside)
  2329. buttonDeactive.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
  2330. container.addSubview(buttonDeactive)
  2331. buttonDeactive.anchor(top: contentS.bottomAnchor, left: buttonCC.rightAnchor, paddingTop: 10, width: UIScreen.main.bounds.width / 3 - 20, height: 35)
  2332. let footer = UILabel()
  2333. footer.text = "We value your security".localized()
  2334. footer.font = .systemFont(ofSize: 12)
  2335. footer.textColor = .gray
  2336. footer.numberOfLines = 0
  2337. container.addSubview(footer)
  2338. footer.anchor(top: buttonDeactive.bottomAnchor, bottom: container.bottomAnchor, right: container.rightAnchor, paddingBottom: 5, paddingRight: 10)
  2339. let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissView))
  2340. tapGesture.cancelsTouchesInView = false
  2341. self.view.addGestureRecognizer(tapGesture)
  2342. }
  2343. @objc func ccTapped() {
  2344. //print("ccTapped")
  2345. self.dismiss(animated: true, completion: {
  2346. APIS.openContactCenter()
  2347. })
  2348. }
  2349. @objc func activateTapped() {
  2350. //print("activateTapped")
  2351. self.dismiss(animated: true)
  2352. }
  2353. @objc func deactiveTapped() {
  2354. //print("deactiveTapped")
  2355. self.dismiss(animated: true)
  2356. }
  2357. @objc func dismissView() {
  2358. self.dismiss(animated: true)
  2359. }
  2360. }
  2361. public class DialogTransactionApproval: UIViewController {
  2362. public var valueLink = "https://hdtrack.com"
  2363. public var valueAmount = "$142.90"
  2364. public var packetId = ""
  2365. public override func viewDidLoad() {
  2366. super.viewDidLoad()
  2367. self.view.backgroundColor = .black.withAlphaComponent(0.5)
  2368. let container = UIView()
  2369. self.view.addSubview(container)
  2370. container.anchor(top: self.view.topAnchor, left: self.view.leftAnchor, right: self.view.rightAnchor, paddingTop: 30, paddingLeft: 20, paddingRight: 20)
  2371. container.layer.cornerRadius = 20.0
  2372. container.clipsToBounds = true
  2373. container.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .white
  2374. let title = UILabel()
  2375. title.text = "Transaction Approval Request".localized()
  2376. title.font = .systemFont(ofSize: 14, weight: .medium)
  2377. title.numberOfLines = 0
  2378. title.textAlignment = .center
  2379. title.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
  2380. container.addSubview(title)
  2381. title.anchor(top: container.topAnchor, paddingTop: 15, centerX: container.centerXAnchor, maxWidth: 270)
  2382. let imageWarning = UIImageView(image: UIImage(named: "pb_security_warning", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  2383. container.addSubview(imageWarning)
  2384. imageWarning.anchor(top: container.topAnchor, right: title.leftAnchor, paddingTop: 10, paddingRight: 5, width: 30, height: 30)
  2385. let imageChat = UIImageView(image: UIImage(named: "pb_startup_iconsuffix", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  2386. container.addSubview(imageChat)
  2387. imageChat.anchor(top: container.topAnchor, right: container.rightAnchor, paddingTop: 10, paddingRight: 20, width: 30, height: 30)
  2388. let sContent1 = "We have detected a".localized()
  2389. let sContent1a = "Rp."
  2390. let sContent2 = "transaction using credit card no. XXXX-XXXX-XXXX-1234 on".localized()
  2391. let sContent3 = "Before processing your payment, kindly verify and confirm the transaction details.".localized()
  2392. let fullString = sContent1 + " " + sContent1a + " " + formatText(valueAmount) + " " + sContent2 + " " + valueLink + ".\n\n" + sContent3
  2393. let contentFull = NSMutableAttributedString(string: fullString)
  2394. contentFull.addAttributes([.font: UIFont.systemFont(ofSize: 12), .foregroundColor: (self.traitCollection.userInterfaceStyle == .dark ? UIColor.white : UIColor.black)], range: NSRange(location: 0, length: fullString.count))
  2395. if let range = fullString.range(of: valueLink) {
  2396. let index = fullString.distance(from: fullString.startIndex, to: range.lowerBound)
  2397. contentFull.addAttributes([.foregroundColor: UIColor.red, .underlineStyle: NSUnderlineStyle.single.rawValue, .link: URL(string: valueLink)!], range: NSRange(location: index, length: valueLink.count))
  2398. }
  2399. let contentS = UILabel()
  2400. contentS.attributedText = contentFull
  2401. contentS.numberOfLines = 0
  2402. container.addSubview(contentS)
  2403. contentS.anchor(top: title.bottomAnchor, left: container.leftAnchor, right: container.rightAnchor, paddingTop: 15, paddingLeft: 15, paddingRight: 10)
  2404. contentS.isUserInteractionEnabled = true
  2405. let tapGesture = UITapGestureRecognizer(target: self, action: #selector(labelTapped))
  2406. contentS.addGestureRecognizer(tapGesture)
  2407. let buttonCC = UIButton(type: .custom)
  2408. let backgroundImageKYC = resizeImage(image: UIImage(named: "pb_startup_cc", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: UIScreen.main.bounds.width / 3 - 20, height: 35))
  2409. buttonCC.setBackgroundImage(backgroundImageKYC, for: .normal)
  2410. buttonCC.imageView?.contentMode = .scaleAspectFill
  2411. buttonCC.addTarget(self, action: #selector(ccTapped), for: .touchUpInside)
  2412. buttonCC.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
  2413. container.addSubview(buttonCC)
  2414. buttonCC.anchor(top: contentS.bottomAnchor, paddingTop: 10, centerX: container.centerXAnchor, width: UIScreen.main.bounds.width / 3 - 20, height: 35)
  2415. let buttonApprove = UIButton(type: .custom)
  2416. let backgroundImageTryAgain = resizeImage(image: UIImage(named: "pb_security_approve", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: UIScreen.main.bounds.width / 3 - 20, height: 35))
  2417. buttonApprove.setBackgroundImage(backgroundImageTryAgain, for: .normal)
  2418. buttonApprove.imageView?.contentMode = .scaleAspectFill
  2419. buttonApprove.addTarget(self, action: #selector(approveTapped), for: .touchUpInside)
  2420. buttonApprove.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
  2421. container.addSubview(buttonApprove)
  2422. buttonApprove.anchor(top: contentS.bottomAnchor, right: buttonCC.leftAnchor, paddingTop: 10, width: UIScreen.main.bounds.width / 3 - 20, height: 35)
  2423. let buttonReject = UIButton(type: .custom)
  2424. let backgroundImageCancel = resizeImage(image: UIImage(named: "pb_security_reject", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: UIScreen.main.bounds.width / 3 - 20, height: 35))
  2425. buttonReject.setBackgroundImage(backgroundImageCancel, for: .normal)
  2426. buttonReject.imageView?.contentMode = .scaleAspectFill
  2427. buttonReject.addTarget(self, action: #selector(rejectTapped), for: .touchUpInside)
  2428. buttonReject.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
  2429. container.addSubview(buttonReject)
  2430. buttonReject.anchor(top: contentS.bottomAnchor, left: buttonCC.rightAnchor, paddingTop: 10, width: UIScreen.main.bounds.width / 3 - 20, height: 35)
  2431. let footer = UILabel()
  2432. footer.text = "We value your security".localized()
  2433. footer.font = .systemFont(ofSize: 12)
  2434. footer.textColor = .gray
  2435. footer.numberOfLines = 0
  2436. container.addSubview(footer)
  2437. footer.anchor(top: buttonReject.bottomAnchor, bottom: container.bottomAnchor, right: container.rightAnchor, paddingBottom: 5, paddingRight: 10)
  2438. }
  2439. @objc func ccTapped() {
  2440. //print("ccTapped")
  2441. self.dismiss(animated: true, completion: {
  2442. APIS.openContactCenter()
  2443. })
  2444. }
  2445. @objc func approveTapped() {
  2446. //print("approveTapped")
  2447. // _ = Nexilis.responseString(packetId: packetId, message: "00", timeout: 3000)
  2448. self.dismiss(animated: true)
  2449. }
  2450. @objc func rejectTapped() {
  2451. //print("rejectTapped")
  2452. // _ = Nexilis.responseString(packetId: packetId, message: "00", timeout: 3000)
  2453. self.dismiss(animated: true)
  2454. }
  2455. @objc func labelTapped(sender: UITapGestureRecognizer) {
  2456. guard let url = URL(string: valueLink) else { return }
  2457. UIApplication.shared.open(url)
  2458. }
  2459. func formatText(_ s: String) -> String {
  2460. let text = s
  2461. if text.isEmpty { return "" }
  2462. let cleanString = text.replacingOccurrences(of: "[^\\d]", with: "", options: .regularExpression)
  2463. let formatter = NumberFormatter()
  2464. formatter.numberStyle = .decimal
  2465. formatter.locale = Locale(identifier: "en_US")
  2466. let formattedString = formatter.string(from: NSNumber(value: Int(cleanString)!)) ?? ""
  2467. return formattedString
  2468. }
  2469. }
  2470. public class ValidationTransactionLimit: UIViewController, UITextFieldDelegate {
  2471. var textField = UITextField()
  2472. var formatter = NumberFormatter()
  2473. public override func viewDidLoad() {
  2474. super.viewDidLoad()
  2475. navigationController?.navigationBar.tintColor = .white
  2476. navigationController?.navigationBar.topItem?.backButtonTitle = ""
  2477. let title = UILabel()
  2478. title.text = "Set a transation validation amount".localized()
  2479. title.font = .systemFont(ofSize: 18, weight: .medium)
  2480. title.numberOfLines = 0
  2481. title.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor
  2482. self.view.addSubview(title)
  2483. title.anchor(top: self.view.safeAreaLayoutGuide.topAnchor, left: self.view.leftAnchor, right: self.view.rightAnchor, paddingTop: 10, paddingLeft: 20, paddingRight: 20)
  2484. let content = UILabel()
  2485. content.text = "Any transaction over this amount will display an alert and require you to accept the alert to validate before proceeding with the transaction".localized()
  2486. content.font = .systemFont(ofSize: 14)
  2487. content.numberOfLines = 0
  2488. content.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor
  2489. self.view.addSubview(content)
  2490. content.anchor(top: title.bottomAnchor, left: self.view.leftAnchor, right: self.view.rightAnchor, paddingTop: 5, paddingLeft: 20, paddingRight: 20)
  2491. self.view.addSubview(textField)
  2492. textField.anchor(top: content.bottomAnchor, left: self.view.leftAnchor, right: self.view.rightAnchor, paddingTop: 5, paddingLeft: 20, paddingRight: 20, height: 40)
  2493. textField.textAlignment = .center
  2494. textField.keyboardType = .numberPad
  2495. textField.layer.borderWidth = 1
  2496. textField.layer.borderColor = UIColor.gray.cgColor
  2497. textField.layer.cornerRadius = 10
  2498. textField.clipsToBounds = true
  2499. textField.text = formatText(Utils.getLimitValidTrans())
  2500. textField.delegate = self
  2501. }
  2502. public override func viewDidAppear(_ animated: Bool) {
  2503. navigationController?.navigationBar.topItem?.backButtonTitle = ""
  2504. navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Submit".localized(), style: .plain, target: self, action: #selector(submit))
  2505. let attributes = [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 16.0), NSAttributedString.Key.foregroundColor: UIColor.white]
  2506. let navBarAppearance = UINavigationBarAppearance()
  2507. navBarAppearance.configureWithOpaqueBackground()
  2508. navBarAppearance.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : UIColor.mainColor
  2509. navBarAppearance.titleTextAttributes = attributes
  2510. navigationController?.navigationBar.standardAppearance = navBarAppearance
  2511. navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
  2512. self.navigationController?.navigationBar.topItem?.title = "Validation Transaction Limit".localized()
  2513. self.navigationController?.navigationBar.setNeedsLayout()
  2514. self.title = "Validation Transaction Limit".localized()
  2515. }
  2516. @objc func submit() {
  2517. if !textField.text!.isEmpty {
  2518. var text = textField.text!
  2519. text = text.replacingOccurrences(of: ",", with: "", options: .regularExpression)
  2520. Utils.setLimitValidTrans(value: text)
  2521. let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
  2522. imageView.tintColor = .white
  2523. let banner = FloatingNotificationBanner(title: "Successfully changed".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)
  2524. banner.show()
  2525. self.navigationController?.popViewController(animated: true)
  2526. }
  2527. }
  2528. public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
  2529. guard string != "\n" else {
  2530. return true
  2531. }
  2532. let currentText = textField.text ?? ""
  2533. let newText = (currentText as NSString).replacingCharacters(in: range, with: string)
  2534. let formattedNumber = formatText(newText)
  2535. if formattedNumber.count <= 13 {
  2536. textField.text = formattedNumber
  2537. }
  2538. return false
  2539. }
  2540. func formatText(_ s: String) -> String {
  2541. let text = s
  2542. if text.isEmpty { return "" }
  2543. let cleanString = text.replacingOccurrences(of: "[^\\d]", with: "", options: .regularExpression)
  2544. let formatter = NumberFormatter()
  2545. formatter.numberStyle = .decimal
  2546. formatter.locale = Locale(identifier: "en_US")
  2547. let formattedString = formatter.string(from: NSNumber(value: Int(cleanString)!)) ?? ""
  2548. return formattedString
  2549. }
  2550. }
  2551. public class DialogErrorMFA: UIViewController {
  2552. public var errorDesc = ""
  2553. public var method = ""
  2554. public var hideTryAgain = false
  2555. var isDismiss: ((Int) -> ())?
  2556. public override func viewDidLoad() {
  2557. super.viewDidLoad()
  2558. self.view.backgroundColor = .black.withAlphaComponent(0.5)
  2559. let container = UIView()
  2560. self.view.addSubview(container)
  2561. container.anchor(top: self.view.topAnchor, left: self.view.leftAnchor, right: self.view.rightAnchor, paddingTop: 30, paddingLeft: 20, paddingRight: 20)
  2562. container.layer.cornerRadius = 20.0
  2563. container.clipsToBounds = true
  2564. container.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .white
  2565. let title = UILabel()
  2566. title.text = errorDesc
  2567. title.font = .boldSystemFont(ofSize: 14)
  2568. title.numberOfLines = 0
  2569. title.textAlignment = .center
  2570. title.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
  2571. container.addSubview(title)
  2572. title.anchor(top: container.topAnchor, paddingTop: 15, centerX: container.centerXAnchor, maxWidth: UIScreen.main.bounds.width / 2)
  2573. let imageWarning = UIImageView(image: UIImage(named: "pb_security_warning_green", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  2574. container.addSubview(imageWarning)
  2575. imageWarning.anchor(top: container.topAnchor, right: title.leftAnchor, paddingTop: 10, paddingRight: -5, width: 30, height: 30)
  2576. let imageLogo = UIImageView(image: UIImage(named: "bjb-blue-flat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  2577. container.addSubview(imageLogo)
  2578. imageLogo.anchor(top: container.topAnchor, left: container.leftAnchor, paddingTop: 10, paddingLeft: 10, width: 40, height: 40)
  2579. let imageChat = UIImageView(image: UIImage(named: "pb_startup_iconsuffix", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  2580. container.addSubview(imageChat)
  2581. imageChat.anchor(top: container.topAnchor, right: container.rightAnchor, paddingTop: 10, paddingRight: 10, width: 30, height: 30)
  2582. var contentDesc = "Silakan coba lagi atau hubungi Contact Center BJB untuk bantuan lebih lanjut"
  2583. if hideTryAgain {
  2584. contentDesc = "Silakan hubungi Contact Center BJB untuk bantuan lebih lanjut atau Silahkan Sign Up/Sign In Ulang"
  2585. }
  2586. let contentS = UILabel()
  2587. contentS.tintColor = .label
  2588. contentS.attributedText = contentDesc.richText()
  2589. contentS.numberOfLines = 0
  2590. container.addSubview(contentS)
  2591. contentS.anchor(top: title.bottomAnchor, left: container.leftAnchor, right: container.rightAnchor, paddingTop: 20, paddingLeft: 15, paddingRight: 10)
  2592. let buttonCC = UIButton(type: .custom)
  2593. buttonCC.setTitle("Call Center", for: .normal)
  2594. buttonCC.backgroundColor = .gray
  2595. buttonCC.titleLabel?.textColor = .white
  2596. buttonCC.titleLabel?.font = .boldSystemFont(ofSize: 14)
  2597. buttonCC.layer.cornerRadius = 17.5
  2598. buttonCC.clipsToBounds = true
  2599. buttonCC.addTarget(self, action: #selector(ccTapped), for: .touchUpInside)
  2600. container.addSubview(buttonCC)
  2601. if !hideTryAgain {
  2602. buttonCC.anchor(top: contentS.bottomAnchor, paddingTop: 20, centerX: container.centerXAnchor, width: UIScreen.main.bounds.width / 3 - 30, height: 35)
  2603. } else {
  2604. buttonCC.anchor(top: contentS.bottomAnchor, left: container.leftAnchor, paddingTop: 20, paddingLeft: 5, width: UIScreen.main.bounds.width / 2 - 30, height: 35)
  2605. }
  2606. if !hideTryAgain {
  2607. let buttonTryAgain = UIButton(type: .custom)
  2608. buttonTryAgain.setTitle("Coba Lagi", for: .normal)
  2609. buttonTryAgain.backgroundColor = .mainColor
  2610. buttonTryAgain.titleLabel?.textColor = .white
  2611. buttonTryAgain.titleLabel?.font = .boldSystemFont(ofSize: 14)
  2612. buttonTryAgain.layer.cornerRadius = 17.5
  2613. buttonTryAgain.clipsToBounds = true
  2614. buttonTryAgain.addTarget(self, action: #selector(tryAgainTapped), for: .touchUpInside)
  2615. container.addSubview(buttonTryAgain)
  2616. buttonTryAgain.anchor(top: contentS.bottomAnchor, right: buttonCC.leftAnchor, paddingTop: 20, paddingRight: 5, width: UIScreen.main.bounds.width / 3 - 30, height: 35)
  2617. }
  2618. let buttonReject = UIButton(type: .custom)
  2619. buttonReject.setTitle("Tutup", for: .normal)
  2620. buttonReject.backgroundColor = .red
  2621. buttonReject.titleLabel?.textColor = .white
  2622. buttonReject.titleLabel?.font = .boldSystemFont(ofSize: 14)
  2623. buttonReject.layer.cornerRadius = 17.5
  2624. buttonReject.clipsToBounds = true
  2625. buttonReject.addTarget(self, action: #selector(rejectTapped), for: .touchUpInside)
  2626. container.addSubview(buttonReject)
  2627. if !hideTryAgain {
  2628. buttonReject.anchor(top: contentS.bottomAnchor, left: buttonCC.rightAnchor, paddingTop: 20, paddingLeft: 5, width: UIScreen.main.bounds.width / 3 - 30, height: 35)
  2629. } else {
  2630. buttonReject.anchor(top: contentS.bottomAnchor, right: container.rightAnchor, paddingTop: 20, paddingRight: 5, width: UIScreen.main.bounds.width / 2 - 30, height: 35)
  2631. }
  2632. let footer = UILabel()
  2633. footer.text = "We value your security".localized()
  2634. footer.font = .systemFont(ofSize: 12)
  2635. footer.textColor = .gray
  2636. footer.numberOfLines = 0
  2637. container.addSubview(footer)
  2638. footer.anchor(top: buttonReject.bottomAnchor, bottom: container.bottomAnchor, right: container.rightAnchor, paddingBottom: 5, paddingRight: 10)
  2639. }
  2640. private func getContentDesc() -> String {
  2641. return "Saya mengalami hambatan pada waktu *\(method)*, dikarenakan *\(errorDesc)*"
  2642. }
  2643. @objc func ccTapped() {
  2644. let contentDesc = getContentDesc()
  2645. self.dismiss(animated: true, completion: { [self] in
  2646. APIS.openContactCenterWithContext(context: "\(contentDesc)~\(method)~\(errorDesc)")
  2647. })
  2648. }
  2649. @objc func tryAgainTapped() {
  2650. self.dismiss(animated: true, completion: {
  2651. self.isDismiss?(1)
  2652. })
  2653. }
  2654. @objc func rejectTapped() {
  2655. self.dismiss(animated: true)
  2656. self.isDismiss?(0)
  2657. }
  2658. }
  2659. public class DialogBroadcastInApp: UIViewController {
  2660. public var form: FormM!
  2661. public var formItem: FormItemM!
  2662. public var labelForm = ""
  2663. public var listTitleButton: [String] = []
  2664. public var message: [String: Any] = [:]
  2665. private var iconTitleImage: UIImage?
  2666. private var iconSuffixImage: UIImage?
  2667. private var buttonBackgroundImages: [Int: UIImage] = [:]
  2668. public override func viewDidLoad() {
  2669. super.viewDidLoad()
  2670. self.view.backgroundColor = .black.withAlphaComponent(0.3)
  2671. DispatchQueue.global().async {
  2672. self.loadDataAndBuildUI()
  2673. }
  2674. }
  2675. private func setupUI() {
  2676. let container = UIView()
  2677. self.view.addSubview(container)
  2678. container.anchor(left: self.view.leftAnchor, right: self.view.rightAnchor, paddingLeft: 20, paddingRight: 20, centerY: self.view.centerYAnchor)
  2679. container.layer.cornerRadius = 20.0
  2680. container.clipsToBounds = true
  2681. container.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .white
  2682. let title = UILabel()
  2683. title.text = form.title
  2684. title.font = .boldSystemFont(ofSize: 14)
  2685. title.numberOfLines = 0
  2686. title.textAlignment = .center
  2687. title.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
  2688. container.addSubview(title)
  2689. title.anchor(top: container.topAnchor, paddingTop: 15, centerX: container.centerXAnchor, maxWidth: UIScreen.main.bounds.width / 2)
  2690. let defaultWarningImage = UIImage(named: "pb_security_warning_green", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
  2691. let imageWarning = UIImageView(image: self.iconTitleImage ?? defaultWarningImage)
  2692. container.addSubview(imageWarning)
  2693. imageWarning.anchor(top: container.topAnchor, right: title.leftAnchor, paddingTop: 10, paddingRight: -5, width: 30, height: 30)
  2694. let imageLogo = UIImageView(image: UIImage(named: "bjb-blue-flat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
  2695. container.addSubview(imageLogo)
  2696. imageLogo.anchor(top: container.topAnchor, left: container.leftAnchor, paddingTop: 10, paddingLeft: 10, width: 40, height: 40)
  2697. let defaultChatImage = UIImage(named: "pb_startup_iconsuffix", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
  2698. let imageChat = UIImageView(image: self.iconSuffixImage ?? defaultChatImage)
  2699. container.addSubview(imageChat)
  2700. imageChat.anchor(top: container.topAnchor, right: container.rightAnchor, paddingTop: 10, paddingRight: 10, width: 30, height: 30)
  2701. let content = labelForm
  2702. var contentAtt = NSAttributedString(string: "")
  2703. let contentS = UITextView()
  2704. contentS.tintColor = .label
  2705. if HtmlUtils.hasHtmlTag(content) {
  2706. contentAtt = HtmlUtils.toHTMLPreview(content)
  2707. contentS.attributedText = contentAtt
  2708. } else {
  2709. contentS.attributedText = content.richText()
  2710. }
  2711. contentS.isEditable = false
  2712. contentS.isScrollEnabled = false
  2713. contentS.dataDetectorTypes = [.link]
  2714. container.addSubview(contentS)
  2715. contentS.anchor(top: title.bottomAnchor, left: container.leftAnchor, right: container.rightAnchor, paddingTop: 20, paddingLeft: 15, paddingRight: 10)
  2716. let spacing: CGFloat = 5
  2717. let buttonHeight: CGFloat = 35
  2718. let maxPerRow = 3
  2719. let parentWidth = UIScreen.main.bounds.width - 40
  2720. let containerButton = UIView()
  2721. container.addSubview(containerButton)
  2722. containerButton.anchor(top: contentS.bottomAnchor, left: container.leftAnchor, right: container.rightAnchor, width: parentWidth)
  2723. let buttonWidth = (parentWidth - (CGFloat(maxPerRow + 1) * spacing)) / CGFloat(maxPerRow)
  2724. var finalRow = 1
  2725. for (index, title) in listTitleButton.enumerated() {
  2726. let row = index / maxPerRow
  2727. let col = index % maxPerRow
  2728. let x = spacing + CGFloat(col) * (buttonWidth + spacing)
  2729. let y = spacing + CGFloat(row) * (buttonHeight + spacing)
  2730. var finalTitleButton = title
  2731. if title.starts(with: "call_") {
  2732. finalTitleButton = "Call " + title.components(separatedBy: "_")[1]
  2733. } else if title == "cc" {
  2734. finalTitleButton = "Contact Center"
  2735. }
  2736. let button = UIButton(type: .system)
  2737. button.frame = CGRect(x: x, y: y, width: buttonWidth, height: buttonHeight)
  2738. button.layer.cornerRadius = 17.5
  2739. button.clipsToBounds = true
  2740. button.titleLabel?.font = .boldSystemFont(ofSize: 14)
  2741. button.setTitleColor(.white, for: .normal)
  2742. button.addAction{ btn in
  2743. if title == "cc" {
  2744. if self.form.formId == "212953" || self.form.formId == "112903"{
  2745. APIS.openContactCenterWithContext(context: self.formItem.label + "~Transaction~Credit Card~Fraud")
  2746. } else {
  2747. APIS.openContactCenterWithContext(context: self.formItem.label)
  2748. }
  2749. } else if title.starts(with: "call_") {
  2750. var phone = Utils.getCallCenter()
  2751. if phone.substring(from: 0, to: 0) == "0" {
  2752. phone = "+62" + phone.substring(from: 1, to: phone.count)
  2753. }
  2754. if let url = URL(string: "tel://\(phone)") {
  2755. UIApplication.shared.open(url)
  2756. }
  2757. } else {
  2758. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  2759. _ = Database.shared.updateRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
  2760. "ex_book" : self.message[CoreMessage_TMessageKey.MESSAGE_TEXT] ?? ""
  2761. ], _where: "message_id = '\(self.message[CoreMessage_TMessageKey.MESSAGE_ID] ?? "")'")
  2762. })
  2763. let messageText = self.message[CoreMessage_TMessageKey.MESSAGE_TEXT] as? String ?? ""
  2764. var messageTextSend = ""
  2765. if var json = try! JSONSerialization.jsonObject(with: messageText.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [String: Any] {
  2766. Database.shared.database?.inTransaction({ fmdb, rollback in
  2767. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select * from FORM_ITEM where form_id = '\(self.formItem.formId)'"), cursor.next() {
  2768. for columnIndex in 0..<cursor.columnCount {
  2769. if let columnName = cursor.columnName(for: columnIndex) {
  2770. if let value = cursor.object(forColumn: columnName) {
  2771. if columnName == "key" {
  2772. json[value as? String ?? ""] = title
  2773. break
  2774. }
  2775. }
  2776. }
  2777. }
  2778. cursor.close()
  2779. }
  2780. if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: .prettyPrinted),
  2781. let jsonString = String(data: jsonData, encoding: .utf8) {
  2782. messageTextSend = jsonString
  2783. }
  2784. })
  2785. }
  2786. let message = CoreMessage_TMessageBank.sendMessage(l_pin: self.form.formId, message_scope_id: MessageScope.FORM, status: "1", message_text: messageTextSend, credential: "0", attachment_flag: "", ex_blog_id: "", message_large_text: "", ex_format: "", image_id: "", audio_id: "", video_id: "", file_id: self.form.formId, thumb_id: "", reff_id: "", read_receipts: "4", chat_id: "", is_call_center: "0", call_center_id: "", opposite_pin: "", specFile: "")
  2787. OutgoingThread.default.addQueue(message: message)
  2788. self.dismiss(animated: true)
  2789. }
  2790. }
  2791. if formItem.background.isEmpty {
  2792. button.setTitle(finalTitleButton, for: .normal)
  2793. button.backgroundColor = .systemBlue
  2794. } else {
  2795. let backgrounds = formItem.background.components(separatedBy: ",")
  2796. if index < backgrounds.count {
  2797. button.setTitle("", for: .normal)
  2798. if let img = buttonBackgroundImages[index] {
  2799. button.setBackgroundImage(img.resizableImage(withCapInsets: .zero, resizingMode: .stretch), for: .normal)
  2800. }
  2801. }
  2802. }
  2803. containerButton.addSubview(button)
  2804. finalRow = row + 1
  2805. }
  2806. containerButton.heightAnchor.constraint(equalToConstant: CGFloat(35 * finalRow)).isActive = true
  2807. let footer = UILabel()
  2808. footer.text = form.footer
  2809. footer.font = .systemFont(ofSize: 12)
  2810. footer.textColor = .gray
  2811. footer.numberOfLines = 0
  2812. container.addSubview(footer)
  2813. footer.anchor(top: containerButton.bottomAnchor, bottom: container.bottomAnchor, right: container.rightAnchor, paddingTop: 10, paddingBottom: 5, paddingRight: 10)
  2814. }
  2815. private func loadDataAndBuildUI() {
  2816. let semaphore = DispatchSemaphore(value: 0)
  2817. if !form.iconTitle.isEmpty {
  2818. getImage(name: form.iconTitle) { result, _, image in
  2819. if result, let img = image {
  2820. self.iconTitleImage = img
  2821. semaphore.signal()
  2822. }
  2823. }
  2824. semaphore.wait()
  2825. }
  2826. if !form.iconSuffix.isEmpty {
  2827. getImage(name: form.iconSuffix) { result, _, image in
  2828. if result, let img = image {
  2829. self.iconSuffixImage = img
  2830. semaphore.signal()
  2831. }
  2832. }
  2833. semaphore.wait()
  2834. }
  2835. if !formItem.background.isEmpty {
  2836. let backgrounds = formItem.background.components(separatedBy: ",")
  2837. for (index, backgroundName) in backgrounds.enumerated() {
  2838. getImage(name: backgroundName, isResized: false) { result, _, image in
  2839. if result, let img = image {
  2840. self.buttonBackgroundImages[index] = img
  2841. semaphore.signal()
  2842. }
  2843. }
  2844. semaphore.wait()
  2845. }
  2846. }
  2847. DispatchQueue.main.async {
  2848. self.setupUI()
  2849. }
  2850. }
  2851. }
  2852. class LocationManager: NSObject, CLLocationManagerDelegate {
  2853. private var locationManager = CLLocationManager()
  2854. override init() {
  2855. super.init()
  2856. self.locationManager.delegate = self
  2857. self.locationManager.requestWhenInUseAuthorization()
  2858. self.locationManager.startUpdatingLocation()
  2859. if let location = locationManager.location {
  2860. let latitude = location.coordinate.latitude
  2861. let longitude = location.coordinate.longitude
  2862. Utils.latitude = "\(latitude)"
  2863. Utils.longitude = "\(longitude)"
  2864. }
  2865. }
  2866. func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
  2867. //print("didUpdateLocations")
  2868. if let location = locations.last {
  2869. let latitude = location.coordinate.latitude
  2870. let longitude = location.coordinate.longitude
  2871. Utils.latitude = "\(latitude)"
  2872. Utils.longitude = "\(longitude)"
  2873. }
  2874. }
  2875. func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
  2876. //print("Failed to find user's location: \(error.localizedDescription)")
  2877. }
  2878. }
  2879. public class SecureUserDefaults {
  2880. public static let shared = SecureUserDefaults()
  2881. private let defaults: UserDefaults
  2882. init(defaults: UserDefaults = .standard) {
  2883. self.defaults = defaults
  2884. }
  2885. // Save a value
  2886. public func set<T: Codable>(_ value: T, forKey key: String) {
  2887. let encoder = JSONEncoder()
  2888. guard let encodedData = try? encoder.encode(value),
  2889. let encryptedData = try? MasterKeyUtil.shared.encryptP(data: encodedData) else {
  2890. return
  2891. }
  2892. defaults.set(encryptedData, forKey: key)
  2893. }
  2894. // Retrieve a value
  2895. public func value<T: Codable>(forKey key: String) -> T? {
  2896. guard let encryptedData = defaults.data(forKey: key),
  2897. let decryptedData = try? MasterKeyUtil.shared.decryptP(data: encryptedData) else {
  2898. // print("Failed to decrypt data \(key)")
  2899. return nil
  2900. }
  2901. let decoder = JSONDecoder()
  2902. return try? decoder.decode(T.self, from: decryptedData)
  2903. }
  2904. // Remove a value
  2905. public func removeValue(forKey key: String) {
  2906. defaults.removeObject(forKey: key)
  2907. }
  2908. }
  2909. public class MessageScope {
  2910. public static let GLOBAL = "1";
  2911. public static let LOCAL = "2";
  2912. public static let WHISPER = "3";
  2913. public static let GROUP = "4";
  2914. public static let CHATROOM = "5";
  2915. public static let PLACE = "6";
  2916. public static let BUDDY = "7";
  2917. public static let FOLLOWER = "8";
  2918. public static let APP = "9";
  2919. public static let BLOG = "10";
  2920. public static let BOT = "11";
  2921. public static let CALL = "12";
  2922. public static let QUOTE = "13";
  2923. public static let DRAW = "14";
  2924. public static let SMS = "15";
  2925. public static let EMAIL = "16";
  2926. public static let LIVE_BRAODCAST = "17";
  2927. public static let FORM = "18";
  2928. public static let MISSED_CALL = "19";
  2929. public static let VIDEO_ATTACHMNET = "20";
  2930. public static let UNREAD_COUNT = "21";
  2931. public static let FAVORITE = "22";
  2932. public static let CALENDAR = "23";
  2933. public static let PILPRES = "25";
  2934. public static let CHATBOT = "26";
  2935. public static let BROADCAST_HISTORY = "30";
  2936. public static let GPT_CHATBOT = "31";
  2937. public static let COMMUNITY = "32";
  2938. public static let CHANNEL = "33";
  2939. }
  2940. class MediaViewerViewController: UIViewController, UIGestureRecognizerDelegate, UIScrollViewDelegate {
  2941. enum MediaType {
  2942. case image(UIImage)
  2943. case gif(UIImage)
  2944. case video(URL)
  2945. }
  2946. var media: MediaType!
  2947. public let backgroundView = UIView()
  2948. private let scrollView = UIScrollView()
  2949. private let imageView = UIImageView()
  2950. private var statusBarBackgroundView: UIView!
  2951. private var player: AVPlayer?
  2952. private var playerLayer: AVPlayerLayer?
  2953. private let playPauseButton = UIButton(type: .custom)
  2954. private var isVideoPlaying = false
  2955. var isNavigationBarHidden = false {
  2956. didSet { setNeedsStatusBarAppearanceUpdate() }
  2957. }
  2958. override var prefersStatusBarHidden: Bool {
  2959. return isNavigationBarHidden
  2960. }
  2961. override func viewDidLoad() {
  2962. super.viewDidLoad()
  2963. view.backgroundColor = .clear
  2964. edgesForExtendedLayout = .all
  2965. extendedLayoutIncludesOpaqueBars = true
  2966. navigationController?.navigationBar.isTranslucent = true
  2967. // Background view
  2968. backgroundView.backgroundColor = .white
  2969. backgroundView.alpha = 0
  2970. backgroundView.frame = view.bounds
  2971. view.addSubview(backgroundView)
  2972. // ScrollView for zooming
  2973. scrollView.frame = view.bounds
  2974. scrollView.delegate = self
  2975. scrollView.minimumZoomScale = 1.0
  2976. scrollView.maximumZoomScale = 3.0
  2977. scrollView.showsVerticalScrollIndicator = false
  2978. scrollView.showsHorizontalScrollIndicator = false
  2979. scrollView.bouncesZoom = true
  2980. view.addSubview(scrollView)
  2981. // Add imageView to scrollView
  2982. imageView.frame = scrollView.bounds
  2983. imageView.contentMode = .scaleAspectFit
  2984. scrollView.addSubview(imageView)
  2985. configureMedia()
  2986. // Tap gesture to toggle navigation bar
  2987. let tap = UITapGestureRecognizer(target: self, action: #selector(toggleNavigationBar))
  2988. tap.numberOfTapsRequired = 1
  2989. view.addGestureRecognizer(tap)
  2990. // Pan gesture for swipe-to-dismiss
  2991. let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
  2992. panGesture.delegate = self
  2993. view.addGestureRecognizer(panGesture)
  2994. // Status bar background view
  2995. let window = UIApplication.shared.windows.first
  2996. let statusBarHeight = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 44
  2997. statusBarBackgroundView = UIView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: statusBarHeight))
  2998. statusBarBackgroundView.backgroundColor = .mainColor
  2999. statusBarBackgroundView.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin]
  3000. view.addSubview(statusBarBackgroundView)
  3001. }
  3002. override func viewWillAppear(_ animated: Bool) {
  3003. super.viewWillAppear(animated)
  3004. navigationController?.setNavigationBarHidden(false, animated: false)
  3005. isNavigationBarHidden = false
  3006. }
  3007. func animateBackgroundIn() {
  3008. UIView.animate(withDuration: 0.25) {
  3009. self.backgroundView.alpha = 1
  3010. }
  3011. }
  3012. private func configureMedia() {
  3013. switch media! {
  3014. case .image(let img):
  3015. imageView.image = img
  3016. case .gif(let img):
  3017. imageView.image = img
  3018. imageView.animationRepeatCount = 0
  3019. imageView.startAnimating()
  3020. case .video(let url):
  3021. setupVideo(url: url)
  3022. }
  3023. }
  3024. private func setupVideo(url: URL) {
  3025. player = AVPlayer(url: url)
  3026. playerLayer = AVPlayerLayer(player: player)
  3027. playerLayer?.frame = scrollView.bounds
  3028. playerLayer?.videoGravity = .resizeAspect
  3029. scrollView.layer.addSublayer(playerLayer!)
  3030. // Observe when video finished playing
  3031. NotificationCenter.default.addObserver(self, selector: #selector(videoDidFinish), name: .AVPlayerItemDidPlayToEndTime, object: player?.currentItem)
  3032. // Add play/pause button
  3033. playPauseButton.setImage(UIImage(systemName: "play.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .bold, scale: .default)), for: .normal)
  3034. playPauseButton.tintColor = .white
  3035. playPauseButton.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
  3036. playPauseButton.backgroundColor = .black.withAlphaComponent(0.3)
  3037. playPauseButton.center = view.center
  3038. playPauseButton.addTarget(self, action: #selector(togglePlayPause), for: .touchUpInside)
  3039. view.addSubview(playPauseButton)
  3040. playPauseButton.circle()
  3041. togglePlayPause()
  3042. }
  3043. @objc private func videoDidFinish() {
  3044. isVideoPlaying = false
  3045. playPauseButton.setImage(UIImage(systemName: "play.fill"), for: .normal)
  3046. }
  3047. @objc private func togglePlayPause() {
  3048. guard let player = player else { return }
  3049. if isVideoPlaying {
  3050. player.pause()
  3051. playPauseButton.setImage(UIImage(systemName: "play.fill"), for: .normal)
  3052. } else {
  3053. if let currentItem = player.currentItem,
  3054. currentItem.currentTime() >= currentItem.duration {
  3055. player.seek(to: .zero)
  3056. }
  3057. player.play()
  3058. playPauseButton.setImage(UIImage(systemName: "pause.fill"), for: .normal)
  3059. DispatchQueue.global().async {
  3060. while self.statusBarBackgroundView == nil {
  3061. Thread.sleep(forTimeInterval: 0.25)
  3062. }
  3063. DispatchQueue.main.async {
  3064. self.toggleNavigationBar()
  3065. }
  3066. }
  3067. }
  3068. isVideoPlaying.toggle()
  3069. }
  3070. @objc private func toggleNavigationBar() {
  3071. guard let navController = navigationController else { return }
  3072. isNavigationBarHidden.toggle()
  3073. UIView.animate(withDuration: 0.25) {
  3074. navController.setNavigationBarHidden(self.isNavigationBarHidden, animated: true)
  3075. self.statusBarBackgroundView.alpha = self.isNavigationBarHidden ? 0 : 1
  3076. self.playPauseButton.alpha = self.isNavigationBarHidden ? 0 : 1
  3077. }
  3078. }
  3079. @objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
  3080. guard scrollView.zoomScale == 1.0 else { return }
  3081. let translation = gesture.translation(in: view)
  3082. let velocity = gesture.velocity(in: view)
  3083. switch gesture.state {
  3084. case .changed:
  3085. let transform = CGAffineTransform(translationX: translation.x, y: translation.y)
  3086. scrollView.transform = transform
  3087. // Calculate percentage based on distance from center
  3088. let distance = hypot(translation.x, translation.y)
  3089. let maxDistance = view.bounds.height / 2.0
  3090. let progress = min(distance / maxDistance, 1.0)
  3091. self.backgroundView.alpha = 1.0 - progress
  3092. case .ended, .cancelled:
  3093. let distance = hypot(translation.x, translation.y)
  3094. let threshold: CGFloat = 120
  3095. if distance > threshold || abs(velocity.y) > 500 || abs(velocity.x) > 500 {
  3096. // Dismiss if far enough or fast swipe
  3097. dismiss(animated: true, completion: nil)
  3098. } else {
  3099. // Return to center if not far enough
  3100. UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.9, initialSpringVelocity: 0.8, options: [], animations: {
  3101. self.scrollView.transform = .identity
  3102. self.backgroundView.alpha = 1.0
  3103. }, completion: nil)
  3104. }
  3105. default:
  3106. break
  3107. }
  3108. }
  3109. // MARK: - UIScrollViewDelegate
  3110. func viewForZooming(in scrollView: UIScrollView) -> UIView? {
  3111. return imageView
  3112. }
  3113. func scrollViewDidZoom(_ scrollView: UIScrollView) {
  3114. let imageViewSize = imageView.frame.size
  3115. let scrollViewSize = scrollView.bounds.size
  3116. let verticalPadding = imageViewSize.height < scrollViewSize.height ? (scrollViewSize.height - imageViewSize.height) / 2 : 0
  3117. let horizontalPadding = imageViewSize.width < scrollViewSize.width ? (scrollViewSize.width - imageViewSize.width) / 2 : 0
  3118. scrollView.contentInset = UIEdgeInsets(top: verticalPadding, left: horizontalPadding, bottom: verticalPadding, right: horizontalPadding)
  3119. }
  3120. }
  3121. class ZoomAnimator: NSObject, UIViewControllerAnimatedTransitioning {
  3122. var isPresenting = true
  3123. var originImageView: UIImageView?
  3124. func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
  3125. return 0.45
  3126. }
  3127. func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
  3128. guard let fromVC = transitionContext.viewController(forKey: .from),
  3129. let toVC = transitionContext.viewController(forKey: .to),
  3130. let originImageView = originImageView else {
  3131. transitionContext.completeTransition(false)
  3132. return
  3133. }
  3134. let container = transitionContext.containerView
  3135. let imageViewSnapshot = UIImageView(image: originImageView.image)
  3136. imageViewSnapshot.contentMode = .scaleAspectFit
  3137. imageViewSnapshot.clipsToBounds = true
  3138. imageViewSnapshot.frame = container.convert(originImageView.bounds, from: originImageView)
  3139. if isPresenting {
  3140. toVC.view.alpha = 0
  3141. container.addSubview(toVC.view)
  3142. container.addSubview(imageViewSnapshot)
  3143. let finalFrame = toVC.view.frame
  3144. UIView.animate(withDuration: transitionDuration(using: transitionContext),
  3145. delay: 0,
  3146. usingSpringWithDamping: 0.85,
  3147. initialSpringVelocity: 0.6,
  3148. options: .curveEaseOut, animations: {
  3149. imageViewSnapshot.frame = finalFrame
  3150. toVC.view.alpha = 1
  3151. }) { _ in
  3152. imageViewSnapshot.removeFromSuperview()
  3153. transitionContext.completeTransition(true)
  3154. }
  3155. } else {
  3156. let navVC = fromVC as! UINavigationController
  3157. let fromImageVC = navVC.viewControllers.first as! MediaViewerViewController
  3158. let finalFrame = container.convert(originImageView.bounds, from: originImageView)
  3159. container.addSubview(imageViewSnapshot)
  3160. fromImageVC.view.alpha = 0
  3161. fromImageVC.backgroundView.alpha = 0 // fade background
  3162. UIView.animate(withDuration: transitionDuration(using: transitionContext),
  3163. delay: 0,
  3164. usingSpringWithDamping: 0.85,
  3165. initialSpringVelocity: 0.6,
  3166. options: .curveEaseOut, animations: {
  3167. imageViewSnapshot.frame = finalFrame
  3168. }) { _ in
  3169. imageViewSnapshot.removeFromSuperview()
  3170. transitionContext.completeTransition(true)
  3171. }
  3172. }
  3173. }
  3174. }
  3175. class ZoomTransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
  3176. var originImageView: UIImageView?
  3177. func animationController(forPresented presented: UIViewController,
  3178. presenting: UIViewController, source: UIViewController)
  3179. -> UIViewControllerAnimatedTransitioning? {
  3180. let animator = ZoomAnimator()
  3181. animator.isPresenting = true
  3182. animator.originImageView = originImageView
  3183. return animator
  3184. }
  3185. func animationController(forDismissed dismissed: UIViewController)
  3186. -> UIViewControllerAnimatedTransitioning? {
  3187. let animator = ZoomAnimator()
  3188. animator.isPresenting = false
  3189. animator.originImageView = originImageView
  3190. return animator
  3191. }
  3192. }
  3193. public class CallBannerView: UIView {
  3194. public override init(frame: CGRect) {
  3195. super.init(frame: frame)
  3196. backgroundColor = UIColor.systemGreen
  3197. let label = UILabel()
  3198. label.text = "Ardi easySoft - Ringing"
  3199. label.textColor = .white
  3200. label.font = UIFont.boldSystemFont(ofSize: 16)
  3201. let endCallButton = UIButton(type: .system)
  3202. endCallButton.setImage(UIImage(systemName: "phone.down.fill"), for: .normal)
  3203. endCallButton.tintColor = .white
  3204. endCallButton.addTarget(self, action: #selector(endCallTapped), for: .touchUpInside)
  3205. let stack = UIStackView(arrangedSubviews: [label, endCallButton])
  3206. stack.axis = .horizontal
  3207. stack.alignment = .center
  3208. stack.distribution = .equalSpacing
  3209. stack.spacing = 12
  3210. addSubview(stack)
  3211. stack.translatesAutoresizingMaskIntoConstraints = false
  3212. NSLayoutConstraint.activate([
  3213. stack.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
  3214. stack.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
  3215. stack.topAnchor.constraint(equalTo: topAnchor, constant: 10),
  3216. stack.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10)
  3217. ])
  3218. }
  3219. @objc func endCallTapped() {
  3220. print("Call ended")
  3221. self.removeFromSuperview()
  3222. }
  3223. public required init?(coder: NSCoder) {
  3224. fatalError("init(coder:) has not been implemented")
  3225. }
  3226. }
  3227. class HtmlUtils {
  3228. private static func unescapeHTMLEntities(_ text: String) -> String {
  3229. var result = text
  3230. // quick named entity replacements
  3231. let named: [String: String] = [
  3232. "&lt;": "<",
  3233. "&gt;": ">",
  3234. "&amp;": "&",
  3235. "&quot;": "\"",
  3236. "&apos;": "'",
  3237. "&#039;": "'" // common single-quote entity in some HTML sources
  3238. ]
  3239. for (k, v) in named {
  3240. result = result.replacingOccurrences(of: k, with: v)
  3241. }
  3242. // decode decimal numeric entities like &#39;
  3243. let decimalPattern = "&#(\\d+);"
  3244. if let decRegex = try? NSRegularExpression(pattern: decimalPattern, options: []) {
  3245. let matches = decRegex.matches(in: result, options: [], range: NSRange(location: 0, length: result.utf16.count))
  3246. for match in matches.reversed() { // reverse so ranges remain valid while replacing
  3247. guard match.numberOfRanges >= 2,
  3248. let numRange = Range(match.range(at: 1), in: result) else { continue }
  3249. let numStr = String(result[numRange])
  3250. if let code = Int(numStr), let scalar = UnicodeScalar(code) {
  3251. let char = String(scalar)
  3252. if let fullRange = Range(match.range(at: 0), in: result) {
  3253. result.replaceSubrange(fullRange, with: char)
  3254. }
  3255. }
  3256. }
  3257. }
  3258. // decode hex numeric entities like &#x27;
  3259. let hexPattern = "&#x([0-9a-fA-F]+);"
  3260. if let hexRegex = try? NSRegularExpression(pattern: hexPattern, options: []) {
  3261. let matches = hexRegex.matches(in: result, options: [], range: NSRange(location: 0, length: result.utf16.count))
  3262. for match in matches.reversed() {
  3263. guard match.numberOfRanges >= 2,
  3264. let hexRange = Range(match.range(at: 1), in: result) else { continue }
  3265. let hexStr = String(result[hexRange])
  3266. if let code = Int(hexStr, radix: 16), let scalar = UnicodeScalar(code) {
  3267. let char = String(scalar)
  3268. if let fullRange = Range(match.range(at: 0), in: result) {
  3269. result.replaceSubrange(fullRange, with: char)
  3270. }
  3271. }
  3272. }
  3273. }
  3274. return result
  3275. }
  3276. static func toHTMLPreview(_ pText: String, fontSize: CGFloat = 12) -> NSAttributedString {
  3277. let unescaped = unescapeHTMLEntities(pText).replacingOccurrences(of: "\n", with: "<br>")
  3278. let parsed: NSAttributedString = {
  3279. guard let data = unescaped.data(using: .utf8) else { return NSAttributedString(string: unescaped) }
  3280. do {
  3281. return try NSAttributedString(
  3282. data: data,
  3283. options: [
  3284. .documentType: NSAttributedString.DocumentType.html,
  3285. .characterEncoding: String.Encoding.utf8.rawValue
  3286. ],
  3287. documentAttributes: nil
  3288. )
  3289. } catch {
  3290. return NSAttributedString(string: unescaped)
  3291. }
  3292. }()
  3293. // 3) Apply your custom fonts while preserving link attributes
  3294. let mutable = NSMutableAttributedString(attributedString: parsed)
  3295. let normalFont = UIFont.systemFont(ofSize: fontSize)
  3296. let boldFont = UIFont.boldSystemFont(ofSize: fontSize)
  3297. let italicFont = UIFont.italicSystemFont(ofSize: fontSize)
  3298. let boldItalicFont = UIFont.systemFont(ofSize: fontSize, weight: .semibold)
  3299. mutable.enumerateAttribute(.font, in: NSRange(location: 0, length: mutable.length)) { value, range, _ in
  3300. guard let oldFont = value as? UIFont else { return }
  3301. let traits = oldFont.fontDescriptor.symbolicTraits
  3302. let newFont: UIFont
  3303. if traits.contains([.traitBold, .traitItalic]) {
  3304. newFont = boldItalicFont
  3305. } else if traits.contains(.traitBold) {
  3306. newFont = boldFont
  3307. } else if traits.contains(.traitItalic) {
  3308. newFont = italicFont
  3309. } else {
  3310. newFont = normalFont
  3311. }
  3312. // replace font but DO NOT remove link attribute or other attrs
  3313. mutable.addAttribute(.font, value: newFont, range: range)
  3314. }
  3315. return mutable
  3316. }
  3317. static func hasHtmlTag(_ pText: String) -> Bool {
  3318. // unescape entities first
  3319. let unescaped = unescapeHTMLEntities(pText)
  3320. let pattern = ".*\\<[^>]+>.*"
  3321. if let regex = try? NSRegularExpression(pattern: pattern,
  3322. options: [.dotMatchesLineSeparators]) {
  3323. let range = NSRange(location: 0, length: (unescaped as NSString).length)
  3324. return regex.firstMatch(in: unescaped, options: [], range: range) != nil
  3325. }
  3326. return false
  3327. }
  3328. }
  3329. enum FormFieldType: String {
  3330. case dateChooser
  3331. case dateTimeChooser
  3332. case timeChooser
  3333. case itemChooser
  3334. case inputRadio
  3335. case inputRadioHorizontal
  3336. case inputNumber
  3337. case inputText
  3338. case inputTextMultiline
  3339. case inputCheck
  3340. case inputFile
  3341. case inputPhoto
  3342. case inputProject
  3343. case header
  3344. case transId
  3345. case transStatus
  3346. case transAssigned
  3347. case signature
  3348. case image
  3349. case video
  3350. }
  3351. // Factory untuk membuat view sesuai tipe
  3352. class FormViewFactory {
  3353. static func createView(
  3354. type: FormFieldType,
  3355. key: String,
  3356. keyLabel: String,
  3357. valueLabel: String,
  3358. background: UIColor? = nil,
  3359. color: UIColor? = nil
  3360. ) -> UIView {
  3361. var result: UIView
  3362. switch type {
  3363. case .dateChooser:
  3364. result = createDateChooser(keyLabel: keyLabel, valueLabel: valueLabel)
  3365. case .dateTimeChooser:
  3366. result = createDateTimeChooser()
  3367. case .timeChooser:
  3368. result = createTimeChooser()
  3369. case .itemChooser:
  3370. result = createItemChooser(keyLabel: keyLabel, valueLabel: valueLabel)
  3371. case .inputRadio:
  3372. result = createRadio(keyLabel: keyLabel, valueLabel: valueLabel, color: color)
  3373. case .inputRadioHorizontal:
  3374. result = createRadioHorizontal(keyLabel: keyLabel, valueLabel: valueLabel, color: color)
  3375. case .inputNumber:
  3376. result = createNumberField(keyLabel: keyLabel, valueLabel: valueLabel)
  3377. case .inputText:
  3378. result = createTextField(keyLabel: keyLabel, valueLabel: valueLabel)
  3379. case .inputTextMultiline:
  3380. result = createMultilineTextField(keyLabel: keyLabel, valueLabel: valueLabel)
  3381. case .inputCheck:
  3382. result = createCheckbox(keyLabel: keyLabel, valueLabel: valueLabel)
  3383. case .inputFile:
  3384. result = createButton(title: "Upload File")
  3385. case .inputPhoto:
  3386. result = createButton(title: "Take Photo")
  3387. case .inputProject:
  3388. result = createLabel("\(keyLabel): [Project Picker]")
  3389. case .header:
  3390. result = createHeader(title: keyLabel)
  3391. case .transId:
  3392. result = createLabel("Transaction ID: \(valueLabel)")
  3393. case .transStatus:
  3394. result = createLabel("Status: \(keyLabel)")
  3395. case .transAssigned:
  3396. result = createLabel("Assigned to: \(valueLabel)")
  3397. case .signature:
  3398. result = createButton(title: "Add Signature")
  3399. case .image:
  3400. result = createButton(title: "Pick Image")
  3401. case .video:
  3402. result = createButton(title: "Pick Video")
  3403. }
  3404. // optional background
  3405. if let bg = background {
  3406. result.backgroundColor = bg
  3407. }
  3408. return result
  3409. }
  3410. // MARK: - Builder sederhana
  3411. private static func createLabel(_ text: String) -> UIView {
  3412. let label = UILabel()
  3413. label.text = text
  3414. return label
  3415. }
  3416. private static func createHeader(title: String) -> UIView {
  3417. let label = UILabel()
  3418. label.text = title
  3419. label.font = UIFont.boldSystemFont(ofSize: 18)
  3420. return label
  3421. }
  3422. private static func createButton(title: String) -> UIView {
  3423. let button = UIButton(type: .system)
  3424. button.setTitle(title, for: .normal)
  3425. return button
  3426. }
  3427. private static func createTextField(keyLabel: String, valueLabel: String) -> UIView {
  3428. let textField = UITextField()
  3429. textField.placeholder = keyLabel
  3430. textField.text = valueLabel
  3431. textField.borderStyle = .roundedRect
  3432. return textField
  3433. }
  3434. private static func createMultilineTextField(keyLabel: String, valueLabel: String) -> UIView {
  3435. let textView = UITextView()
  3436. textView.text = valueLabel.isEmpty ? keyLabel : valueLabel
  3437. textView.layer.borderWidth = 1
  3438. textView.layer.borderColor = UIColor.gray.cgColor
  3439. textView.layer.cornerRadius = 6
  3440. return textView
  3441. }
  3442. private static func createNumberField(keyLabel: String, valueLabel: String) -> UIView {
  3443. let textField = createTextField(keyLabel: keyLabel, valueLabel: valueLabel) as! UITextField
  3444. textField.keyboardType = .numberPad
  3445. return textField
  3446. }
  3447. private static func createDateChooser(keyLabel: String, valueLabel: String) -> UIView {
  3448. let picker = UIDatePicker()
  3449. picker.datePickerMode = .date
  3450. return picker
  3451. }
  3452. private static func createDateTimeChooser() -> UIView {
  3453. let picker = UIDatePicker()
  3454. picker.datePickerMode = .dateAndTime
  3455. return picker
  3456. }
  3457. private static func createTimeChooser() -> UIView {
  3458. let picker = UIDatePicker()
  3459. picker.datePickerMode = .time
  3460. return picker
  3461. }
  3462. private static func createItemChooser(keyLabel: String, valueLabel: String) -> UIView {
  3463. return createButton(title: "\(keyLabel): \(valueLabel)")
  3464. }
  3465. private static func createRadio(keyLabel: String, valueLabel: String, color: UIColor?) -> UIView {
  3466. let button = UIButton(type: .system)
  3467. button.setTitle("○ \(valueLabel)", for: .normal)
  3468. button.tintColor = color ?? .blue
  3469. return button
  3470. }
  3471. private static func createRadioHorizontal(keyLabel: String, valueLabel: String, color: UIColor?) -> UIView {
  3472. let stack = UIStackView()
  3473. stack.axis = .horizontal
  3474. stack.spacing = 8
  3475. let label = UILabel()
  3476. label.text = keyLabel
  3477. let button = UIButton(type: .system)
  3478. button.setTitle(valueLabel, for: .normal)
  3479. button.tintColor = color ?? .blue
  3480. stack.addArrangedSubview(label)
  3481. stack.addArrangedSubview(button)
  3482. return stack
  3483. }
  3484. private static func createCheckbox(keyLabel: String, valueLabel: String) -> UIView {
  3485. let button = UIButton(type: .system)
  3486. button.setTitle("☐ \(keyLabel)", for: .normal)
  3487. return button
  3488. }
  3489. }
  3490. public final class MessageGuardLite {
  3491. // MARK: - Verdict
  3492. public enum Verdict {
  3493. case allow, sanitized, block
  3494. }
  3495. // MARK: - Result
  3496. public struct Result {
  3497. public let verdict: Verdict
  3498. public let reason: String
  3499. public let mime: String
  3500. public let data: Data? // nil for some paths (like PDF->images)
  3501. }
  3502. // MARK: - Limits
  3503. public struct Limits {
  3504. public let maxImagePixels: Int
  3505. public let maxImageEdge: Int
  3506. public let pdfMaxPages: Int
  3507. public init(maxImagePixels: Int, maxImageEdge: Int, pdfMaxPages: Int) {
  3508. self.maxImagePixels = maxImagePixels
  3509. self.maxImageEdge = maxImageEdge
  3510. self.pdfMaxPages = pdfMaxPages
  3511. }
  3512. public static func defaults() -> Limits {
  3513. return Limits(maxImagePixels: 4096 * 4096, maxImageEdge: 4096, pdfMaxPages: 10)
  3514. }
  3515. }
  3516. private let limits: Limits
  3517. public init(limits: Limits? = nil) {
  3518. self.limits = limits ?? Limits.defaults()
  3519. }
  3520. // MARK: - 1. Text Sanitization
  3521. public func sanitizeText(_ utf8: Data) -> Result {
  3522. guard let input = String(data: utf8, encoding: .utf8) else {
  3523. return Result(verdict: .block,
  3524. reason: "Invalid UTF-8 text",
  3525. mime: "application/octet-stream",
  3526. data: nil)
  3527. }
  3528. let pattern = "[\\p{C}\\u200B-\\u200F\\uFEFF\\u202A-\\u202E]"
  3529. let regex = try! NSRegularExpression(pattern: pattern)
  3530. let clean = regex.stringByReplacingMatches(in: input,
  3531. options: [],
  3532. range: NSRange(location: 0, length: input.utf16.count),
  3533. withTemplate: "")
  3534. if input == clean {
  3535. return Result(verdict: .allow, reason: "No changes", mime: "text/plain", data: utf8)
  3536. } else {
  3537. return Result(verdict: .sanitized, reason: "Removed control & zero-width characters", mime: "text/plain", data: clean.data(using: .utf8))
  3538. }
  3539. }
  3540. // MARK: - 2. HTML Sanitization
  3541. public func sanitizeHtml(_ utf8Html: Data) -> Result {
  3542. guard let input = String(data: utf8Html, encoding: .utf8) else {
  3543. return Result(verdict: .block, reason: "Invalid HTML encoding", mime: "application/octet-stream", data: nil)
  3544. }
  3545. var clean = input
  3546. clean = clean.replacingOccurrences(of: "(?is)<(script|style)[^>]*>.*?</\\1>", with: "", options: .regularExpression)
  3547. clean = clean.replacingOccurrences(of: "\\son\\w+=\"[^\"]*\"", with: "", options: .regularExpression)
  3548. clean = clean.replacingOccurrences(of: "(?i)javascript:[^\"']*", with: "", options: .regularExpression)
  3549. if input == clean {
  3550. return Result(verdict: .allow, reason: "No changes", mime: "text/html", data: utf8Html)
  3551. } else {
  3552. return Result(verdict: .sanitized, reason: "Sanitized HTML allowlist", mime: "text/html", data: clean.data(using: .utf8))
  3553. }
  3554. }
  3555. // MARK: - 3. Image Sanitization
  3556. public func sanitizeImage(_ bytes: Data) -> Result {
  3557. guard let image = UIImage(data: bytes) else {
  3558. return Result(verdict: .block, reason: "Unrecognized or corrupt image", mime: "image/jpeg", data: nil)
  3559. }
  3560. let pixels = Int(image.size.width * image.size.height)
  3561. var processed = image
  3562. if pixels > limits.maxImagePixels {
  3563. let scale = sqrt(Double(limits.maxImagePixels) / Double(pixels))
  3564. let newSize = CGSize(width: image.size.width * scale, height: image.size.height * scale)
  3565. processed = resize(image, to: newSize)
  3566. }
  3567. processed = capEdge(processed, maxEdge: limits.maxImageEdge)
  3568. guard let out = processed.jpegData(compressionQuality: 0.8) else {
  3569. return Result(verdict: .block, reason: "Failed to re-encode image", mime: "image/jpeg", data: nil)
  3570. }
  3571. return Result(verdict: .sanitized,
  3572. reason: "Re-encoded PNG (metadata/animation removed)",
  3573. mime: "image/png",
  3574. data: out)
  3575. }
  3576. private func resize(_ image: UIImage, to size: CGSize) -> UIImage {
  3577. UIGraphicsBeginImageContextWithOptions(size, true, 1.0)
  3578. image.draw(in: CGRect(origin: .zero, size: size))
  3579. let newImg = UIGraphicsGetImageFromCurrentImageContext()
  3580. UIGraphicsEndImageContext()
  3581. return newImg ?? image
  3582. }
  3583. private func capEdge(_ image: UIImage, maxEdge: Int) -> UIImage {
  3584. let w = image.size.width
  3585. let h = image.size.height
  3586. let maxDim = max(w, h)
  3587. if maxDim <= CGFloat(maxEdge) { return image }
  3588. let scale = CGFloat(maxEdge) / maxDim
  3589. let newSize = CGSize(width: w * scale, height: h * scale)
  3590. return resize(image, to: newSize)
  3591. }
  3592. // MARK: - 4. PDF Sanitization
  3593. public func sanitizePdf(_ pdfData: Data) -> Result {
  3594. guard let pdf = PDFDocument(data: pdfData) else {
  3595. return Result(
  3596. verdict: .block,
  3597. reason: "Unrecognized or corrupt PDF",
  3598. mime: "application/octet-stream",
  3599. data: nil
  3600. )
  3601. }
  3602. // ✅ Allowed as-is
  3603. return Result(
  3604. verdict: .allow,
  3605. reason: "PDF is valid and within limits",
  3606. mime: "application/pdf",
  3607. data: pdfData
  3608. )
  3609. }
  3610. // MARK: - 5. MIME Sniffing
  3611. public static func sniffMime(_ data: Data) -> String {
  3612. let bytes = [UInt8](data.prefix(8))
  3613. guard bytes.count >= 4 else { return "application/octet-stream" }
  3614. if bytes.starts(with: [0x89, 0x50, 0x4E, 0x47]) { return "image/png" }
  3615. if bytes.starts(with: [0xFF, 0xD8]) { return "image/jpeg" }
  3616. if bytes.starts(with: [0x47, 0x49, 0x46]) { return "image/gif" }
  3617. if bytes.starts(with: [0x25, 0x50, 0x44, 0x46]) { return "application/pdf" }
  3618. if bytes.starts(with: [0x50, 0x4B]) { return "application/zip" }
  3619. if let s = String(data: data.prefix(32), encoding: .utf8)?
  3620. .trimmingCharacters(in: .whitespacesAndNewlines).lowercased() {
  3621. if s.hasPrefix("<!doctype html") || s.hasPrefix("<html") || s.hasPrefix("<body") {
  3622. return "text/html"
  3623. }
  3624. }
  3625. return "application/octet-stream"
  3626. }
  3627. public static func containsHtmlTags(_ input: String) -> Bool {
  3628. let pattern = ".*<[^>]+>.*"
  3629. return input.range(of: pattern, options: .regularExpression) != nil
  3630. }
  3631. }