Browse Source

first commit

kevin 8 months ago
parent
commit
f3ba9097df
100 changed files with 8046 additions and 0 deletions
  1. BIN
      .DS_Store
  2. BIN
      AppBuilder/.DS_Store
  3. 673 0
      AppBuilder/AppBuilder.xcodeproj/project.pbxproj
  4. 7 0
      AppBuilder/AppBuilder.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  5. 8 0
      AppBuilder/AppBuilder.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
  6. 98 0
      AppBuilder/AppBuilder.xcodeproj/xcshareddata/xcschemes/AppBuilder.xcscheme
  7. 10 0
      AppBuilder/AppBuilder.xcworkspace/contents.xcworkspacedata
  8. 8 0
      AppBuilder/AppBuilder.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
  9. 155 0
      AppBuilder/AppBuilder/AppDelegate.swift
  10. 11 0
      AppBuilder/AppBuilder/Assets.xcassets/AccentColor.colorset/Contents.json
  11. BIN
      AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/1024.png
  12. BIN
      AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/114.png
  13. BIN
      AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/120.png
  14. BIN
      AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/180.png
  15. BIN
      AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/29.png
  16. BIN
      AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/40.png
  17. BIN
      AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/57.png
  18. BIN
      AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/58.png
  19. BIN
      AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/60.png
  20. BIN
      AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/80.png
  21. BIN
      AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/87.png
  22. 80 0
      AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/Contents.json
  23. 6 0
      AppBuilder/AppBuilder/Assets.xcassets/Contents.json
  24. 21 0
      AppBuilder/AppBuilder/Assets.xcassets/ic_broadcast.imageset/Contents.json
  25. BIN
      AppBuilder/AppBuilder/Assets.xcassets/ic_broadcast.imageset/ic_broadcast.png
  26. 21 0
      AppBuilder/AppBuilder/Assets.xcassets/pb_icon.imageset/Contents.json
  27. BIN
      AppBuilder/AppBuilder/Assets.xcassets/pb_icon.imageset/nexilis_icon.png
  28. 21 0
      AppBuilder/AppBuilder/Assets.xcassets/pb_powered_button.imageset/Contents.json
  29. BIN
      AppBuilder/AppBuilder/Assets.xcassets/pb_powered_button.imageset/pb_powered_button.png
  30. 21 0
      AppBuilder/AppBuilder/Assets.xcassets/tab_1_icon.imageset/Contents.json
  31. BIN
      AppBuilder/AppBuilder/Assets.xcassets/tab_1_icon.imageset/tab_1_nexilis.png
  32. 21 0
      AppBuilder/AppBuilder/Assets.xcassets/tab_2_icon.imageset/Contents.json
  33. BIN
      AppBuilder/AppBuilder/Assets.xcassets/tab_2_icon.imageset/tab_2_nexilis.png
  34. 21 0
      AppBuilder/AppBuilder/Assets.xcassets/tab_3_icon.imageset/Contents.json
  35. BIN
      AppBuilder/AppBuilder/Assets.xcassets/tab_3_icon.imageset/tab_3_nexilis.png
  36. 21 0
      AppBuilder/AppBuilder/Assets.xcassets/tab_4_icon.imageset/Contents.json
  37. BIN
      AppBuilder/AppBuilder/Assets.xcassets/tab_4_icon.imageset/tab_4_nexilis.png
  38. 48 0
      AppBuilder/AppBuilder/Base.lproj/LaunchScreen.storyboard
  39. 295 0
      AppBuilder/AppBuilder/Base.lproj/Main.storyboard
  40. 608 0
      AppBuilder/AppBuilder/FirstTabViewController.swift
  41. 1287 0
      AppBuilder/AppBuilder/FourthTabViewController.swift
  42. 213 0
      AppBuilder/AppBuilder/Info.plist
  43. 33 0
      AppBuilder/AppBuilder/LaunchScreenViewController.swift
  44. 230 0
      AppBuilder/AppBuilder/PrefsUtil.swift
  45. 120 0
      AppBuilder/AppBuilder/SceneDelegate.swift
  46. 1433 0
      AppBuilder/AppBuilder/SecondTabViewController.swift
  47. 617 0
      AppBuilder/AppBuilder/ThirdTabViewController.swift
  48. 1336 0
      AppBuilder/AppBuilder/ViewController.swift
  49. BIN
      AppBuilder/AppBuilder/bi_icon.png
  50. BIN
      AppBuilder/AppBuilder/bpkh_icon.png
  51. BIN
      AppBuilder/AppBuilder/diginets_icon.png
  52. BIN
      AppBuilder/AppBuilder/digisales_icon.png
  53. BIN
      AppBuilder/AppBuilder/disini_icon.png
  54. BIN
      AppBuilder/AppBuilder/gudeg_icon.png
  55. BIN
      AppBuilder/AppBuilder/ikn_icon.png
  56. BIN
      AppBuilder/AppBuilder/kmi_icon.png
  57. BIN
      AppBuilder/AppBuilder/nu_icon.png
  58. BIN
      AppBuilder/AppBuilder/nxcook_icon.png
  59. BIN
      AppBuilder/AppBuilder/nxsport_icon.png
  60. 21 0
      AppBuilder/NotificationService/Info.plist
  61. 81 0
      AppBuilder/NotificationService/NotificationService.swift
  62. 35 0
      AppBuilder/Podfile
  63. BIN
      NexilisLite/.DS_Store
  64. 8 0
      NexilisLite/LICENSE
  65. 42 0
      NexilisLite/NexilisLite.podspec
  66. BIN
      NexilisLite/NexilisLite/.DS_Store
  67. 84 0
      NexilisLite/NexilisLite/Info.plist
  68. 13 0
      NexilisLite/NexilisLite/NexilisLite.docc/NexilisLite.md
  69. 18 0
      NexilisLite/NexilisLite/NexilisLite.h
  70. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Attachment.imageset/Attachment.png
  71. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Attachment.imageset/Contents.json
  72. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Camera.imageset/Camera.png
  73. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Camera.imageset/Contents.json
  74. 6 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Contents.json
  75. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Conversation---Black.imageset/Contents.json
  76. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Conversation---Black.imageset/Conversation---Black.png
  77. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Conversation---Purple.imageset/Contents.json
  78. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Conversation---Purple.imageset/Conversation---Purple.png
  79. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/File---Documents.imageset/Contents.json
  80. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/File---Documents.imageset/File---Documents.png
  81. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Profile---Black.imageset/Contents.json
  82. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Profile---Black.imageset/Profile---Black.png
  83. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Profile---Purple.imageset/Contents.json
  84. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Profile---Purple.imageset/Profile---Purple.png
  85. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Q-Button-PNG.imageset/Contents.json
  86. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Q-Button-PNG.imageset/Q-Button-PNG.png
  87. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Send-(White).imageset/Contents.json
  88. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Send-(White).imageset/Send-(White).png
  89. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Send---Purple.imageset/Contents.json
  90. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Send---Purple.imageset/Send---Purple.png
  91. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Send-Image.imageset/Contents.json
  92. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Send-Image.imageset/Send-Image.png
  93. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Sofa.imageset/1-Furniture-Single-Sofa-196.jpg
  94. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Sofa.imageset/Contents.json
  95. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Sticker---Emoji.imageset/Contents.json
  96. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Sticker---Emoji.imageset/Sticker---Emoji.png
  97. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Voice-Command.imageset/Contents.json
  98. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Voice-Command.imageset/Voice-Command.png
  99. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Voice-Record.imageset/Contents.json
  100. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/Voice-Record.imageset/Voice-Record.png

BIN
.DS_Store


BIN
AppBuilder/.DS_Store


+ 673 - 0
AppBuilder/AppBuilder.xcodeproj/project.pbxproj

@@ -0,0 +1,673 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 54;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		12960AE02892361000A467DD /* FourthTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12960ADF2892361000A467DD /* FourthTabViewController.swift */; };
+		2401CE9A275490DB00B323BB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2401CE99275490DB00B323BB /* AppDelegate.swift */; };
+		2401CE9C275490DB00B323BB /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2401CE9B275490DB00B323BB /* SceneDelegate.swift */; };
+		2401CE9E275490DB00B323BB /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2401CE9D275490DB00B323BB /* ViewController.swift */; };
+		2401CEA1275490DB00B323BB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2401CE9F275490DB00B323BB /* Main.storyboard */; };
+		2401CEA3275490E600B323BB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2401CEA2275490E600B323BB /* Assets.xcassets */; };
+		2401CEA6275490E600B323BB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2401CEA4275490E600B323BB /* LaunchScreen.storyboard */; };
+		A413B18727EACB20006D16EB /* PrefsUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = A413B18627EACB20006D16EB /* PrefsUtil.swift */; };
+		A42ED92227F30BA200B0FAB7 /* FirstTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A42ED92127F30BA200B0FAB7 /* FirstTabViewController.swift */; };
+		A42ED92427F3FC2F00B0FAB7 /* SecondTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A42ED92327F3FC2F00B0FAB7 /* SecondTabViewController.swift */; };
+		A42ED92627F439A200B0FAB7 /* ThirdTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A42ED92527F439A200B0FAB7 /* ThirdTabViewController.swift */; };
+		C11E68605CFBACF560F5A037 /* Pods_AppBuilder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 169CB3023A5723F0238D7145 /* Pods_AppBuilder.framework */; };
+		CD9D59D92BEE1D30008014B4 /* digisales_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD9D59CE2BEE1D2F008014B4 /* digisales_icon.png */; };
+		CD9D59DA2BEE1D30008014B4 /* ikn_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD9D59CF2BEE1D2F008014B4 /* ikn_icon.png */; };
+		CD9D59DB2BEE1D30008014B4 /* gudeg_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD9D59D02BEE1D2F008014B4 /* gudeg_icon.png */; };
+		CD9D59DC2BEE1D30008014B4 /* nxcook_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD9D59D12BEE1D2F008014B4 /* nxcook_icon.png */; };
+		CD9D59DD2BEE1D30008014B4 /* nxsport_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD9D59D22BEE1D2F008014B4 /* nxsport_icon.png */; };
+		CD9D59DE2BEE1D30008014B4 /* bpkh_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD9D59D32BEE1D30008014B4 /* bpkh_icon.png */; };
+		CD9D59DF2BEE1D30008014B4 /* bi_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD9D59D42BEE1D30008014B4 /* bi_icon.png */; };
+		CD9D59E02BEE1D30008014B4 /* diginets_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD9D59D52BEE1D30008014B4 /* diginets_icon.png */; };
+		CD9D59E12BEE1D30008014B4 /* disini_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD9D59D62BEE1D30008014B4 /* disini_icon.png */; };
+		CD9D59E22BEE1D30008014B4 /* kmi_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD9D59D72BEE1D30008014B4 /* kmi_icon.png */; };
+		CD9D59E32BEE1D30008014B4 /* nu_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD9D59D82BEE1D30008014B4 /* nu_icon.png */; };
+		CDEE3DCC29B06E1E00B420E5 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDEE3DCB29B06E1E00B420E5 /* NotificationService.swift */; };
+		CDEE3DD029B06E1E00B420E5 /* NotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = CDEE3DC929B06E1E00B420E5 /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+		CDEE3DCE29B06E1E00B420E5 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 2401CE8E275490DB00B323BB /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = CDEE3DC829B06E1E00B420E5;
+			remoteInfo = NotificationService;
+		};
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		247E0A722796969200430E5F /* Embed Frameworks */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 10;
+			files = (
+			);
+			name = "Embed Frameworks";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		CDEE3DD129B06E1E00B420E5 /* Embed Foundation Extensions */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 13;
+			files = (
+				CDEE3DD029B06E1E00B420E5 /* NotificationService.appex in Embed Foundation Extensions */,
+			);
+			name = "Embed Foundation Extensions";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		12960ADF2892361000A467DD /* FourthTabViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FourthTabViewController.swift; sourceTree = "<group>"; };
+		169CB3023A5723F0238D7145 /* Pods_AppBuilder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AppBuilder.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		2401CE96275490DB00B323BB /* AppBuilder.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AppBuilder.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		2401CE99275490DB00B323BB /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
+		2401CE9B275490DB00B323BB /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
+		2401CE9D275490DB00B323BB /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
+		2401CEA0275490DB00B323BB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+		2401CEA2275490E600B323BB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		2401CEA5275490E600B323BB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+		2401CEA7275490E600B323BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		A413B18627EACB20006D16EB /* PrefsUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsUtil.swift; sourceTree = "<group>"; };
+		A42ED92127F30BA200B0FAB7 /* FirstTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstTabViewController.swift; sourceTree = "<group>"; };
+		A42ED92327F3FC2F00B0FAB7 /* SecondTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondTabViewController.swift; sourceTree = "<group>"; };
+		A42ED92527F439A200B0FAB7 /* ThirdTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThirdTabViewController.swift; sourceTree = "<group>"; };
+		CD9D59CE2BEE1D2F008014B4 /* digisales_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = digisales_icon.png; sourceTree = "<group>"; };
+		CD9D59CF2BEE1D2F008014B4 /* ikn_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ikn_icon.png; sourceTree = "<group>"; };
+		CD9D59D02BEE1D2F008014B4 /* gudeg_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = gudeg_icon.png; sourceTree = "<group>"; };
+		CD9D59D12BEE1D2F008014B4 /* nxcook_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = nxcook_icon.png; sourceTree = "<group>"; };
+		CD9D59D22BEE1D2F008014B4 /* nxsport_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = nxsport_icon.png; sourceTree = "<group>"; };
+		CD9D59D32BEE1D30008014B4 /* bpkh_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = bpkh_icon.png; sourceTree = "<group>"; };
+		CD9D59D42BEE1D30008014B4 /* bi_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = bi_icon.png; sourceTree = "<group>"; };
+		CD9D59D52BEE1D30008014B4 /* diginets_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = diginets_icon.png; sourceTree = "<group>"; };
+		CD9D59D62BEE1D30008014B4 /* disini_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = disini_icon.png; sourceTree = "<group>"; };
+		CD9D59D72BEE1D30008014B4 /* kmi_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = kmi_icon.png; sourceTree = "<group>"; };
+		CD9D59D82BEE1D30008014B4 /* nu_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = nu_icon.png; sourceTree = "<group>"; };
+		CDEE3DC929B06E1E00B420E5 /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+		CDEE3DCB29B06E1E00B420E5 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
+		CDEE3DCD29B06E1E00B420E5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		F29D18BB0B372CE96BE45B5F /* Pods-AppBuilder.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppBuilder.debug.xcconfig"; path = "Target Support Files/Pods-AppBuilder/Pods-AppBuilder.debug.xcconfig"; sourceTree = "<group>"; };
+		F8112E05F6E80E4B82AE18CE /* Pods-AppBuilder.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppBuilder.release.xcconfig"; path = "Target Support Files/Pods-AppBuilder/Pods-AppBuilder.release.xcconfig"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		2401CE93275490DB00B323BB /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				C11E68605CFBACF560F5A037 /* Pods_AppBuilder.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		CDEE3DC629B06E1E00B420E5 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		2401CE8D275490DB00B323BB = {
+			isa = PBXGroup;
+			children = (
+				2401CE98275490DB00B323BB /* AppBuilder */,
+				CDEE3DCA29B06E1E00B420E5 /* NotificationService */,
+				2401CE97275490DB00B323BB /* Products */,
+				6E32BCCF4DE50EE1A90E8AAE /* Pods */,
+				EB3AD86EF0270518F84092C6 /* Frameworks */,
+			);
+			sourceTree = "<group>";
+		};
+		2401CE97275490DB00B323BB /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				2401CE96275490DB00B323BB /* AppBuilder.app */,
+				CDEE3DC929B06E1E00B420E5 /* NotificationService.appex */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		2401CE98275490DB00B323BB /* AppBuilder */ = {
+			isa = PBXGroup;
+			children = (
+				CD9D59D42BEE1D30008014B4 /* bi_icon.png */,
+				CD9D59D32BEE1D30008014B4 /* bpkh_icon.png */,
+				CD9D59D52BEE1D30008014B4 /* diginets_icon.png */,
+				CD9D59CE2BEE1D2F008014B4 /* digisales_icon.png */,
+				CD9D59D62BEE1D30008014B4 /* disini_icon.png */,
+				CD9D59D02BEE1D2F008014B4 /* gudeg_icon.png */,
+				CD9D59CF2BEE1D2F008014B4 /* ikn_icon.png */,
+				CD9D59D72BEE1D30008014B4 /* kmi_icon.png */,
+				CD9D59D82BEE1D30008014B4 /* nu_icon.png */,
+				CD9D59D12BEE1D2F008014B4 /* nxcook_icon.png */,
+				CD9D59D22BEE1D2F008014B4 /* nxsport_icon.png */,
+				2401CE99275490DB00B323BB /* AppDelegate.swift */,
+				2401CE9B275490DB00B323BB /* SceneDelegate.swift */,
+				2401CE9D275490DB00B323BB /* ViewController.swift */,
+				2401CE9F275490DB00B323BB /* Main.storyboard */,
+				2401CEA2275490E600B323BB /* Assets.xcassets */,
+				2401CEA4275490E600B323BB /* LaunchScreen.storyboard */,
+				2401CEA7275490E600B323BB /* Info.plist */,
+				A413B18627EACB20006D16EB /* PrefsUtil.swift */,
+				A42ED92127F30BA200B0FAB7 /* FirstTabViewController.swift */,
+				A42ED92327F3FC2F00B0FAB7 /* SecondTabViewController.swift */,
+				A42ED92527F439A200B0FAB7 /* ThirdTabViewController.swift */,
+				12960ADF2892361000A467DD /* FourthTabViewController.swift */,
+			);
+			path = AppBuilder;
+			sourceTree = "<group>";
+		};
+		6E32BCCF4DE50EE1A90E8AAE /* Pods */ = {
+			isa = PBXGroup;
+			children = (
+				F29D18BB0B372CE96BE45B5F /* Pods-AppBuilder.debug.xcconfig */,
+				F8112E05F6E80E4B82AE18CE /* Pods-AppBuilder.release.xcconfig */,
+			);
+			path = Pods;
+			sourceTree = "<group>";
+		};
+		CDEE3DCA29B06E1E00B420E5 /* NotificationService */ = {
+			isa = PBXGroup;
+			children = (
+				CDEE3DCB29B06E1E00B420E5 /* NotificationService.swift */,
+				CDEE3DCD29B06E1E00B420E5 /* Info.plist */,
+			);
+			path = NotificationService;
+			sourceTree = "<group>";
+		};
+		EB3AD86EF0270518F84092C6 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				169CB3023A5723F0238D7145 /* Pods_AppBuilder.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		2401CE95275490DB00B323BB /* AppBuilder */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 2401CEC0275490E600B323BB /* Build configuration list for PBXNativeTarget "AppBuilder" */;
+			buildPhases = (
+				59A167444AFEF3E3735EB5CB /* [CP] Check Pods Manifest.lock */,
+				2401CE92275490DB00B323BB /* Sources */,
+				2401CE93275490DB00B323BB /* Frameworks */,
+				2401CE94275490DB00B323BB /* Resources */,
+				247E0A722796969200430E5F /* Embed Frameworks */,
+				CDEE3DD129B06E1E00B420E5 /* Embed Foundation Extensions */,
+				C75656FBE6F44FE88E2B122C /* [CP] Embed Pods Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				CDEE3DCF29B06E1E00B420E5 /* PBXTargetDependency */,
+			);
+			name = AppBuilder;
+			productName = TestQmeraLite;
+			productReference = 2401CE96275490DB00B323BB /* AppBuilder.app */;
+			productType = "com.apple.product-type.application";
+		};
+		CDEE3DC829B06E1E00B420E5 /* NotificationService */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = CDEE3DD429B06E1E00B420E5 /* Build configuration list for PBXNativeTarget "NotificationService" */;
+			buildPhases = (
+				CDEE3DC529B06E1E00B420E5 /* Sources */,
+				CDEE3DC629B06E1E00B420E5 /* Frameworks */,
+				CDEE3DC729B06E1E00B420E5 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = NotificationService;
+			productName = NotificationService;
+			productReference = CDEE3DC929B06E1E00B420E5 /* NotificationService.appex */;
+			productType = "com.apple.product-type.app-extension";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		2401CE8E275490DB00B323BB /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastSwiftUpdateCheck = 1420;
+				LastUpgradeCheck = 1250;
+				TargetAttributes = {
+					2401CE95275490DB00B323BB = {
+						CreatedOnToolsVersion = 12.5.1;
+					};
+					CDEE3DC829B06E1E00B420E5 = {
+						CreatedOnToolsVersion = 14.2;
+					};
+				};
+			};
+			buildConfigurationList = 2401CE91275490DB00B323BB /* Build configuration list for PBXProject "AppBuilder" */;
+			compatibilityVersion = "Xcode 9.3";
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = 2401CE8D275490DB00B323BB;
+			productRefGroup = 2401CE97275490DB00B323BB /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				2401CE95275490DB00B323BB /* AppBuilder */,
+				CDEE3DC829B06E1E00B420E5 /* NotificationService */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		2401CE94275490DB00B323BB /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CD9D59DA2BEE1D30008014B4 /* ikn_icon.png in Resources */,
+				CD9D59E32BEE1D30008014B4 /* nu_icon.png in Resources */,
+				CD9D59E02BEE1D30008014B4 /* diginets_icon.png in Resources */,
+				CD9D59DD2BEE1D30008014B4 /* nxsport_icon.png in Resources */,
+				CD9D59DC2BEE1D30008014B4 /* nxcook_icon.png in Resources */,
+				CD9D59DF2BEE1D30008014B4 /* bi_icon.png in Resources */,
+				2401CEA6275490E600B323BB /* LaunchScreen.storyboard in Resources */,
+				CD9D59E12BEE1D30008014B4 /* disini_icon.png in Resources */,
+				CD9D59DE2BEE1D30008014B4 /* bpkh_icon.png in Resources */,
+				CD9D59E22BEE1D30008014B4 /* kmi_icon.png in Resources */,
+				2401CEA3275490E600B323BB /* Assets.xcassets in Resources */,
+				CD9D59D92BEE1D30008014B4 /* digisales_icon.png in Resources */,
+				2401CEA1275490DB00B323BB /* Main.storyboard in Resources */,
+				CD9D59DB2BEE1D30008014B4 /* gudeg_icon.png in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		CDEE3DC729B06E1E00B420E5 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		59A167444AFEF3E3735EB5CB /* [CP] Check Pods Manifest.lock */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+			);
+			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
+			);
+			name = "[CP] Check Pods Manifest.lock";
+			outputFileListPaths = (
+			);
+			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-AppBuilder-checkManifestLockResult.txt",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+			showEnvVarsInLog = 0;
+		};
+		C75656FBE6F44FE88E2B122C /* [CP] Embed Pods Frameworks */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+				"${PODS_ROOT}/Target Support Files/Pods-AppBuilder/Pods-AppBuilder-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+			);
+			name = "[CP] Embed Pods Frameworks";
+			outputFileListPaths = (
+				"${PODS_ROOT}/Target Support Files/Pods-AppBuilder/Pods-AppBuilder-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AppBuilder/Pods-AppBuilder-frameworks.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		2401CE92275490DB00B323BB /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				A42ED92427F3FC2F00B0FAB7 /* SecondTabViewController.swift in Sources */,
+				A413B18727EACB20006D16EB /* PrefsUtil.swift in Sources */,
+				A42ED92227F30BA200B0FAB7 /* FirstTabViewController.swift in Sources */,
+				A42ED92627F439A200B0FAB7 /* ThirdTabViewController.swift in Sources */,
+				2401CE9E275490DB00B323BB /* ViewController.swift in Sources */,
+				2401CE9A275490DB00B323BB /* AppDelegate.swift in Sources */,
+				12960AE02892361000A467DD /* FourthTabViewController.swift in Sources */,
+				2401CE9C275490DB00B323BB /* SceneDelegate.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		CDEE3DC529B06E1E00B420E5 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CDEE3DCC29B06E1E00B420E5 /* NotificationService.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+		CDEE3DCF29B06E1E00B420E5 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = CDEE3DC829B06E1E00B420E5 /* NotificationService */;
+			targetProxy = CDEE3DCE29B06E1E00B420E5 /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+		2401CE9F275490DB00B323BB /* Main.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				2401CEA0275490DB00B323BB /* Base */,
+			);
+			name = Main.storyboard;
+			sourceTree = "<group>";
+		};
+		2401CEA4275490E600B323BB /* LaunchScreen.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				2401CEA5275490E600B323BB /* Base */,
+			);
+			name = LaunchScreen.storyboard;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		2401CEBE275490E600B323BB /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 14.5;
+				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+				MTL_FAST_MATH = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+			};
+			name = Debug;
+		};
+		2401CEBF275490E600B323BB /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 14.5;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				MTL_FAST_MATH = YES;
+				SDKROOT = iphoneos;
+				SWIFT_COMPILATION_MODE = wholemodule;
+				SWIFT_OPTIMIZATION_LEVEL = "-O";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		2401CEC1275490E600B323BB /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = F29D18BB0B372CE96BE45B5F /* Pods-AppBuilder.debug.xcconfig */;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+				BUILD_LIBRARY_FOR_DISTRIBUTION = NO;
+				CODE_SIGN_IDENTITY = "Apple Development";
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 2;
+				DEVELOPMENT_TEAM = FR2C2CZUYZ;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Frameworks",
+				);
+				INFOPLIST_FILE = AppBuilder/Info.plist;
+				INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
+				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				MARKETING_VERSION = 2.2.9;
+				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilders;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "";
+				SWIFT_VERSION = 5.0;
+				TARGETED_DEVICE_FAMILY = 1;
+			};
+			name = Debug;
+		};
+		2401CEC2275490E600B323BB /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = F8112E05F6E80E4B82AE18CE /* Pods-AppBuilder.release.xcconfig */;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+				BUILD_LIBRARY_FOR_DISTRIBUTION = NO;
+				CODE_SIGN_IDENTITY = "Apple Development";
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 2;
+				DEVELOPMENT_TEAM = FR2C2CZUYZ;
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Frameworks",
+				);
+				INFOPLIST_FILE = AppBuilder/Info.plist;
+				INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
+				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				MARKETING_VERSION = 2.2.9;
+				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilders;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "";
+				SWIFT_VERSION = 5.0;
+				TARGETED_DEVICE_FAMILY = 1;
+			};
+			name = Release;
+		};
+		CDEE3DD229B06E1E00B420E5 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+				CODE_SIGN_IDENTITY = "Apple Development";
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 1;
+				DEVELOPMENT_TEAM = FR2C2CZUYZ;
+				GENERATE_INFOPLIST_FILE = YES;
+				INFOPLIST_FILE = NotificationService/Info.plist;
+				INFOPLIST_KEY_CFBundleDisplayName = NotificationService;
+				INFOPLIST_KEY_NSHumanReadableCopyright = "";
+				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+					"@executable_path/../../Frameworks",
+				);
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilders.NotificationService;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_EMIT_LOC_STRINGS = YES;
+				SWIFT_VERSION = 5.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		CDEE3DD329B06E1E00B420E5 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+				CODE_SIGN_IDENTITY = "Apple Development";
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 1;
+				DEVELOPMENT_TEAM = FR2C2CZUYZ;
+				GENERATE_INFOPLIST_FILE = YES;
+				INFOPLIST_FILE = NotificationService/Info.plist;
+				INFOPLIST_KEY_CFBundleDisplayName = NotificationService;
+				INFOPLIST_KEY_NSHumanReadableCopyright = "";
+				IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+					"@executable_path/../../Frameworks",
+				);
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilders.NotificationService;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+				SWIFT_EMIT_LOC_STRINGS = YES;
+				SWIFT_VERSION = 5.0;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		2401CE91275490DB00B323BB /* Build configuration list for PBXProject "AppBuilder" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				2401CEBE275490E600B323BB /* Debug */,
+				2401CEBF275490E600B323BB /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		2401CEC0275490E600B323BB /* Build configuration list for PBXNativeTarget "AppBuilder" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				2401CEC1275490E600B323BB /* Debug */,
+				2401CEC2275490E600B323BB /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		CDEE3DD429B06E1E00B420E5 /* Build configuration list for PBXNativeTarget "NotificationService" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				CDEE3DD229B06E1E00B420E5 /* Debug */,
+				CDEE3DD329B06E1E00B420E5 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 2401CE8E275490DB00B323BB /* Project object */;
+}

+ 7 - 0
AppBuilder/AppBuilder.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:">
+   </FileRef>
+</Workspace>

+ 8 - 0
AppBuilder/AppBuilder.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IDEDidComputeMac32BitWarning</key>
+	<true/>
+</dict>
+</plist>

+ 98 - 0
AppBuilder/AppBuilder.xcodeproj/xcshareddata/xcschemes/AppBuilder.xcscheme

@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1250"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "2401CE95275490DB00B323BB"
+               BuildableName = "AppBuilder.app"
+               BlueprintName = "AppBuilder"
+               ReferencedContainer = "container:AppBuilder.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "2401CEAB275490E600B323BB"
+               BuildableName = "AppBuilderTests.xctest"
+               BlueprintName = "AppBuilderTests"
+               ReferencedContainer = "container:AppBuilder.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "2401CEB6275490E600B323BB"
+               BuildableName = "AppBuilderUITests.xctest"
+               BlueprintName = "AppBuilderUITests"
+               ReferencedContainer = "container:AppBuilder.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "2401CE95275490DB00B323BB"
+            BuildableName = "AppBuilder.app"
+            BlueprintName = "AppBuilder"
+            ReferencedContainer = "container:AppBuilder.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "2401CE95275490DB00B323BB"
+            BuildableName = "AppBuilder.app"
+            BlueprintName = "AppBuilder"
+            ReferencedContainer = "container:AppBuilder.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Debug"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 10 - 0
AppBuilder/AppBuilder.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "group:AppBuilder.xcodeproj">
+   </FileRef>
+   <FileRef
+      location = "group:Pods/Pods.xcodeproj">
+   </FileRef>
+</Workspace>

+ 8 - 0
AppBuilder/AppBuilder.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IDEDidComputeMac32BitWarning</key>
+	<true/>
+</dict>
+</plist>

+ 155 - 0
AppBuilder/AppBuilder/AppDelegate.swift

@@ -0,0 +1,155 @@
+//
+//  AppDelegate.swift
+//  TestQmeraLite
+//
+//  Created by Qindi on 29/11/21.
+//
+
+import UIKit
+import NexilisLite
+import NotificationBannerSwift
+
+@main
+class AppDelegate: UIResponder, UIApplicationDelegate {
+    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
+        var showButton = false
+        if PrefsUtil.getCpaasMode() == PrefsUtil.CPAAS_MODE_FLOATING || PrefsUtil.getCpaasMode() == PrefsUtil.CPAAS_MODE_MIX {
+            showButton = true
+        }
+        Nexilis.isShowForceSignIn = false
+        APIS.connect(appName: Bundle.main.infoDictionary?["CFBundleName"] as! String , apiKey: "***REPLACE***WITH***YOUR***ACCOUNT***", delegate: self, showButton: showButton, fromMAB: true) //23091CF494A11149F5A8FC8D17FF690DC69AE656F91B86070A11506ED24144F5(BPKH) //38747683290F62E9667A018F490396EAE47BC16ADECD85B7E865C733E6DBD6A2(OneApp)
+        registerForPushNotifications()
+        return true
+    }
+
+    // MARK: UISceneSession Lifecycle
+
+    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
+        // Called when a new scene session is being created.
+        // Use this method to select a configuration to create the new scene with.
+        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
+    }
+
+    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
+        Nexilis.destroyAll()
+        // Called when the user discards a scene session.
+        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
+        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
+    }
+    
+    private func registerForPushNotifications() {
+        if #available(iOS 10.0, *) {
+            let center  = UNUserNotificationCenter.current()
+            center.delegate = self
+            center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
+                if error == nil{
+                    DispatchQueue.main.async {
+                        UIApplication.shared.registerForRemoteNotifications()
+                    }
+                }
+            }
+        }
+        else {
+            UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.sound, .alert, .badge], categories: nil))
+            UIApplication.shared.registerForRemoteNotifications()
+        }
+    }
+
+
+}
+
+extension AppDelegate: ConnectDelegate, UNUserNotificationCenterDelegate {
+    
+    func onSuccess(userId: String) {
+        //print(#function, "userId: \(userId)")
+    }
+    
+    func onFailed(error: String) {
+        //print(#function, "error: \(error)")
+    }
+    
+    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
+        let deviceTokenString = deviceToken.map { String(format: "%02x", $0) }.joined()
+        //print("TOKEN: \(deviceTokenString)")
+    }
+    
+    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
+        //print(error)
+    }
+    
+    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
+        let userInfo = response.notification.request.content.userInfo
+        if let opposite = userInfo["opposite"] as? String {
+            let user = User.getDataCanNil(pin: opposite)
+            if user != nil {
+                openEditorPersonal(opposite: opposite)
+            } else {
+                let group = Group.getData(group_id: opposite)
+                let topic = Topic.getData(topic_id: opposite)
+                if group != nil || topic != nil {
+                    openEditorGroup(opposite: opposite)
+                }
+            }
+        }
+        UIApplication.shared.applicationIconBadgeNumber = 0
+        UNUserNotificationCenter.current().removeAllDeliveredNotifications()
+        completionHandler()
+    }
+    
+    func openEditorPersonal(opposite: String) {
+        let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
+        editorPersonalVC.hidesBottomBarWhenPushed = true
+        editorPersonalVC.unique_l_pin = opposite
+        editorPersonalVC.fromNotification = true
+        let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
+        if !onGoingCC.isEmpty {
+            let compalintId = onGoingCC.components(separatedBy: ",")[2]
+            let fPinCC = onGoingCC.isEmpty ? "" : onGoingCC.components(separatedBy: ",")[1]
+            editorPersonalVC.isContactCenter = true
+            editorPersonalVC.fPinContacCenter = fPinCC
+            editorPersonalVC.complaintId = compalintId
+            editorPersonalVC.onGoingCC = true
+            editorPersonalVC.isRequestContactCenter = false
+        }
+        let navigationController = CustomNavigationController(rootViewController: editorPersonalVC)
+        navigationController.modalPresentationStyle = .fullScreen
+        navigationController.navigationBar.tintColor = .white
+        navigationController.navigationBar.barTintColor = UIApplication.shared.visibleViewController?.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
+        navigationController.navigationBar.isTranslucent = false
+        navigationController.navigationBar.overrideUserInterfaceStyle = .dark
+        navigationController.navigationBar.barStyle = .black
+        let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
+        UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
+        let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
+        navigationController.navigationBar.titleTextAttributes = textAttributes
+        if UIApplication.shared.visibleViewController?.navigationController != nil {
+            UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
+        } else {
+            UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
+        }
+    }
+    
+    func openEditorGroup(opposite: String) {
+        let editorGroupVC = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "editorGroupVC") as! EditorGroup
+        editorGroupVC.hidesBottomBarWhenPushed = true
+        editorGroupVC.unique_l_pin = opposite
+        editorGroupVC.fromNotification = true
+        let navigationController = CustomNavigationController(rootViewController: editorGroupVC)
+        navigationController.modalPresentationStyle = .fullScreen
+        navigationController.navigationBar.tintColor = .white
+        navigationController.navigationBar.barTintColor = UIApplication.shared.visibleViewController?.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
+        navigationController.navigationBar.isTranslucent = false
+        navigationController.navigationBar.overrideUserInterfaceStyle = .dark
+        navigationController.navigationBar.barStyle = .black
+        let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
+        UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
+        let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
+        navigationController.navigationBar.titleTextAttributes = textAttributes
+        if UIApplication.shared.visibleViewController?.navigationController != nil {
+            UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
+        } else {
+            UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
+        }
+    }
+}
+

+ 11 - 0
AppBuilder/AppBuilder/Assets.xcassets/AccentColor.colorset/Contents.json

@@ -0,0 +1,11 @@
+{
+  "colors" : [
+    {
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/1024.png


BIN
AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/114.png


BIN
AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/120.png


BIN
AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/180.png


BIN
AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/29.png


BIN
AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/40.png


BIN
AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/57.png


BIN
AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/58.png


BIN
AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/60.png


BIN
AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/80.png


BIN
AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/87.png


+ 80 - 0
AppBuilder/AppBuilder/Assets.xcassets/AppIcon.appiconset/Contents.json

@@ -0,0 +1,80 @@
+{
+  "images" : [
+    {
+      "filename" : "40.png",
+      "idiom" : "iphone",
+      "scale" : "2x",
+      "size" : "20x20"
+    },
+    {
+      "filename" : "60.png",
+      "idiom" : "iphone",
+      "scale" : "3x",
+      "size" : "20x20"
+    },
+    {
+      "filename" : "29.png",
+      "idiom" : "iphone",
+      "scale" : "1x",
+      "size" : "29x29"
+    },
+    {
+      "filename" : "58.png",
+      "idiom" : "iphone",
+      "scale" : "2x",
+      "size" : "29x29"
+    },
+    {
+      "filename" : "87.png",
+      "idiom" : "iphone",
+      "scale" : "3x",
+      "size" : "29x29"
+    },
+    {
+      "filename" : "80.png",
+      "idiom" : "iphone",
+      "scale" : "2x",
+      "size" : "40x40"
+    },
+    {
+      "filename" : "120.png",
+      "idiom" : "iphone",
+      "scale" : "3x",
+      "size" : "40x40"
+    },
+    {
+      "filename" : "57.png",
+      "idiom" : "iphone",
+      "scale" : "1x",
+      "size" : "57x57"
+    },
+    {
+      "filename" : "114.png",
+      "idiom" : "iphone",
+      "scale" : "2x",
+      "size" : "57x57"
+    },
+    {
+      "filename" : "120.png",
+      "idiom" : "iphone",
+      "scale" : "2x",
+      "size" : "60x60"
+    },
+    {
+      "filename" : "180.png",
+      "idiom" : "iphone",
+      "scale" : "3x",
+      "size" : "60x60"
+    },
+    {
+      "filename" : "1024.png",
+      "idiom" : "ios-marketing",
+      "scale" : "1x",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 6 - 0
AppBuilder/AppBuilder/Assets.xcassets/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 21 - 0
AppBuilder/AppBuilder/Assets.xcassets/ic_broadcast.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "ic_broadcast.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
AppBuilder/AppBuilder/Assets.xcassets/ic_broadcast.imageset/ic_broadcast.png


+ 21 - 0
AppBuilder/AppBuilder/Assets.xcassets/pb_icon.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "nexilis_icon.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
AppBuilder/AppBuilder/Assets.xcassets/pb_icon.imageset/nexilis_icon.png


+ 21 - 0
AppBuilder/AppBuilder/Assets.xcassets/pb_powered_button.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_powered_button.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
AppBuilder/AppBuilder/Assets.xcassets/pb_powered_button.imageset/pb_powered_button.png


+ 21 - 0
AppBuilder/AppBuilder/Assets.xcassets/tab_1_icon.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "tab_1_nexilis.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
AppBuilder/AppBuilder/Assets.xcassets/tab_1_icon.imageset/tab_1_nexilis.png


+ 21 - 0
AppBuilder/AppBuilder/Assets.xcassets/tab_2_icon.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "tab_2_nexilis.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
AppBuilder/AppBuilder/Assets.xcassets/tab_2_icon.imageset/tab_2_nexilis.png


+ 21 - 0
AppBuilder/AppBuilder/Assets.xcassets/tab_3_icon.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "tab_3_nexilis.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
AppBuilder/AppBuilder/Assets.xcassets/tab_3_icon.imageset/tab_3_nexilis.png


+ 21 - 0
AppBuilder/AppBuilder/Assets.xcassets/tab_4_icon.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "tab_4_nexilis.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
AppBuilder/AppBuilder/Assets.xcassets/tab_4_icon.imageset/tab_4_nexilis.png


+ 48 - 0
AppBuilder/AppBuilder/Base.lproj/LaunchScreen.storyboard

@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
+    <device id="retina6_1" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="EHf-IW-A2E">
+            <objects>
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="pb_icon" translatesAutoresizingMaskIntoConstraints="NO" id="Dki-8X-fvw">
+                                <rect key="frame" x="107" y="348" width="200" height="200"/>
+                                <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="200" id="Kvz-Gz-JlQ"/>
+                                    <constraint firstAttribute="width" constant="200" id="YUt-RC-lbI"/>
+                                </constraints>
+                            </imageView>
+                        </subviews>
+                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
+                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                        <constraints>
+                            <constraint firstItem="Dki-8X-fvw" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="P1E-dg-6gJ"/>
+                            <constraint firstItem="Dki-8X-fvw" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="ZXk-uU-Old"/>
+                        </constraints>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="53" y="375"/>
+        </scene>
+    </scenes>
+    <resources>
+        <image name="pb_icon" width="1024" height="1024"/>
+        <systemColor name="systemBackgroundColor">
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+        </systemColor>
+    </resources>
+</document>

+ 295 - 0
AppBuilder/AppBuilder/Base.lproj/Main.storyboard

@@ -0,0 +1,295 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="nD6-T3-59p">
+    <device id="retina6_7" orientation="portrait" appearance="dark"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--Item 2-->
+        <scene sceneID="3Wf-gK-qyG">
+            <objects>
+                <viewController id="yL2-sh-r2b" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="Cwo-Ej-asl">
+                        <rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <viewLayoutGuide key="safeArea" id="NCr-Sf-zM1"/>
+                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    </view>
+                    <tabBarItem key="tabBarItem" title="Item 2" id="3tr-an-hLR"/>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="Fum-Sw-dKP" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-94" y="525"/>
+        </scene>
+        <!--First Tab View Controller-->
+        <scene sceneID="bNR-du-k4c">
+            <objects>
+                <viewController storyboardIdentifier="firstTabVC" useStoryboardIdentifierAsRestorationIdentifier="YES" id="iKy-YH-N88" customClass="FirstTabViewController" customModule="AppBuilder" customModuleProvider="target" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="OUO-5T-AtV">
+                        <rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <viewLayoutGuide key="safeArea" id="f2x-TV-t0G"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="1UN-B6-dct" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-772" y="1185"/>
+        </scene>
+        <!--Second Tab View Controller-->
+        <scene sceneID="JH2-j3-Jce">
+            <objects>
+                <viewController storyboardIdentifier="secondTabVC" useStoryboardIdentifierAsRestorationIdentifier="YES" id="z6f-Hz-Xwh" customClass="SecondTabViewController" customModule="AppBuilder" customModuleProvider="target" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="T1X-gt-fSN">
+                        <rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="BU2-P5-16y">
+                                <rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
+                            </imageView>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oT8-Uw-cgS">
+                                <rect key="frame" x="0.0" y="47" width="428" height="845"/>
+                                <subviews>
+                                    <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="4Jc-b8-aeF">
+                                        <rect key="frame" x="0.0" y="0.0" width="428" height="845"/>
+                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                        <prototypes>
+                                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="reuseIdentifierChat" id="Tz5-0s-zFj">
+                                                <rect key="frame" x="0.0" y="50" width="428" height="43.666667938232422"/>
+                                                <autoresizingMask key="autoresizingMask"/>
+                                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Tz5-0s-zFj" id="4MW-eb-afV">
+                                                    <rect key="frame" x="0.0" y="0.0" width="428" height="43.666667938232422"/>
+                                                    <autoresizingMask key="autoresizingMask"/>
+                                                </tableViewCellContentView>
+                                            </tableViewCell>
+                                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="reuseIdentifierGroup" id="im7-ks-lTd">
+                                                <rect key="frame" x="0.0" y="93.666667938232422" width="428" height="43.666667938232422"/>
+                                                <autoresizingMask key="autoresizingMask"/>
+                                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="im7-ks-lTd" id="lNo-4T-eyr">
+                                                    <rect key="frame" x="0.0" y="0.0" width="428" height="43.666667938232422"/>
+                                                    <autoresizingMask key="autoresizingMask"/>
+                                                </tableViewCellContentView>
+                                            </tableViewCell>
+                                        </prototypes>
+                                        <connections>
+                                            <outlet property="dataSource" destination="z6f-Hz-Xwh" id="AOZ-F1-Rhe"/>
+                                            <outlet property="delegate" destination="z6f-Hz-Xwh" id="rwB-hc-wXw"/>
+                                        </connections>
+                                    </tableView>
+                                </subviews>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                <constraints>
+                                    <constraint firstAttribute="bottom" secondItem="4Jc-b8-aeF" secondAttribute="bottom" id="AJg-3y-ycq"/>
+                                    <constraint firstAttribute="trailing" secondItem="4Jc-b8-aeF" secondAttribute="trailing" id="MQg-wg-wJC"/>
+                                    <constraint firstItem="4Jc-b8-aeF" firstAttribute="leading" secondItem="oT8-Uw-cgS" secondAttribute="leading" id="gr8-uB-Kjv"/>
+                                    <constraint firstItem="4Jc-b8-aeF" firstAttribute="top" secondItem="oT8-Uw-cgS" secondAttribute="top" id="tgW-8t-y1Q"/>
+                                </constraints>
+                            </view>
+                        </subviews>
+                        <viewLayoutGuide key="safeArea" id="Exo-M2-oVn"/>
+                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <constraints>
+                            <constraint firstItem="BU2-P5-16y" firstAttribute="top" secondItem="T1X-gt-fSN" secondAttribute="top" id="6kj-QA-eHg"/>
+                            <constraint firstItem="oT8-Uw-cgS" firstAttribute="leading" secondItem="Exo-M2-oVn" secondAttribute="leading" id="9FF-6z-ROG"/>
+                            <constraint firstItem="oT8-Uw-cgS" firstAttribute="top" secondItem="Exo-M2-oVn" secondAttribute="top" id="CvI-hv-hNw"/>
+                            <constraint firstItem="Exo-M2-oVn" firstAttribute="bottom" secondItem="oT8-Uw-cgS" secondAttribute="bottom" id="Imt-VX-VR1"/>
+                            <constraint firstItem="BU2-P5-16y" firstAttribute="leading" secondItem="Exo-M2-oVn" secondAttribute="leading" id="L9z-Na-Kbb"/>
+                            <constraint firstItem="Exo-M2-oVn" firstAttribute="trailing" secondItem="BU2-P5-16y" secondAttribute="trailing" id="Udn-OO-sE2"/>
+                            <constraint firstItem="oT8-Uw-cgS" firstAttribute="trailing" secondItem="Exo-M2-oVn" secondAttribute="trailing" id="Vck-XN-acd"/>
+                            <constraint firstAttribute="bottom" secondItem="BU2-P5-16y" secondAttribute="bottom" id="jai-lq-WbQ"/>
+                        </constraints>
+                    </view>
+                    <connections>
+                        <outlet property="backgroundImage" destination="BU2-P5-16y" id="gud-Yi-EyH"/>
+                        <outlet property="tableView" destination="4Jc-b8-aeF" id="kie-X3-tsw"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iEb-Pf-p13" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-94.20289855072464" y="1184.5982142857142"/>
+        </scene>
+        <!--Item 1-->
+        <scene sceneID="N8z-aZ-R0C">
+            <objects>
+                <viewController id="shx-A0-Rpw" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="0VY-c7-1YL">
+                        <rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <viewLayoutGuide key="safeArea" id="cTG-dq-upN"/>
+                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    </view>
+                    <tabBarItem key="tabBarItem" title="Item 1" id="p7E-Es-Ytv"/>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="ea8-TI-6Jg" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-772" y="525"/>
+        </scene>
+        <!--test-->
+        <scene sceneID="P0z-HA-ArT">
+            <objects>
+                <navigationController title="test" id="nD6-T3-59p" sceneMemberID="viewController">
+                    <navigationBar key="navigationBar" opaque="NO" contentMode="scaleToFill" id="mEs-FV-nQc">
+                        <rect key="frame" x="0.0" y="47" width="428" height="44"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <color key="barTintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <textAttributes key="titleTextAttributes">
+                            <color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        </textAttributes>
+                        <textAttributes key="largeTitleTextAttributes">
+                            <color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        </textAttributes>
+                    </navigationBar>
+                    <toolbar key="toolbar" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="7Tu-EZ-US7">
+                        <autoresizingMask key="autoresizingMask"/>
+                    </toolbar>
+                    <connections>
+                        <segue destination="303-e4-dlv" kind="relationship" relationship="rootViewController" id="ax7-Vc-WBo"/>
+                    </connections>
+                </navigationController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="2PQ-0V-IE2" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-145" y="-202"/>
+        </scene>
+        <!--mainVC-->
+        <scene sceneID="acr-UY-sCb">
+            <objects>
+                <tabBarController title="mainVC" id="303-e4-dlv" customClass="ViewController" customModule="AppBuilder" customModuleProvider="target" sceneMemberID="viewController">
+                    <navigationItem key="navigationItem" id="sH1-Nb-Vna"/>
+                    <tabBar key="tabBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="aG7-6Q-gSS">
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="49"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <color key="barTintColor" white="0.91082411545973563" alpha="1" colorSpace="calibratedWhite"/>
+                    </tabBar>
+                    <connections>
+                        <segue destination="shx-A0-Rpw" kind="relationship" relationship="viewControllers" id="InU-1A-5CF"/>
+                        <segue destination="yL2-sh-r2b" kind="relationship" relationship="viewControllers" id="2uQ-yM-Uwx"/>
+                        <segue destination="BQG-BK-XdT" kind="relationship" relationship="viewControllers" id="xa0-0l-EhV"/>
+                        <segue destination="HRs-yQ-che" kind="relationship" relationship="viewControllers" id="H7y-1o-pCn"/>
+                        <segue destination="doo-wB-Xef" kind="relationship" relationship="viewControllers" id="XZ7-g3-417"/>
+                    </connections>
+                </tabBarController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="xVj-nd-1u2" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="619" y="-202"/>
+        </scene>
+        <!--Item 3-->
+        <scene sceneID="akE-9q-KIu">
+            <objects>
+                <viewController id="BQG-BK-XdT" userLabel="Item 3" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="tfu-1X-nbl">
+                        <rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <viewLayoutGuide key="safeArea" id="5ym-td-Khs"/>
+                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    </view>
+                    <tabBarItem key="tabBarItem" title="Item 3" id="fhU-xt-rD1" userLabel="Item 3"/>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dEh-1z-WOg" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="619" y="525"/>
+        </scene>
+        <!--Item 4-->
+        <scene sceneID="ayN-8g-7Qb">
+            <objects>
+                <viewController id="HRs-yQ-che" userLabel="Item 4" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="CpP-4M-jQO">
+                        <rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <viewLayoutGuide key="safeArea" id="FW7-Pt-spm"/>
+                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    </view>
+                    <tabBarItem key="tabBarItem" title="Item 4" id="9HE-z6-qW3" userLabel="Item 4"/>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="kTc-lt-5jQ" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1293" y="525"/>
+        </scene>
+        <!--Item 5-->
+        <scene sceneID="1OZ-lX-QwV">
+            <objects>
+                <viewController id="doo-wB-Xef" userLabel="Item 5" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="gva-IL-Ua7">
+                        <rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <viewLayoutGuide key="safeArea" id="b9A-7D-aDQ"/>
+                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    </view>
+                    <tabBarItem key="tabBarItem" title="Item 5" id="aDp-Df-R88" userLabel="Item 5"/>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="pku-2n-PfH" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="2017" y="525"/>
+        </scene>
+        <!--Third Tab View Controller-->
+        <scene sceneID="2tv-T7-3Gz">
+            <objects>
+                <viewController storyboardIdentifier="thirdTabVC" useStoryboardIdentifierAsRestorationIdentifier="YES" id="sim-nJ-liW" customClass="ThirdTabViewController" customModule="AppBuilder" customModuleProvider="target" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="zlx-Nr-4qk">
+                        <rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <viewLayoutGuide key="safeArea" id="gQh-2u-SN6"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="crD-Us-xmX" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="619" y="1185"/>
+        </scene>
+        <!--Fourth Tab View Controller-->
+        <scene sceneID="ZzT-E6-umc">
+            <objects>
+                <viewController storyboardIdentifier="fourthTabVC" useStoryboardIdentifierAsRestorationIdentifier="YES" id="ruc-qb-tdV" customClass="FourthTabViewController" customModule="AppBuilder" customModuleProvider="target" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="9o3-Cd-xmC">
+                        <rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="rdi-Bn-gaF">
+                                <rect key="frame" x="0.0" y="0.0" width="428" height="926"/>
+                            </imageView>
+                            <tableView opaque="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" bouncesZoom="NO" dataMode="prototypes" style="insetGrouped" separatorStyle="default" separatorInsetReference="fromAutomaticInsets" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="5" sectionFooterHeight="5" translatesAutoresizingMaskIntoConstraints="NO" id="gUO-Ws-n00">
+                                <rect key="frame" x="0.0" y="80" width="428" height="807"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                <inset key="separatorInset" minX="3" minY="0.0" maxX="0.0" maxY="0.0"/>
+                                <color key="sectionIndexBackgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                <prototypes>
+                                    <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="2" reuseIdentifier="reuseIdentifier" id="IEo-SX-4um">
+                                        <rect key="frame" x="20" y="55.333332061767578" width="388" height="43.666667938232422"/>
+                                        <autoresizingMask key="autoresizingMask"/>
+                                        <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="IEo-SX-4um" id="je4-kr-tvF">
+                                            <rect key="frame" x="0.0" y="0.0" width="388" height="43.666667938232422"/>
+                                            <autoresizingMask key="autoresizingMask"/>
+                                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                            <edgeInsets key="layoutMargins" top="0.0" left="0.0" bottom="0.0" right="0.0"/>
+                                        </tableViewCellContentView>
+                                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                    </tableViewCell>
+                                </prototypes>
+                            </tableView>
+                        </subviews>
+                        <viewLayoutGuide key="safeArea" id="SgQ-c4-v3h"/>
+                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                        <constraints>
+                            <constraint firstItem="rdi-Bn-gaF" firstAttribute="top" secondItem="9o3-Cd-xmC" secondAttribute="top" id="3iG-Qg-ugF"/>
+                            <constraint firstItem="SgQ-c4-v3h" firstAttribute="bottom" secondItem="gUO-Ws-n00" secondAttribute="bottom" constant="5" id="cJW-F2-vbP"/>
+                            <constraint firstItem="gUO-Ws-n00" firstAttribute="top" secondItem="9o3-Cd-xmC" secondAttribute="top" constant="80" id="dgB-Kt-3hN"/>
+                            <constraint firstAttribute="bottom" secondItem="rdi-Bn-gaF" secondAttribute="bottom" id="i6c-Au-25J"/>
+                            <constraint firstItem="SgQ-c4-v3h" firstAttribute="trailing" secondItem="rdi-Bn-gaF" secondAttribute="trailing" id="ka4-Ak-VDR"/>
+                            <constraint firstItem="gUO-Ws-n00" firstAttribute="trailing" secondItem="SgQ-c4-v3h" secondAttribute="trailing" id="suE-CO-UTB"/>
+                            <constraint firstItem="rdi-Bn-gaF" firstAttribute="leading" secondItem="SgQ-c4-v3h" secondAttribute="leading" id="wzr-gR-Yrs"/>
+                            <constraint firstItem="gUO-Ws-n00" firstAttribute="leading" secondItem="SgQ-c4-v3h" secondAttribute="leading" id="xiY-lp-lrd"/>
+                        </constraints>
+                    </view>
+                    <connections>
+                        <outlet property="backgroundImage" destination="rdi-Bn-gaF" id="MAO-jC-VP5"/>
+                        <outlet property="tableView" destination="gUO-Ws-n00" id="8ZB-Pu-MLW"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="R3B-ld-vod" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1293" y="1184"/>
+        </scene>
+    </scenes>
+</document>

+ 608 - 0
AppBuilder/AppBuilder/FirstTabViewController.swift

@@ -0,0 +1,608 @@
+//
+//  FirstTabViewController.swift
+//  AppBuilder
+//
+//  Created by Kevin Maulana on 29/03/22.
+//
+
+import UIKit
+import WebKit
+import NexilisLite
+import Speech
+
+class FirstTabViewController: UIViewController, UIScrollViewDelegate, UIGestureRecognizerDelegate, WKScriptMessageHandler {
+    
+    var webView: WKWebView!
+    var address = ""
+    private var lastContentOffset: CGFloat = 0
+    
+    var isAllowSpeech = false
+    
+    let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "id"))
+
+    var recognitionRequest : SFSpeechAudioBufferRecognitionRequest?
+    var recognitionTask : SFSpeechRecognitionTask?
+    let audioEngine = AVAudioEngine()
+    var alertController = LibAlertController()
+    
+    var dateRefresh: Date?
+    public static var forceRefresh = false
+    public static var atFirstPage = true
+    public static var showModal = false
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        
+        self.view.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .black : .white
+        
+        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(collapseDocked))
+        tapGesture.cancelsTouchesInView = false
+        tapGesture.delegate = self
+        let configuration = WKWebViewConfiguration()
+        configuration.allowsInlineMediaPlayback = true
+        let customUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1 \(Utils.getUserAgent())"
+        let finalUserAgent = "\(customUserAgent)"
+        configuration.applicationNameForUserAgent = finalUserAgent
+        webView = WKWebView(frame: .zero, configuration: configuration)
+        view.addSubview(webView)
+        webView.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
+            webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
+            webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
+            webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
+        ])
+        webView.scrollView.addGestureRecognizer(tapGesture)
+        let refreshControl = UIRefreshControl()
+        refreshControl.addTarget(self, action: #selector(reloadWebView(_:)), for: .valueChanged)
+        webView.scrollView.addSubview(refreshControl)
+        webView.scrollView.delegate = self
+        webView.navigationDelegate = self
+        webView.allowsBackForwardNavigationGestures = true
+        
+        let contentController = self.webView.configuration.userContentController
+        contentController.add(self, name: "checkProfile")
+        contentController.add(self, name: "setIsProductModalOpen")
+        contentController.add(self, name: "toggleVoiceSearch")
+        contentController.add(self, name: "blockUser")
+        contentController.add(self, name: "showAlert")
+        contentController.add(self, name: "closeProfile")
+        contentController.add(self, name: "tabShowHide")
+        
+        let source: String = "var meta = document.createElement('meta');" +
+            "meta.name = 'viewport';" +
+            "meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no';" +
+            "var head = document.getElementsByTagName('head')[0];" +
+            "head.appendChild(meta);" +
+        "$('#header-layout').find('.col-8').removeClass('col-8').addClass('col');" +
+        "$('#header-layout').find('.col-4').removeClass('col-4').addClass('col');"
+        let script: WKUserScript = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
+        contentController.addUserScript(script)
+        
+        let cookieScript1 = "document.cookie = '\(Utils.getCookiesMobile().components(separatedBy: ";")[0])';"
+        let cookieScriptInjection1 = WKUserScript(source: cookieScript1, injectionTime: .atDocumentStart, forMainFrameOnly: false)
+        configuration.userContentController.addUserScript(cookieScriptInjection1)
+        
+        let cookieScript2 = "document.cookie = '\(Utils.getCookiesMobile().components(separatedBy: ";")[1])';"
+        let cookieScriptInjection2 = WKUserScript(source: cookieScript2, injectionTime: .atDocumentStart, forMainFrameOnly: false)
+        configuration.userContentController.addUserScript(cookieScriptInjection2)
+        
+        NotificationCenter.default.addObserver(self, selector: #selector(onShowAC(notification:)), name: NSNotification.Name(rawValue: "onShowAC"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onRefreshWebView(notification:)), name: NSNotification.Name(rawValue: "onRefreshWebView"), object: nil)
+    }
+    
+    func loadURLWithCookie(url: URL) {
+        var urlRequest = URLRequest(url: url)
+        let cookieHeader = Utils.getCookiesMobile()
+        urlRequest.addValue(cookieHeader, forHTTPHeaderField: "Cookie")
+        let customUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1 \(Utils.getUserAgent())"
+        urlRequest.setValue(customUserAgent, forHTTPHeaderField: "User-Agent")
+        webView.load(urlRequest)
+        
+        if let cookies = HTTPCookieStorage.shared.cookies {
+            for cookie in cookies {
+                webView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie)
+            }
+        }
+    }
+    
+    override func viewWillAppear(_ animated: Bool) {
+        let me = UserDefaults.standard.string(forKey: "me")
+        
+        var myURL : URL?
+        let lang = UserDefaults.standard.string(forKey: "i18n_language")
+        var intLang = 0
+        if lang == "id" {
+            intLang = 1
+        }
+        if PrefsUtil.getURLFirstTab() != nil {
+            ViewController.sURL = PrefsUtil.getURLFirstTab()!
+        }
+        switch(ViewController.sURL){
+        case "0":
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main-only?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
+            myURL = URL(string: address)
+        case "1":
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-main-only?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
+            myURL = URL(string: address)
+        case "2":
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
+            myURL = URL(string: address)
+        case "3":
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-commerce?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
+            myURL = URL(string: address)
+        case "4":
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-video?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
+            myURL = URL(string: address)
+        default:
+            if(!ViewController.sURL.isEmpty){
+                if(ViewController.sURL.lowercased().contains("https://") || ViewController.sURL.lowercased().contains("http://")){
+                    address = ViewController.sURL
+                    myURL = URL(string: address)
+                }
+                else {
+                    if ViewController.sURL.contains("nexilis/pages"){
+                        address = "\(PrefsUtil.getURLBase())\(ViewController.sURL)?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
+                    } else {
+                        address = "https://\(ViewController.sURL)"
+                    }
+                    myURL = URL(string: address)
+                }
+            }
+        }
+        if let u = myURL {
+            self.webView.evaluateJavaScript("{window.localStorage.setItem('currentTab','\(ViewController.sURL)')}")
+            if ((dateRefresh == nil || Int(Date().timeIntervalSince(dateRefresh!)) >= 60) && FirstTabViewController.atFirstPage) || FirstTabViewController.forceRefresh {
+//                let myRequest = URLRequest(url: u)
+                loadURLWithCookie(url: u)
+            } else {
+                self.webView.evaluateJavaScript("if(resumeAll){resumeAll();}")
+            }
+            dateRefresh = Date()
+            FirstTabViewController.forceRefresh = false
+        }
+        navigationController?.setNavigationBarHidden(true, animated: false)
+    }
+    
+    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
+        if Utils.getIsLoadThemeFromOther() {
+            self.webView.evaluateJavaScript("{window.localStorage.setItem('mobileConfiguration','"+Utils.getMyTheme()+"')}")
+        }
+    }
+    
+    override func viewDidAppear(_ animated: Bool) {
+//        if (self.isUsingMyWebview() && self.webView.url != nil && !self.webView.url!.absoluteString.contains("nexilis/pages/tab1-main-only") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab3-main-only") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab1-main") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab3-commerce") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab1-video") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab3-main")) || FirstTabViewController.showModal {
+//            ViewController.alwaysHideButton = true
+//            self.hideTabBar()
+//            ThirdTabViewController.atFirstPage = false
+//        } else {
+            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
+                var viewController = UIApplication.shared.windows.first!.rootViewController
+                if !(viewController is ViewController) {
+                    viewController = self.parent
+                }
+                if ViewController.middleButton.isHidden {
+                    ViewController.isExpandButton = false
+                    if let viewController = viewController as? ViewController {
+                        if viewController.tabBar.isHidden {
+                            viewController.tabBar.isHidden = false
+                            ViewController.middleButton.isHidden = false
+                            ViewController.alwaysHideButton = false
+                        }
+                    }
+                } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
+                    DispatchQueue.main.async {
+                        if let viewController = viewController as? ViewController {
+                            if viewController.tabBar.isHidden {
+                                viewController.tabBar.isHidden = false
+                                ViewController.alwaysHideButton = false
+                            }
+                        }
+                    }
+                }
+            })
+//        }
+    }
+    
+    @objc func onShowAC(notification: NSNotification) {
+        self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+        view.endEditing(true)
+        resignFirstResponder()
+    }
+    
+    @objc func onRefreshWebView(notification: NSNotification) {
+        FirstTabViewController.forceRefresh = true
+    }
+    
+    override func viewWillDisappear(_ animated: Bool) {
+        if self.webView.scrollView.contentOffset.y < 0 { // Move tableView to top
+            self.webView.scrollView.setContentOffset(CGPoint.zero, animated: true)
+        }
+        self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+        self.webView.evaluateJavaScript("hideAddToCart();")
+    }
+    
+    func scrollViewDidScroll(_ scrollView: UIScrollView) {
+        if (self.lastContentOffset > scrollView.contentOffset.y && scrollView.contentOffset.y < (scrollView.contentSize.height - scrollView.frame.size.height)) {
+            showTabBar();
+        }
+        else if (self.lastContentOffset != 0 && self.lastContentOffset < scrollView.contentOffset.y && self.lastContentOffset >= 0) {
+            hideTabBar();
+        }
+        self.lastContentOffset = scrollView.contentOffset.y
+        self.collapseDocked()
+    }
+    
+    @objc func collapseDocked() {
+        if ViewController.isExpandButton {
+            ViewController.expandButton()
+        }
+    }
+
+    @objc func reloadWebView(_ sender: UIRefreshControl) {
+        webView.reload()
+        sender.endRefreshing()
+    }
+    
+    func hideTabBar() {
+        var viewController = UIApplication.shared.windows.first!.rootViewController
+        if !(viewController is ViewController) {
+            viewController = self.parent
+        }
+        if ViewController.middleButton.isDescendant(of: viewController!.view) {
+            DispatchQueue.main.async {
+                if ViewController.isExpandButton {
+                    ViewController.expandButton()
+                }
+                ViewController.hideDockedButton()
+                if let viewController = viewController as? ViewController {
+                    viewController.tabBar.isHidden = true
+                }
+                ViewController.removeMiddleButton()
+            }
+        } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
+            DispatchQueue.main.async {
+                if let viewController = viewController as? ViewController {
+                    if !viewController.tabBar.isHidden {
+                        viewController.tabBar.isHidden = true
+                    }
+                }
+            }
+        }
+    }
+
+    func showTabBar() {
+        if(ViewController.alwaysHideButton){
+            return
+        }
+        var viewController = UIApplication.shared.windows.first!.rootViewController
+        if !(viewController is ViewController) {
+            viewController = self.parent
+        }
+        if ViewController.middleButton.isHidden {
+            if let viewController = viewController as? ViewController {
+                viewController.tabBar.isHidden = false
+                ViewController.middleButton.isHidden = false
+            }
+        } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
+            DispatchQueue.main.async {
+                if let viewController = viewController as? ViewController {
+                    if viewController.tabBar.isHidden {
+                        viewController.tabBar.isHidden = false
+                    }
+                }
+            }
+        }
+    }
+
+    func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
+        scrollView.pinchGestureRecognizer?.isEnabled = false
+    }
+
+    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
+        if message.name == "checkProfile" {
+            guard let dict = message.body as? [String: AnyObject],
+                  let param1 = dict["param1"] as? String,
+                  let param2 = dict["param2"] as? String else {
+                return
+            }
+            if ViewController.checkIsChangePerson() {
+                if param2 == "like" {
+                    self.webView.evaluateJavaScript("likeProduct('\(param1)',1,true);")
+                } else if param2 == "comment" {
+                    self.webView.evaluateJavaScript("openComment('\(param1.split(separator: "|")[0])',\(param1.split(separator: "|")[1]),true);")
+                } else if param2 == "report_user" {
+                    self.webView.evaluateJavaScript("reportUser('\(param1)',true);")
+                } else if param2 == "report_content" {
+                    self.webView.evaluateJavaScript("reportContent('\(param1.split(separator: "|")[0])','\(param1.split(separator: "|")[1])',true);")
+                } else if param2 == "block_user" {
+                    self.webView.evaluateJavaScript("blockUser('\(param1)',true);")
+                } else if param2 == "follow_user" {
+                    self.webView.evaluateJavaScript("followUser('\(param1.split(separator: "|")[0])',\(param1.split(separator: "|")[1]),true);")
+                } else if param2 == "homepage" || param2 == "gif" {
+                    self.webView.evaluateJavaScript("window.location.href = '\(param1)';")
+                } else if param2 == "block_content" {
+                    self.webView.evaluateJavaScript("blockContent('\(param1)',true);")
+                } else {
+                    self.webView.evaluateJavaScript("openNewPost(true);")
+                }
+            } else {
+                self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+            }
+        } else if message.name == "setIsProductModalOpen" {
+            guard let dict = message.body as? [String: AnyObject],
+                  let param1 = dict["param1"] as? Bool else {
+                return
+            }
+            if param1 {
+                if self.webView.scrollView.contentOffset.y < 0 { // Move tableView to top
+                    self.webView.scrollView.setContentOffset(CGPoint.zero, animated: true)
+                }
+            }
+            FirstTabViewController.showModal = param1
+        } else if message.name == "toggleVoiceSearch" {
+            if !isAllowSpeech {
+                setupSpeech()
+            } else {
+                runVoice()
+            }
+        } else if message.name == "blockUser" {
+            guard let dict = message.body as? [String: AnyObject],
+                  let param1 = dict["param1"] as? String,
+                  let param2 = dict["param2"] as? Bool else {
+                return
+            }
+            if param2 {
+                DispatchQueue.global().async {
+                    if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getBlock(l_pin: param1)) {
+                        if response.isOk() {
+                            DispatchQueue.main.async {
+                                Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                                    _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
+                                        "ex_block" : "1"
+                                    ], _where: "f_pin = '\(param1)'")
+                                })
+                            }
+                        }
+                    }
+                }
+            } else {
+                DispatchQueue.global().async {
+                    if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getUnBlock(l_pin: param1)) {
+                        if response.isOk() {
+                            DispatchQueue.main.async {
+                                Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                                    _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
+                                        "ex_block" : "0"
+                                    ], _where: "f_pin = '\(param1)'")
+                                })
+                            }
+                        }
+                    }
+                }
+            }
+        } else if message.name == "showAlert" {
+            guard let dict = message.body as? [String: AnyObject],
+                  let param1 = dict["param1"] as? String else {
+                return
+            }
+            showToast(message: param1, controller: self.tabBarController!)
+        } else if message.name == "blockUser" {
+            guard let dict = message.body as? [String: AnyObject],
+                  let param1 = dict["param1"] as? String,
+                  let param2 = dict["param2"] as? Bool else {
+                return
+            }
+            if param2 {
+                DispatchQueue.global().async {
+                    if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getBlock(l_pin: param1)) {
+                        if response.isOk() {
+                            DispatchQueue.main.async {
+                                Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                                    _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
+                                        "ex_block" : "1"
+                                    ], _where: "f_pin = '\(param1)'")
+                                })
+                            }
+                        }
+                    }
+                }
+            } else {
+                DispatchQueue.global().async {
+                    if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getUnBlock(l_pin: param1)) {
+                        if response.isOk() {
+                            DispatchQueue.main.async {
+                                Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                                    _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
+                                        "ex_block" : "0"
+                                    ], _where: "f_pin = '\(param1)'")
+                                })
+                            }
+                        }
+                    }
+                }
+            }
+        } else if message.name == "tabShowHide" {
+            guard let dict = message.body as? [String: AnyObject],
+                  let param1 = dict["param1"] as? Bool else {
+                return
+            }
+            if param1 {
+                ViewController.alwaysHideButton = false
+                showTabBar()
+            } else {
+                if self.viewIfLoaded?.window != nil {
+                    ViewController.alwaysHideButton = true
+                    hideTabBar()
+                }
+            }
+        }
+    }
+    
+    func setupSpeech() {
+
+        self.speechRecognizer?.delegate = self
+
+        SFSpeechRecognizer.requestAuthorization { (authStatus) in
+
+            var isButtonEnabled = false
+
+            switch authStatus {
+            case .authorized:
+                isButtonEnabled = true
+
+            case .denied:
+                isButtonEnabled = false
+                //print("User denied access to speech recognition")
+
+            case .restricted:
+                isButtonEnabled = false
+                //print("Speech recognition restricted on this device")
+
+            case .notDetermined:
+                isButtonEnabled = false
+                //print("Speech recognition not yet authorized")
+            @unknown default:
+                isButtonEnabled = false
+            }
+
+            OperationQueue.main.addOperation() {
+                self.isAllowSpeech = isButtonEnabled
+                if isButtonEnabled {
+                    UserDefaults.standard.set(isButtonEnabled, forKey: "allowSpeech")
+                    self.runVoice()
+                }
+            }
+        }
+    }
+    
+    func runVoice() {
+        if !audioEngine.isRunning {
+            alertController = LibAlertController(title: "Start Recording".localized(), message: "Say something, I'm listening!".localized(), preferredStyle: .alert)
+            self.present(alertController, animated: true)
+            self.webView.evaluateJavaScript("toggleVoiceButton(true)")
+            self.startRecording()
+        }
+    }
+    
+    func startRecording() {
+
+        // Clear all previous session data and cancel task
+        if recognitionTask != nil {
+            recognitionTask?.cancel()
+            recognitionTask = nil
+        }
+
+        // Create instance of audio session to record voice
+        let audioSession = AVAudioSession.sharedInstance()
+        do {
+            try audioSession.setCategory(AVAudioSession.Category.record, mode: .default, options: [])
+            try audioSession.setMode(AVAudioSession.Mode.measurement)
+            try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
+        } catch {
+            //print("audioSession properties weren't set because of an error.")
+        }
+
+        self.recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
+
+        let inputNode = audioEngine.inputNode
+
+        guard let recognitionRequest = recognitionRequest else {
+            fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object")
+        }
+
+        recognitionRequest.shouldReportPartialResults = true
+
+        self.recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in
+
+            var isFinal = false
+            var text = ""
+
+            if result != nil {
+                text = result?.bestTranscription.formattedString ?? ""
+                isFinal = (result?.isFinal)!
+                self.alertController.dismiss(animated: true)
+                self.audioEngine.stop()
+                self.recognitionRequest?.endAudio()
+            } else {
+                self.alertController.dismiss(animated: true)
+            }
+
+            if error != nil || isFinal {
+                if error == nil {
+                    self.webView.evaluateJavaScript("toggleVoiceButton(false)")
+                    self.webView.evaluateJavaScript("submitVoiceSearch('\(text)')")
+                } else {
+                    self.audioEngine.stop()
+                    self.recognitionRequest?.endAudio()
+                }
+                inputNode.removeTap(onBus: 0)
+
+                self.recognitionRequest = nil
+                self.recognitionTask = nil
+
+                self.isAllowSpeech = true
+            }
+        })
+
+        let recordingFormat = inputNode.outputFormat(forBus: 0)
+        inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
+            self.recognitionRequest?.append(buffer)
+        }
+
+        self.audioEngine.prepare()
+
+        do {
+            try self.audioEngine.start()
+        } catch {
+            //print("audioEngine couldn't start because of an error.")
+        }
+    }
+    
+    func isUsingMyWebview() -> Bool{
+        return PrefsUtil.getURLFirstTab() == "0" || PrefsUtil.getURLFirstTab() == "1" || PrefsUtil.getURLFirstTab() == "2" || PrefsUtil.getURLFirstTab() == "3" || PrefsUtil.getURLFirstTab() == "4"
+    }
+
+}
+
+extension FirstTabViewController: SFSpeechRecognizerDelegate {
+
+    func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
+        if available {
+            self.isAllowSpeech = true
+        } else {
+            self.isAllowSpeech = false
+        }
+    }
+}
+
+extension FirstTabViewController: WKUIDelegate, WKNavigationDelegate {
+    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
+        if self.viewIfLoaded?.window != nil {
+          if let urlStr = navigationAction.request.url?.absoluteString {
+              //print("url: \(urlStr)")
+              collapseDocked()
+              if urlStr.contains("nexilis/pages/tab1-main-only") || urlStr.contains("nexilis/pages/tab3-main-only") || urlStr.contains("nexilis/pages/tab1-main") || urlStr.contains("nexilis/pages/tab3-commerce") || urlStr.contains("nexilis/pages/tab1-video") || urlStr.contains("nexilis/pages/tab3-main") {
+                  ViewController.alwaysHideButton = false
+                  showTabBar()
+                  FirstTabViewController.atFirstPage = true
+              }
+    //                  else if isUsingMyWebview() {
+    //                      ViewController.alwaysHideButton = true
+    //                      hideTabBar()
+    //                      FirstTabViewController.atFirstPage = false
+    //                  }
+          }
+        }
+        decisionHandler(.allow)
+    }
+    func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
+        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
+            let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
+            completionHandler(.useCredential, credential)
+        }
+        else {
+            completionHandler(.cancelAuthenticationChallenge, nil)
+        }
+    }
+}

+ 1287 - 0
AppBuilder/AppBuilder/FourthTabViewController.swift

@@ -0,0 +1,1287 @@
+//
+//  SettingTableViewController.swift
+//  Qmera
+//
+//  Created by Yayan Dwi on 16/09/21.
+//
+
+import UIKit
+import NotificationBannerSwift
+import nuSDKService
+import NexilisLite
+import Photos
+
+public class FourthTabViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIScrollViewDelegate, UIGestureRecognizerDelegate {
+    
+    var language: [[String: String]] = [["Indonesia": "id"],["English": "en"]]
+    var alert: UIAlertController?
+    var textFields = [UITextField]()
+    
+    var switchVibrateMode = UISwitch()
+    var switchSaveToGallery = UISwitch()
+    var switchAutoDownload = UISwitch()
+    
+    @IBOutlet weak var tableView: UITableView!
+    @IBOutlet weak var backgroundImage: UIImageView!
+    
+    var notInTab = false
+    
+    public override func viewDidLoad() {
+        super.viewDidLoad()
+        
+        self.view.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .black : .white
+        self.navigationController?.navigationBar.topItem?.backButtonTitle = ""
+        
+        tableView.delegate = self
+        tableView.dataSource = self
+        tableView.layoutMargins = .init(top: 0, left: 0, bottom: 0, right: 0)
+//        tableView.separatorColor = .gray
+        tableView.separatorStyle = .none
+        
+        if PrefsUtil.getCpaasMode() == PrefsUtil.CPAAS_MODE_DOCKED {
+            tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 80, right: 0)
+        }
+        
+        switchVibrateMode.tintColor = .gray
+        switchSaveToGallery.tintColor = .gray
+        switchAutoDownload.tintColor = .gray
+        switchVibrateMode.onTintColor = .mainColor
+        switchSaveToGallery.onTintColor = .mainColor
+        switchAutoDownload.onTintColor = .mainColor
+        let vibrateMode = UserDefaults.standard.bool(forKey: "vibrateMode")
+        let saveGallery = UserDefaults.standard.bool(forKey: "saveToGallery")
+        let autoDownload = UserDefaults.standard.bool(forKey: "autoDownload")
+        if vibrateMode {
+            switchVibrateMode.setOn(true, animated: false)
+        }
+        if saveGallery {
+            switchSaveToGallery.setOn(true, animated: false)
+        }
+        if autoDownload {
+            switchAutoDownload.setOn(true, animated: false)
+        }
+        switchVibrateMode.addTarget(self, action: #selector(vibrateModeSwitch), for: .valueChanged)
+        switchSaveToGallery.addTarget(self, action: #selector(saveToGallerySwitch), for: .valueChanged)
+        switchAutoDownload.addTarget(self, action: #selector(autoDownloadSwitch), for: .valueChanged)
+        
+        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(collapseDocked))
+        tapGesture.cancelsTouchesInView = false
+        tapGesture.delegate = self
+        self.view.addGestureRecognizer(tapGesture)
+        
+//        navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(didTapCancel))
+    }
+    
+    @objc func collapseDocked() {
+        if ViewController.isExpandButton {
+            ViewController.expandButton()
+        }
+    }
+
+    public override func viewWillDisappear(_ animated: Bool) {
+        if ViewController.isExpandButton {
+            ViewController.expandButton()
+        }
+    }
+    
+    public override func viewDidAppear(_ animated: Bool) {
+        self.navigationController?.navigationBar.topItem?.title = "Settings".localized()
+        self.navigationController?.navigationBar.setNeedsLayout()
+        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
+            var viewController = UIApplication.shared.windows.first!.rootViewController
+            if !(viewController is ViewController) {
+                viewController = self.parent
+            }
+            if ViewController.middleButton.isHidden {
+                ViewController.isExpandButton = false
+                if let viewController = viewController as? ViewController {
+                    if viewController.tabBar.isHidden {
+                        viewController.tabBar.isHidden = false
+                        ViewController.alwaysHideButton = false
+                        ViewController.middleButton.isHidden = false
+                    }
+                }
+            } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
+                DispatchQueue.main.async {
+                    if let viewController = viewController as? ViewController {
+                        if viewController.tabBar.isHidden {
+                            viewController.tabBar.isHidden = false
+                            ViewController.alwaysHideButton = false
+                        }
+                    }
+                }
+            }
+        })
+    }
+    
+    @objc func vibrateModeSwitch() {
+        UserDefaults.standard.set(switchVibrateMode.isOn, forKey: "vibrateMode")
+    }
+    
+    @objc func saveToGallerySwitch() {
+        if switchSaveToGallery.isOn {
+            PHPhotoLibrary.requestAuthorization({status in
+                DispatchQueue.main.async {
+                    if status == .authorized {
+                        UserDefaults.standard.set(self.switchSaveToGallery.isOn, forKey: "saveToGallery")
+                    } else {
+                        self.switchSaveToGallery.setOn(false, animated: true)
+                    }
+                }
+            })
+        } else {
+            UserDefaults.standard.set(self.switchSaveToGallery.isOn, forKey: "saveToGallery")
+        }
+    }
+    
+    @objc func autoDownloadSwitch() {
+        UserDefaults.standard.set(switchAutoDownload.isOn, forKey: "autoDownload")
+    }
+    
+    func makeMenu(imageSignIn: String = ""){
+        let isChangeProfile = Utils.getSetProfile()
+        Database.shared.database?.inTransaction({ fmdb, rollback in
+            let idMe = UserDefaults.standard.string(forKey: "me") as String?
+            if let cursorUser = Database.shared.getRecords(fmdb: fmdb, query: "SELECT user_type, image_id, official_account FROM BUDDY where f_pin='\(idMe!)'"), cursorUser.next() {
+                if (User.isInternal(userType: cursorUser.string(forColumnIndex: 0) ?? "") && User.isAdmin(fmdb: fmdb)) || User.isOfficial(official_account: cursorUser.string(forColumnIndex: 2) ?? "") || User.isOfficial(official_account: cursorUser.string(forColumnIndex: 2) ?? "") {
+                    Item.menus["Personal"] = [
+                        Item(icon: UIImage(systemName: "person"), title: "Personal Information".localized()),
+                        Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
+                        Item(icon: UIImage(systemName: "person.crop.rectangle"), title: "Change Admin / Internal Password".localized()),
+                        Item(icon: UIImage(systemName: "laptopcomputer.and.iphone"), title: "Sign-In to Web".localized()),
+                        Item(icon: UIImage(named: "ic_internal", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, title: "Set Internal Account".localized()),
+                        Item(icon: UIImage(named: "pb_call_center", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, title: "Set CS Account".localized()),
+                    ]
+                } else if User.isInternal(userType: cursorUser.string(forColumnIndex: 0) ?? "") || User.isCallCenter(userType: cursorUser.string(forColumnIndex: 0) ?? "") || User.isVerified(official_account: cursorUser.string(forColumnIndex: 2) ?? "") {
+                    Item.menus["Personal"] = [
+                        Item(icon: UIImage(systemName: "person"), title: "Personal Information".localized()),
+                        Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
+                        Item(icon: UIImage(systemName: "laptopcomputer.and.iphone"), title: "Sign-In to Web".localized()),
+                    ]
+                } else {
+                    Item.menus["Personal"] = [
+                        Item(icon: UIImage(systemName: "person"), title: "Personal Information".localized()),
+                            Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
+                        Item(icon: UIImage(systemName: "person.badge.key"), title: "Access Admin / Internal Features".localized()),
+                    ]
+                }
+                if !isChangeProfile {
+                    Item.menus["Personal"]?.append(Item(icon: UIImage(systemName: "arrow.up.and.person.rectangle.portrait"), title: "Sign-Up/Sign-In".localized()))
+                } else if isChangeProfile {
+                    if Nexilis.checkingAccess(key: "backup_restore") {
+                        Item.menus["Personal"]?.append(Item(icon: UIImage(systemName: "arrow.clockwise.icloud"), title: "Backup & Restore".localized()))
+                    }
+                    if Utils.getLimitValidTrans() == "1" {
+                        Item.menus["Personal"]?.insert(Item(icon: UIImage(systemName: "lessthan.circle"), title: "Validation Transaction Limit".localized()), at: 1)
+                    }
+                }
+                let image = cursorUser.string(forColumnIndex: 1)
+                if image != nil {
+                    if !image!.isEmpty {
+                        do {
+                            let documentDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
+                            let file = documentDir.appendingPathComponent(image!)
+                            if FileManager().fileExists(atPath: file.path) {
+                                let image = UIImage(contentsOfFile: file.path)
+                                Item.menus["Personal"]?[0].icon = image?.circleMasked
+                                if !imageSignIn.isEmpty {
+                                    var dataImage: [AnyHashable : Any] = [:]
+                                    dataImage["name"] = imageSignIn
+                                    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "imageFBUpdate"), object: nil, userInfo: dataImage)
+                                }
+                            } else {
+                                Download().start(forKey: image!) { (name, progress) in
+                                    guard progress == 100 else {
+                                        return
+                                    }
+
+                                    DispatchQueue.main.async {
+                                        let image = UIImage(contentsOfFile: file.path)
+                                        Item.menus["Personal"]?[0].icon = image?.circleMasked
+                                        self.tableView.reloadData()
+                                        if !imageSignIn.isEmpty {
+                                            var dataImage: [AnyHashable : Any] = [:]
+                                            dataImage["name"] = imageSignIn
+                                            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "imageFBUpdate"), object: nil, userInfo: dataImage)
+                                        }
+                                    }
+                                }
+                            }
+                        } catch {}
+                    }
+                }
+                cursorUser.close()
+            } else {
+                Item.menus["Personal"] = [
+                    Item(icon: UIImage(systemName: "person"), title: "Personal Information".localized()),
+                        Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
+                    Item(icon: UIImage(systemName: "person.badge.key"), title: "Access Admin / Internal Features".localized()),
+                ]
+                if Nexilis.showButtonFB {
+                    Item.menus["Personal"]?.append(Item(icon: UIImage(systemName: "gearshape.circle"), title: "Configure Floating Button".localized()))
+                }
+                Item.menus["Personal"]?.append(Item(icon: UIImage(systemName: "arrow.up.and.person.rectangle.portrait"), title: "Sign-Up/Sign-In".localized()))
+                if !imageSignIn.isEmpty {
+                    do {
+                        let documentDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
+                        let file = documentDir.appendingPathComponent(imageSignIn)
+                        if FileManager().fileExists(atPath: file.path) {
+                            let image = UIImage(contentsOfFile: file.path)
+                            Item.menus["Personal"]?[0].icon = image?.circleMasked
+                            var dataImage: [AnyHashable : Any] = [:]
+                            dataImage["name"] = imageSignIn
+                            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "imageFBUpdate"), object: nil, userInfo: dataImage)
+                        } else {
+                            Download().start(forKey: imageSignIn) { (name, progress) in
+                                guard progress == 100 else {
+                                    return
+                                }
+                                DispatchQueue.main.async {
+                                    let image = UIImage(contentsOfFile: file.path)
+                                    Item.menus["Personal"]?[0].icon = image?.circleMasked
+                                    self.tableView.reloadData()
+                                    var dataImage: [AnyHashable : Any] = [:]
+                                    dataImage["name"] = imageSignIn
+                                    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "imageFBUpdate"), object: nil, userInfo: dataImage)
+                                }
+                            }
+                        }
+                    } catch {}
+                }
+            }
+        })
+        
+        Item.menus["Config"] = [
+            Item(icon: UIImage(systemName: "iphone"), title: "Create Your Own App".localized()),
+            Item(icon: UIImage(systemName: "gearshape.circle"), title: "Configure Floating Button".localized())
+        ]
+        if !isChangeProfile || Utils.getEnableMobileBuilder() != "1" {
+            if Item.menus["Config"]!.count > 1 {
+                Item.menus["Config"]!.remove(at: 0)
+            } else {
+                Item.menus["Config"]!.removeAll()
+            }
+        }
+        if !Nexilis.showButtonFB {
+            if Item.menus["Config"]!.count > 1 {
+                Item.menus["Config"]!.remove(at: 1)
+            } else {
+                Item.menus["Config"]!.removeAll()
+            }
+        }
+        if Utils.getIsLoadThemeFromOther() {
+            Item.menus["Config"]?.insert(Item(icon: UIImage(systemName: "iphone"), title: "Back to Company App".localized()), at: 1)
+        }
+        
+        Item.menus["Call"] = [
+            Item(icon: UIImage(systemName: "message"), title: "Notification Message(s)".localized()),
+            Item(icon: UIImage(systemName: "message"), title: "Notification Message(s) Group".localized()),
+            Item(icon: UIImage(systemName: "iphone.homebutton.radiowaves.left.and.right"), title: "Vibrate Mode".localized()),
+            Item(icon: UIImage(systemName: "photo.on.rectangle.angled"), title: "Save to Gallery".localized()),
+            Item(icon: UIImage(systemName: "arrow.down.square"), title: "Auto Download".localized()),
+        ]
+        Item.menus["Version"] = [
+            Item(icon: UIImage(systemName: "gear"), title: "Version".localized()),
+            Item(icon: UIImage(named: "pb_powered_button", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), title: "Powered by Nexilis".localized()),
+        ]
+        if isChangeProfile {
+            if Nexilis.checkingAccess(key: "logout"){
+                Item.menus["Version"]?.insert(Item(icon: UIImage(systemName: "rectangle.portrait.and.arrow.right"), title: "Sign-Out".localized()), at: 0)
+            }
+        }
+    }
+    
+    override public func viewWillAppear(_ animated: Bool) {
+//        self.navigationController?.navigationBar.topItem?.title = ""
+        self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: self.traitCollection.userInterfaceStyle == .dark ? .white : UIColor.black]
+        let attributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: self.traitCollection.userInterfaceStyle == .dark ? .white : UIColor.black, NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 16)]
+        let navBarAppearance = UINavigationBarAppearance()
+        navBarAppearance.configureWithTransparentBackground()
+        navBarAppearance.titleTextAttributes = attributes
+        navigationController?.navigationBar.standardAppearance = navBarAppearance
+        navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
+        let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: self.traitCollection.userInterfaceStyle == .dark ? .white : UIColor.black, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
+        UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
+        navigationController?.navigationBar.backgroundColor = .clear
+        navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
+        navigationController?.navigationBar.shadowImage = UIImage()
+        navigationController?.navigationBar.isTranslucent = true
+        navigationController?.setNavigationBarHidden(false, animated: false)
+        navigationController?.navigationBar.overrideUserInterfaceStyle = self.traitCollection.userInterfaceStyle == .dark ? .dark : .light
+        navigationController?.navigationBar.barStyle = .default
+        navigationController?.navigationBar.tintColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
+        tabBarController?.navigationItem.leftBarButtonItem = nil
+        tabBarController?.navigationItem.searchController = nil
+        checkBurgerMode()
+        backgroundImage.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .black : .white
+        backgroundImage.image = nil
+        DispatchQueue.global().async {
+            DispatchQueue.main.async {
+                let listBg = PrefsUtil.getBackgroundLight().isEmpty && PrefsUtil.getBackgroundDark().isEmpty ? PrefsUtil.getBackground() :
+                                    self.traitCollection.userInterfaceStyle == .dark ? PrefsUtil.getBackgroundDark() : PrefsUtil.getBackgroundLight()
+                if listBg.isEmpty {
+                   return
+                }
+                var bgChoosen = ""
+                let arrayBg = listBg.split(separator: ",")
+                bgChoosen = String(arrayBg[Int.random(in: 0..<arrayBg.count)])
+                let urlString = PrefsUtil.getURLBase() + "get_file_from_path?img=" + bgChoosen
+                if let cachedImage = ImageCache.shared.image(forKey: urlString) {
+                    DispatchQueue.main.async() { [self] in
+                        backgroundImage.image = cachedImage
+                    }
+                    return
+                }
+                Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
+                    guard let data = data, error == nil else { return }
+                    // always update the UI from the main thread
+                    DispatchQueue.main.async() { [self] in
+                        if UIImage(data: data) != nil {
+                            backgroundImage.image = UIImage(data: data)!
+                            ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
+                        }
+                    }
+                }
+            }
+        }
+        makeMenu()
+        tableView.reloadData()
+    }
+    
+    // MARK: - Table view data source
+    
+    func checkBurgerMode() {
+        let cpaasMode = PrefsUtil.getCpaasMode()
+        let isBurger = cpaasMode == PrefsUtil.CPAAS_MODE_BURGER
+        if isBurger {
+            var childrenMenu: [UIAction] = []
+            if !Utils.getCustomButtons().isEmpty {
+                let customButtons = Utils.getCustomButtons().components(separatedBy: ",")
+                for i in 0..<customButtons.count {
+                    let package_id = customButtons[i]
+                    var app_id = ""
+                    var indexTap = 0
+                    if package_id.contains("_fb"){
+                        let listSplit = package_id.split(separator: "_", maxSplits: 1)
+                        let numIdx = listSplit[listSplit.firstIndex(where: { $0.contains("fb") }) ?? 0]
+                        indexTap = Int(String(numIdx).substring(from: 2, to: numIdx.count))!
+                        if listSplit.count == 2 {
+                            app_id = String(listSplit[1])
+                        }
+                    }
+                    var nameButton = ""
+                    switch (indexTap) {
+                    case Nexilis.IDX_ADDFRIEND :
+                        nameButton = "Add Friend".localized()
+                    case Nexilis.IDX_BROADCAST_FORM :
+                        nameButton = "Broadcast Form".localized()
+                    case Nexilis.IDX_CALL :
+                        nameButton = "Call".localized()
+                    case Nexilis.IDX_CALL_AUDIO :
+                        nameButton = "Call Audio".localized()
+                    case Nexilis.IDX_CALL_VIDEO :
+                        nameButton = "Call Video".localized()
+                    case Nexilis.IDX_CC :
+                        nameButton = "Contact Center".localized()
+                    case Nexilis.IDX_CC_STREAM :
+                        nameButton = "Contact Center Streaming".localized()
+                    case Nexilis.IDX_CHAT :
+                        nameButton = "Chat".localized()
+                    case Nexilis.IDX_CONFERENCE_ROOM_FORM :
+                        nameButton = "Video Conference Room".localized()
+                    case Nexilis.IDX_CREATE_GROUP :
+                        nameButton = "Create Group".localized()
+                    case Nexilis.IDX_CONVERSATION :
+                        nameButton = "Conversation".localized()
+                    case Nexilis.IDX_EMAIL_CONFIGURATION :
+                        nameButton = "Email Configuration".localized()
+                    case Nexilis.IDX_FAVORITEMESSAGE :
+                        nameButton = "Favorite Message".localized()
+                    case Nexilis.IDX_POST :
+                        nameButton = "New post".localized()
+                    case Nexilis.IDX_QUEUE_SYSTEM :
+                        nameButton = "Custom URL".localized()
+                    case Nexilis.IDX_NOTIF_CENTER :
+                        nameButton = "Notification Center".localized()
+                    case Nexilis.IDX_SCREENSHARING :
+                        nameButton = "Screen Sharing".localized()
+                    case Nexilis.IDX_STREAM :
+                        nameButton = "Live Streaming".localized()
+                    case Nexilis.IDX_WHITEBOARD :
+                        nameButton = "Whiteboard".localized()
+                    case Nexilis.IDX_SELF_ACT :
+                        nameButton = "Custom Action".localized()
+                    case Nexilis.IDX_SOCIAL_COMMERCE :
+                        nameButton = "Social Commerce".localized()
+                    case Nexilis.IDX_NEWS :
+                        nameButton = "News".localized()
+                    default :
+                        nameButton = ""
+                    }
+                    childrenMenu.append(UIAction(title: nameButton, handler: {(_) in
+                        Nexilis.buttonClicked(index: indexTap, id: app_id)
+                    }))
+                }
+            } else {
+                childrenMenu.append(UIAction(title: "Contact Center".localized(), handler: {(_) in
+                    Nexilis.buttonClicked(index: Nexilis.IDX_CC)
+                }))
+                childrenMenu.append(UIAction(title: "Chat".localized(), handler: {(_) in
+                    Nexilis.buttonClicked(index: Nexilis.IDX_CHAT)
+                }))
+                childrenMenu.append(UIAction(title: "Call".localized(), handler: {(_) in
+                    Nexilis.buttonClicked(index: Nexilis.IDX_CALL)
+                }))
+                childrenMenu.append(UIAction(title: "Live Streaming".localized(), handler: {(_) in
+                    Nexilis.buttonClicked(index: Nexilis.IDX_STREAM)
+                }))
+            }
+            let menu = UIMenu(title: "", children: childrenMenu)
+            let menuButton = UIBarButtonItem(image: self.traitCollection.userInterfaceStyle == .dark ? UIImage(systemName: "ellipsis")?.withTintColor(.white) : UIImage(systemName: "ellipsis"), menu: menu)
+            tabBarController?.navigationItem.rightBarButtonItem = menuButton
+        } else {
+            tabBarController?.navigationItem.rightBarButtonItem = nil
+        }
+    }
+    
+    public func numberOfSections(in tableView: UITableView) -> Int {
+        return Item.sections.count
+    }
+    
+    public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+        return Item.menuFor(section: section).count
+    }
+    
+    public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
+        let isChangeProfile = Utils.getSetProfile()
+        cell.accessoryType = .none
+        cell.indentationLevel = 0
+        var content = cell.defaultContentConfiguration()
+        content.textProperties.font = UIFont.systemFont(ofSize: 14)
+        content.secondaryTextProperties.font = UIFont.systemFont(ofSize: 14)
+        content.secondaryTextProperties.color = .gray
+        content.prefersSideBySideTextAndSecondaryText = true
+        let section = Item.sections[indexPath.section]
+        if let arr = Item.menus[section] {
+            let menu = arr[indexPath.row]
+            content.image = menu.icon
+            content.imageProperties.tintColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
+            content.imageProperties.maximumSize = CGSize(width: 24, height: 24)
+            content.text = menu.title
+            cell.accessoryView = nil
+            switch menu.title {
+            case "Personal Information".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Access Admin / Internal Features".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Sign-In to Web".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Sign-Up/Sign-In".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Configure Floating Button".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Notification Message(s)".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Backup & Restore".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Validation Transaction Limit".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Create Your Own App".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Notification Message(s) Group".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Change Admin / Internal Password".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Change Language".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Set Internal Account".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Set CS Account".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Version".localized():
+                let accessoryButton = UIButton(type: .custom)
+                accessoryButton.setTitle(UIApplication.appVersion, for: .normal)
+                accessoryButton.setTitleColor(self.traitCollection.userInterfaceStyle == .dark ? .white : .black, for: .normal)
+                accessoryButton.titleLabel?.font = .systemFont(ofSize: 18)
+                accessoryButton.contentHorizontalAlignment = .right
+                accessoryButton.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
+                accessoryButton.contentMode = .scaleAspectFit
+                cell.accessoryView = accessoryButton as UIView
+            case "Vibrate Mode".localized():
+                cell.accessoryView = switchVibrateMode
+            case "Save to Gallery".localized():
+                cell.accessoryView = switchSaveToGallery
+            case "Auto Download".localized():
+                cell.accessoryView = switchAutoDownload
+            default:
+                content.secondaryText = nil
+            }
+        }
+        cell.contentConfiguration = content
+        return cell
+    }
+    
+    public func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
+        let footerView = UIView()
+        if section != 3 {
+            footerView.backgroundColor = .clear
+            
+            let lineView = UIView()
+            lineView.backgroundColor = .gray
+            lineView.translatesAutoresizingMaskIntoConstraints = false
+            footerView.addSubview(lineView)
+            
+            NSLayoutConstraint.activate([
+                lineView.leadingAnchor.constraint(equalTo: footerView.leadingAnchor),
+                lineView.trailingAnchor.constraint(equalTo: footerView.trailingAnchor),
+                lineView.heightAnchor.constraint(equalToConstant: 1),
+                lineView.bottomAnchor.constraint(equalTo: footerView.bottomAnchor)
+            ])
+        }
+        return footerView
+    }
+    
+    public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
+        let headerView = UIView()
+        if (section == 2 && Item.menus["Config"]!.count > 0) || section == 3 || (section == 1 && Item.menus["Config"]!.count > 0) {
+            headerView.backgroundColor = .clear
+            
+            let lineView = UIView()
+            lineView.backgroundColor = .gray
+            lineView.translatesAutoresizingMaskIntoConstraints = false
+            headerView.addSubview(lineView)
+            
+            NSLayoutConstraint.activate([
+                lineView.leadingAnchor.constraint(equalTo: headerView.leadingAnchor),
+                lineView.trailingAnchor.constraint(equalTo: headerView.trailingAnchor),
+                lineView.heightAnchor.constraint(equalToConstant: 1),
+                lineView.bottomAnchor.constraint(equalTo: headerView.bottomAnchor)
+            ])
+        }
+        return headerView
+    }
+    
+    public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
+        if section == 2 || section == 3 || section == 1 {
+            return 6
+        }
+        return 1
+    }
+    
+    public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        let item = Item.menuFor(section: indexPath.section)[indexPath.row]
+        if item.title == "Personal Information".localized() {
+            if(ViewController.checkIsChangePerson()){
+                let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "profileView") as! ProfileViewController
+                controller.data = UserDefaults.standard.string(forKey: "me")!
+                controller.flag = .me
+                controller.dismissImage = { image, imageName in
+                    var dataImage: [AnyHashable : Any] = [:]
+                    dataImage["name"] = imageName
+                    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "imageFBUpdate"), object: nil, userInfo: dataImage)
+                    self.makeMenu()
+                    self.tableView.reloadData()
+                }
+                navigationController?.show(controller, sender: nil)
+            }
+        } else if item.title == "Access Admin / Internal Features".localized() || item.title == "Change Admin / Internal Password".localized() {
+            if(ViewController.checkIsChangePerson()){
+                if !CheckConnection.isConnectedToNetwork()  || API.nGetCLXConnState() == 0 {
+                    let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                    imageView.tintColor = .white
+                    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)
+                    banner.show()
+                    return
+                }
+                let alertController = LibAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
+                if(item.title.contains("Change")){
+                    if let action = self.actionChangePassword(for: "admin", title: "Change Admin Password".localized()) {
+                        alertController.addAction(action)
+                    }
+                    if let action = self.actionChangePassword(for: "internal", title: "Change Internal Password".localized()) {
+                        alertController.addAction(action)
+                    }
+                }
+                else {
+                    if let action = self.actionLogin(for: "admin", title: "Access Admin Features".localized()) {
+                        alertController.addAction(action)
+                    }
+                    if let action = self.actionLogin(for: "internal", title: "Access Internal Features".localized()) {
+                        alertController.addAction(action)
+                    }
+                }
+                alertController.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil))
+                self.present(alertController, animated: true)
+            }
+        } else if item.title == "Change Language".localized() {
+            let vc = UIViewController()
+            vc.preferredContentSize = CGSize(width: UIScreen.main.bounds.width - 10, height: 150)
+            let pickerView = UIPickerView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width - 10, height: 150))
+            pickerView.dataSource = self
+            pickerView.delegate = self
+            
+            let lang = UserDefaults.standard.string(forKey: "i18n_language")
+            var index = 1
+            if lang == "id" {
+                index = 0
+            }
+            pickerView.selectRow(index, inComponent: 0, animated: false)
+            
+            vc.view.addSubview(pickerView)
+            pickerView.translatesAutoresizingMaskIntoConstraints = false
+            pickerView.centerXAnchor.constraint(equalTo: vc.view.centerXAnchor).isActive = true
+            pickerView.centerYAnchor.constraint(equalTo: vc.view.centerYAnchor).isActive = true
+            
+            let alert = LibAlertController(title: "Select Language".localized(), message: "", preferredStyle: .actionSheet)
+            
+            alert.setValue(vc, forKey: "contentViewController")
+            alert.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: { (UIAlertAction) in
+            }))
+            
+            alert.addAction(UIAlertAction(title: "Select".localized(), style: .default, handler: { (UIAlertAction) in
+                let selectedIndex = pickerView.selectedRow(inComponent: 0)
+                let lang = self.language[selectedIndex].values.first
+                UserDefaults.standard.set(lang, forKey: "i18n_language")
+                self.navigationController?.navigationBar.topItem?.title = "Settings".localized();
+                self.navigationController?.navigationBar.setNeedsLayout()
+                self.makeMenu()
+                self.tableView.reloadData()
+                FirstTabViewController.forceRefresh = true
+                ThirdTabViewController.forceRefresh = true
+                FirstTabViewController.showModal = false
+                ThirdTabViewController.showModal = false
+            }))
+            self.present(alert, animated: true, completion: nil)
+        } else if item.title == "Sign-In".localized() {
+            let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "changeDevice") as! ChangeDeviceViewController
+            controller.isDismiss = { newThumb in
+                self.makeMenu(imageSignIn: newThumb)
+                self.tableView.reloadData()
+            }
+            navigationController?.show(controller, sender: nil)
+        } else if item.title == "Sign-Up/Sign-In".localized() {
+            let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "signupsignin") as! SignUpSignIn
+            controller.isDismiss = { newThumb in
+                self.makeMenu(imageSignIn: newThumb)
+                self.tableView.reloadData()
+                FirstTabViewController.forceRefresh = true
+                ThirdTabViewController.forceRefresh = true
+                FirstTabViewController.showModal = false
+                ThirdTabViewController.showModal = false
+            }
+            navigationController?.show(controller, sender: nil)
+        } else if item.title == "Sign-Out".localized() {
+            let alert = LibAlertController(title: "Sign-Out".localized(), message: "Are you sure want to logout?".localized(), preferredStyle: .alert)
+            alert.addAction(UIAlertAction(title: "Cancel".localized(), style: UIAlertAction.Style.default, handler: nil))
+            alert.addAction(UIAlertAction(title: "Yes".localized(), style: .destructive, handler: {(_) in
+                var viewController = UIApplication.shared.windows.first!.rootViewController
+                if !(viewController is ViewController) {
+                    viewController = self.parent
+                }
+                if let viewController = viewController as? ViewController {
+                    if !(viewController.selectedViewController is FourthTabViewController) {
+                        viewController.selectedIndex = (viewController.viewControllers?.firstIndex(of: viewController.fourthTab!))!
+                    }
+                }
+                if !CheckConnection.isConnectedToNetwork()  || API.nGetCLXConnState() == 0 {
+                    let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                    imageView.tintColor = .white
+                    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)
+                    banner.show()
+                    return
+                }
+                Nexilis.showLoader()
+                DispatchQueue.global().async {
+                    let apiKey = Nexilis.sAPIKey
+                    var id = Utils.getConnectionID()
+                    if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getSignUpApi(api: apiKey, p_pin: id), timeout: 30 * 1000) {
+                        id = response.getBody(key: CoreMessage_TMessageKey.F_PIN, default_value: "")
+                        if(!id.isEmpty){
+//                            Nexilis.changeUser(f_pin: id)
+                            UserDefaults.standard.setValue(id, forKey: "me")
+                            Utils.setProfile(value: false)
+                            UserDefaults.standard.synchronize()
+                            if Utils.getForceAnonymous() {
+                                self.deleteAllRecordDatabase()
+                                UserDefaults.standard.removeObject(forKey: "device_id")
+                                Nexilis.destroyAll()
+                                _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: id))
+                            }
+                            DispatchQueue.main.async {
+                                Nexilis.hideLoader(completion: {
+                                    let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
+                                    imageView.tintColor = .white
+                                    let banner = FloatingNotificationBanner(title: "Successfully Sign-Out".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)
+                                    banner.show()
+                                    if viewController is UINavigationController {
+                                        viewController = (viewController as! UINavigationController).viewControllers[0]
+                                    }
+                                    if Nexilis.showFB && viewController is ViewController{
+                                        Nexilis.floatingButton.removeFromSuperview()
+                                        Nexilis.floatingButton = FloatingButton()
+                                        Nexilis.addFB(viewController: viewController!, fromMAB: true)
+                                    }
+                                    var dataImage: [AnyHashable : Any] = [:]
+                                    dataImage["name"] = ""
+                                    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "imageFBUpdate"), object: nil, userInfo: dataImage)
+                                    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
+                                    self.makeMenu()
+                                    self.tableView.reloadData()
+                                    FirstTabViewController.forceRefresh = true
+                                    ThirdTabViewController.forceRefresh = true
+                                    FirstTabViewController.showModal = false
+                                    ThirdTabViewController.showModal = false
+                                    
+                                    if !Utils.getForceAnonymous() {
+                                        Nexilis.showForceSignIn()
+                                    }
+                                })
+                            }
+                        } else {
+                            DispatchQueue.main.async {
+                                Nexilis.hideLoader(completion: {
+                                    let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                                    imageView.tintColor = .white
+                                    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)
+                                    banner.show()
+                                })
+                            }
+                        }
+                    } else {
+                        DispatchQueue.main.async {
+                            Nexilis.hideLoader(completion: {
+                                let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                                imageView.tintColor = .white
+                                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)
+                                banner.show()
+                            })
+                        }
+                    }
+                }
+            }))
+            self.present(alert, animated: true, completion: nil)
+        } else if item.title == "Sign-In to Web".localized() {
+            var permissionCheck = -1
+            if AVCaptureDevice.authorizationStatus(for: .video) ==  .authorized {
+                permissionCheck = 1
+            } else if AVCaptureDevice.authorizationStatus(for: .video) ==  .denied {
+                permissionCheck = 0
+            } else {
+                AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) -> Void in
+                    if granted == true {
+                        permissionCheck = 1
+                    } else {
+                        permissionCheck = 0
+                    }
+                })
+            }
+            
+            while permissionCheck == -1 {
+                sleep(1)
+            }
+            
+            if permissionCheck == 0 {
+                let alert = LibAlertController(title: "Attention!".localized(), message: "Please allow camera permission in your settings".localized(), preferredStyle: .alert)
+                alert.addAction(UIAlertAction(title: "OK".localized(), style: UIAlertAction.Style.default, handler: { _ in
+                    if let url = URL(string: UIApplication.openSettingsURLString), UIApplication.shared.canOpenURL(url) {
+                        UIApplication.shared.open(url, options: [:], completionHandler: nil)
+                    }
+                }))
+                if UIApplication.shared.visibleViewController?.navigationController != nil {
+                    UIApplication.shared.visibleViewController?.navigationController?.present(alert, animated: true, completion: nil)
+                } else {
+                    UIApplication.shared.visibleViewController?.present(alert, animated: true, completion: nil)
+                }
+                return
+            }
+            let controller = ScannerViewController()
+            let navigationController = CustomNavigationController(rootViewController: controller)
+            navigationController.navigationBar.tintColor = .white
+            navigationController.navigationBar.barTintColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
+            navigationController.navigationBar.isTranslucent = false
+            let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
+            UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
+            let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
+            navigationController.navigationBar.titleTextAttributes = textAttributes
+            navigationController.navigationBar.overrideUserInterfaceStyle = .dark
+            navigationController.navigationBar.barStyle = .black
+            navigationController.modalPresentationStyle = .custom
+            self.present(navigationController, animated: true)
+        } else if item.title == "Notification Message(s)".localized() || item.title == "Notification Message(s) Group".localized() {
+            let controller = NotificationSound()
+            if item.title != "Notification Message(s)".localized() {
+                controller.isPersonal = false
+            }
+            let navigationController = CustomNavigationController(rootViewController: controller)
+            navigationController.navigationBar.tintColor = .white
+            navigationController.navigationBar.barTintColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
+            navigationController.navigationBar.isTranslucent = false
+            navigationController.navigationBar.overrideUserInterfaceStyle = .dark
+            navigationController.navigationBar.barStyle = .black
+            let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
+            UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
+            let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
+            navigationController.navigationBar.titleTextAttributes = textAttributes
+            self.present(navigationController, animated: true)
+        } else if item.title == "Backup & Restore".localized() {
+            let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "backupRestore") as! BackupRestoreView
+            navigationController?.show(controller, sender: nil)
+        } else if item.title == "Set Internal Account".localized() {
+            let controller = SetInternalCSAccount()
+            navigationController?.show(controller, sender: nil)
+        } else if item.title == "Set CS Account".localized() {
+            let controller = SetInternalCSAccount()
+            controller.isSetCS = true
+            navigationController?.show(controller, sender: nil)
+        } else if item.title == "Configure Floating Button".localized() {
+            let viewConfigureFB = ConfigureFloatingButton()
+            viewConfigureFB.modalTransitionStyle = .crossDissolve
+            viewConfigureFB.modalPresentationStyle = .custom
+            self.present(viewConfigureFB, animated: true)
+        } else if item.title == "Validation Transaction Limit".localized() {
+            let controller = ValidationTransactionLimit()
+            navigationController?.show(controller, sender: nil)
+        } else if item.title == "Create Your Own App".localized() {
+            let controller = BNIBookingWebView()
+            controller.customUrl = PrefsUtil.getURLBase() + "mobile_MAB?f_pin="
+            self.present(controller, animated: true)
+        } else if item.title == "Back to Company App".localized() {
+            let alert = LibAlertController(title: "", message: "Are you sure want to back to company app?".localized(), preferredStyle: .alert)
+            alert.addAction(UIAlertAction(title: "Cancel".localized(), style: UIAlertAction.Style.default, handler: nil))
+            alert.addAction(UIAlertAction(title: "Yes".localized(), style: .destructive, handler: {(_) in
+                if !CheckConnection.isConnectedToNetwork()  || API.nGetCLXConnState() == 0 {
+                    let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                    imageView.tintColor = .white
+                    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)
+                    banner.show()
+                    return
+                }
+                Nexilis.showLoader()
+                DispatchQueue.global().async {
+                    if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.backToSuperApp(), timeout: 30 * 1000) {
+                        DispatchQueue.main.async {
+                            if response.isOk() {
+                                Utils.setMyTheme(value: "")
+                                Utils.setIsLoadThemeFromOther(value: false)
+                                Utils.resetValueSuperApp()
+                                Utils.setValueInitialApp(data: Utils.getPrefTheme())
+                                UIApplication.shared.setAlternateIconName(nil)
+                                Database.shared.database?.inTransaction({ fmdb, rollback in
+                                    _ = Database.shared.deleteRecord(fmdb: fmdb, table: "GROUPZ", _where: "")
+                                    _ = Database.shared.deleteRecord(fmdb: fmdb, table: "GROUPZ_MEMBER", _where: "")
+                                    _ = Database.shared.deleteRecord(fmdb: fmdb, table: "DISCUSSION_FORUM", _where: "")
+                                    _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: User.getMyPin() ?? ""))
+                                })
+                                Nexilis.hideLoader {
+                                    let alert = LibAlertController(title: "Successfully changed".localized(), message: "Please open the app again to see the changes".localized(), preferredStyle: .alert)
+                                    alert.addAction(UIAlertAction(title: "OK".localized(), style: .default, handler: {(_) in
+                                        exit(0)
+                                    }))
+                                    self.present(alert, animated: true, completion: nil)
+                                }
+                            } else if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "10" {
+                                Nexilis.hideLoader(completion: {
+                                    let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                                    imageView.tintColor = .white
+                                    let banner = FloatingNotificationBanner(title: "Failed to back to Company App".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)
+                                    banner.show()
+                                })
+                            } else {
+                                Nexilis.hideLoader(completion: {
+                                    let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                                    imageView.tintColor = .white
+                                    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)
+                                    banner.show()
+                                })
+                            }
+                        }
+                    } else {
+                        DispatchQueue.main.async {
+                            Nexilis.hideLoader(completion: {
+                                let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                                imageView.tintColor = .white
+                                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)
+                                banner.show()
+                            })
+                        }
+                    }
+                }
+            }))
+            self.present(alert, animated: true, completion: nil)
+        }
+    }
+    
+    private func actionLogin(for type: String, title: String) -> UIAlertAction? {
+        return UIAlertAction(title: title, style: .default) { _ in
+            self.alert = LibAlertController(title:"Access Admin Features".localized(), message: nil, preferredStyle: .alert)
+            if type == "internal" {
+                self.alert = LibAlertController(title: "Access Internal Features".localized(), message: nil, preferredStyle: .alert)
+            }
+            self.textFields.removeAll()
+            self.alert?.addTextField{ (texfield) in
+                texfield.placeholder = "Password".localized()
+                texfield.isSecureTextEntry = true
+                texfield.addPadding(.right(40))
+                texfield.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged)
+                
+                let buttonHideUnhide = UIButton()
+                buttonHideUnhide.tag = 0
+                texfield.addSubview(buttonHideUnhide)
+                buttonHideUnhide.anchor(top: texfield.topAnchor, right: texfield.rightAnchor, paddingTop: -7, width: 30, height: 30)
+                buttonHideUnhide.setImage(UIImage(systemName: "eye.slash.fill"), for: .normal)
+                buttonHideUnhide.tintColor = .black
+                buttonHideUnhide.addTarget(self, action: #selector(self.showPassword), for: .touchUpInside)
+            }
+            let submitAction = UIAlertAction(title: "Sign-In".localized(), style: .default, handler: { (action) -> Void in
+                let textField = self.alert?.textFields![0]
+                if !CheckConnection.isConnectedToNetwork()  || API.nGetCLXConnState() == 0 {
+                    let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                    imageView.tintColor = .white
+                    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)
+                    banner.show()
+                    return
+                }
+                Nexilis.showLoader()
+                if type == "admin" {
+                    self.signInAdmin(password: textField!.text!, completion: { result in
+                        if result {
+                            DispatchQueue.main.async {
+                                Nexilis.hideLoader {
+                                    self.makeMenu()
+                                    self.tableView.reloadData()
+                                    let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
+                                    imageView.tintColor = .white
+                                    let banner = FloatingNotificationBanner(title: "Successfully Sign-In Admin".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .success, colors: nil, iconPosition: .center)
+                                    banner.show()
+                                }
+                            }
+                        } else {
+                            DispatchQueue.main.async {
+                                Nexilis.hideLoader {}
+                            }
+                        }
+                    })
+                } else {
+                    self.signInInternal(password: textField!.text!, completion: { result in
+                        if result {
+                            DispatchQueue.main.async {
+                                Nexilis.hideLoader {
+                                    self.makeMenu()
+                                    self.tableView.reloadData()
+                                    let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
+                                    imageView.tintColor = .white
+                                    let banner = FloatingNotificationBanner(title: "Successfully Sign-In Internal Team".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)
+                                    banner.show()
+                                }
+                            }
+                        } else {
+                            DispatchQueue.main.async {
+                                Nexilis.hideLoader {}
+                            }
+                        }
+                    })
+                }
+            })
+            submitAction.isEnabled = false
+            self.alert?.addAction(submitAction)
+            self.alert?.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil))
+            
+            self.present(self.alert!, animated: true, completion: nil)
+        }
+    }
+    
+    private func actionChangePassword(for type: String, title: String) -> UIAlertAction? {
+        return UIAlertAction(title: title, style: .default) { _ in
+            self.alert = LibAlertController(title: "Change Admin Password".localized(), message: nil, preferredStyle: .alert)
+            if type == "internal" {
+                self.alert = LibAlertController(title: "Change Internal Password".localized(), message: nil, preferredStyle: .alert)
+            }
+            self.textFields.removeAll()
+            self.alert?.addTextField{ (texfield) in
+                texfield.placeholder = "Old Password"
+                texfield.isSecureTextEntry = true
+                texfield.addPadding(.right(40))
+                texfield.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged)
+                self.textFields.append(texfield)
+                
+                let buttonHideUnhide = UIButton()
+                buttonHideUnhide.tag = 0
+                texfield.addSubview(buttonHideUnhide)
+                buttonHideUnhide.anchor(top: texfield.topAnchor, right: texfield.rightAnchor, paddingTop: -7, width: 30, height: 30)
+                buttonHideUnhide.setImage(UIImage(systemName: "eye.slash.fill"), for: .normal)
+                buttonHideUnhide.tintColor = .black
+                buttonHideUnhide.addTarget(self, action: #selector(self.showPassword), for: .touchUpInside)
+            }
+            self.alert?.addTextField{ (texfield) in
+                texfield.placeholder = "New Password"
+                texfield.isSecureTextEntry = true
+                texfield.addPadding(.right(40))
+                texfield.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged)
+                self.textFields.append(texfield)
+                
+                let buttonHideUnhide = UIButton()
+                buttonHideUnhide.tag = 1
+                texfield.addSubview(buttonHideUnhide)
+                buttonHideUnhide.anchor(top: texfield.topAnchor, right: texfield.rightAnchor, paddingTop: -7, width: 30, height: 30)
+                buttonHideUnhide.setImage(UIImage(systemName: "eye.slash.fill"), for: .normal)
+                buttonHideUnhide.tintColor = .black
+                buttonHideUnhide.addTarget(self, action: #selector(self.showPassword), for: .touchUpInside)
+            }
+            let submitAction = UIAlertAction(title: "Change Password".localized(), style: .default, handler: { (action) -> Void in
+                let textFieldOld = self.alert?.textFields![0]
+                let textFieldNew = self.alert?.textFields![1]
+                if !CheckConnection.isConnectedToNetwork()  || API.nGetCLXConnState() == 0 {
+                    let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                    imageView.tintColor = .white
+                    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)
+                    banner.show()
+                    return
+                }
+                if type == "admin" {
+                    self.changePasswordAdmin(oldPassword: textFieldOld!.text!, newPassword: textFieldNew!.text!, completion: { result in
+                        if result {
+                            DispatchQueue.main.async {
+                                let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
+                                imageView.tintColor = .white
+                                let banner = FloatingNotificationBanner(title: "Admin password changed successfully".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)
+                                banner.show()
+                            }
+                        }
+                    })
+                } else {
+                    self.changePasswordInternal(oldPassword: textFieldOld!.text!, newPassword: textFieldNew!.text!, completion: { result in
+                        if result {
+                            DispatchQueue.main.async {
+                                let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
+                                imageView.tintColor = .white
+                                let banner = FloatingNotificationBanner(title: "Internal password changed successfully".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)
+                                banner.show()
+                            }
+                        }
+                    })
+                }
+            })
+            submitAction.isEnabled = false
+            self.alert?.addAction(submitAction)
+            self.alert?.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil))
+            
+            self.present(self.alert!, animated: true, completion: nil)
+        }
+    }
+    
+    @objc func showPassword(_ sender:UIButton) {
+        if alert!.textFields![sender.tag].isSecureTextEntry {
+            alert!.textFields![sender.tag].isSecureTextEntry = false
+            let buttonImage = alert!.textFields![sender.tag].subviews[0] as! UIButton
+            buttonImage.setImage(UIImage(systemName: "eye.fill"), for: .normal)
+        } else {
+            alert!.textFields![sender.tag].isSecureTextEntry = true
+            let buttonImage = alert!.textFields![sender.tag].subviews[0] as! UIButton
+            buttonImage.setImage(UIImage(systemName: "eye.slash.fill"), for: .normal)
+        }
+    }
+    
+    @objc func alertTextFieldDidChange(_ sender: UITextField) {
+        if(!textFields.isEmpty){
+            //print("text count 0: \(textFields[0].text!.count)")
+            //print("text count 1: \(textFields[1].text!.count)")
+            alert?.actions[0].isEnabled = textFields[0].text!.count > 0 && textFields[1].text!.count > 0
+        }
+        else {
+            alert?.actions[0].isEnabled = sender.text!.count > 0
+        }
+    }
+    
+    private func signInAdmin(password: String, completion: @escaping (Bool) -> ()) {
+        DispatchQueue.global().async {
+            let idMe = UserDefaults.standard.string(forKey: "me") as String?
+            let p_password = password
+            let md5Hex = p_password
+            var result: Bool = false
+            if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getSignInApiAdmin(p_name: idMe!, p_password: md5Hex)) {
+                if response.isOk() {
+                    result = true
+                }
+                DispatchQueue.main.async {
+                    if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "11" {
+                        let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                        imageView.tintColor = .white
+                        let banner = FloatingNotificationBanner(title: "Username or password does not match".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .top)
+                        banner.show()
+                    } else if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "20" {
+                        let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                        imageView.tintColor = .white
+                        let banner = FloatingNotificationBanner(title: "Invalid password".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .top)
+                        banner.show()
+                    }
+                }
+            } else {
+                DispatchQueue.main.async {
+                    let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                    imageView.tintColor = .white
+                    let banner = FloatingNotificationBanner(title: "Unable to access servers".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .top)
+                    banner.show()
+                }
+            }
+            completion(result)
+        }
+    }
+    
+    private func signInInternal(password: String, completion: @escaping (Bool) -> ()) {
+        DispatchQueue.global().async {
+            let idMe = UserDefaults.standard.string(forKey: "me") as String?
+            let p_password = password
+            let md5Hex = p_password
+            var result: Bool = false
+            if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getSignInApiInternal(p_name: idMe!, p_password: md5Hex)) {
+                if response.isOk() {
+                    result = true
+                }
+                DispatchQueue.main.async {
+                    if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "11" {
+                        let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                        imageView.tintColor = .white
+                        let banner = FloatingNotificationBanner(title: "Username or password does not match".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .top)
+                        banner.show()
+                    } else if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "20" {
+                        let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                        imageView.tintColor = .white
+                        let banner = FloatingNotificationBanner(title: "Invalid password".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .top)
+                        banner.show()
+                    }
+                }
+            } else {
+                DispatchQueue.main.async {
+                    let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                    imageView.tintColor = .white
+                    let banner = FloatingNotificationBanner(title: "Unable to access servers".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .top)
+                    banner.show()
+                }
+            }
+            completion(result)
+        }
+    }
+    
+    private func changePasswordAdmin(oldPassword: String, newPassword: String, completion: @escaping (Bool) -> ()) {
+        DispatchQueue.global().async {
+            let idMe = UserDefaults.standard.string(forKey: "me") as String?
+            let p_password = oldPassword
+            let n_password = newPassword
+            let md5Hex = p_password
+            let md5HexNew = n_password
+            var result: Bool = false
+            if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getChangePasswordAdmin(p_f_pin: idMe!, pwd_en: md5HexNew, pwd_old: md5Hex)) {
+                if response.isOk() {
+                    result = true
+                }
+                DispatchQueue.main.async {
+                    if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "11" {
+                        let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                        imageView.tintColor = .white
+                        let banner = FloatingNotificationBanner(title: "Username or password does not match".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .top)
+                        banner.show()
+                    } else if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "20" {
+                        let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                        imageView.tintColor = .white
+                        let banner = FloatingNotificationBanner(title: "Invalid password".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .top)
+                        banner.show()
+                    }
+                }
+            } else {
+                DispatchQueue.main.async {
+                    let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                    imageView.tintColor = .white
+                    let banner = FloatingNotificationBanner(title: "Unable to access servers".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .top)
+                    banner.show()
+                }
+            }
+            completion(result)
+        }
+    }
+    
+    private func changePasswordInternal(oldPassword: String, newPassword: String, completion: @escaping (Bool) -> ()) {
+        DispatchQueue.global().async {
+            let idMe = UserDefaults.standard.string(forKey: "me") as String?
+            let p_password = oldPassword
+            let n_password = newPassword
+            let md5Hex = p_password
+            let md5HexNew = n_password
+            var result: Bool = false
+            if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getChangePasswordInternal(p_f_pin: idMe!, pwd_en: md5HexNew, pwd_old: md5Hex)) {
+                if response.isOk() {
+                    result = true
+                }
+                DispatchQueue.main.async {
+                    if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "11" {
+                        let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                        imageView.tintColor = .white
+                        let banner = FloatingNotificationBanner(title: "Username or password does not match".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .top)
+                        banner.show()
+                    } else if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "20" {
+                        let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                        imageView.tintColor = .white
+                        let banner = FloatingNotificationBanner(title: "Invalid password".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .top)
+                        banner.show()
+                    }
+                }
+            } else {
+                DispatchQueue.main.async {
+                    let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                    imageView.tintColor = .white
+                    let banner = FloatingNotificationBanner(title: "Unable to access servers".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .top)
+                    banner.show()
+                }
+            }
+            completion(result)
+        }
+    }
+}
+
+// MARK: - Item
+
+struct Item: Hashable {
+    
+    static func == (lhs: Item, rhs: Item) -> Bool {
+        return lhs.title == rhs.title
+    }
+    
+    var icon: UIImage?
+    var title = ""
+    
+    static var sections: [String] {
+        return ["Personal", "Config", "Call", "Version"]
+    }
+    
+    static var menus: [String: [Item]] = [:]
+    
+    static func menuFor(section: Int) -> [Item] {
+        let sec = sections[section]
+        if let arr = menus[sec] {
+            return arr
+        }
+        return []
+    }
+    
+}
+
+extension FourthTabViewController: UIPickerViewDelegate, UIPickerViewDataSource {
+    public func numberOfComponents(in pickerView: UIPickerView) -> Int {
+        return 1
+    }
+    
+    public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
+        return language.count
+    }
+    
+    public func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
+        return 60
+    }
+    
+    public func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
+        let label = UILabel(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width - 10, height: 30))
+        label.text = (language[row]).keys.first
+        label.sizeToFit()
+        return label
+    }
+}

+ 213 - 0
AppBuilder/AppBuilder/Info.plist

@@ -0,0 +1,213 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>BGTaskSchedulerPermittedIdentifiers</key>
+	<array>
+		<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	</array>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
+	<key>CFBundleDisplayName</key>
+	<string>AppBuilder</string>
+    <key>CFBundleIcons</key>
+    <dict>
+        <key>CFBundleAlternateIcons</key>
+        <dict>
+            <key>digisales_icon</key>
+            <dict>
+                <key>CFBundleIconFiles</key>
+                <array>
+                    <string>digisales_icon</string>
+                </array>
+            </dict>
+            <key>nu_icon</key>
+            <dict>
+                <key>CFBundleIconFiles</key>
+                <array>
+                    <string>nu_icon</string>
+                </array>
+            </dict>
+            <key>ikn_icon</key>
+            <dict>
+                <key>CFBundleIconFiles</key>
+                <array>
+                    <string>ikn_icon</string>
+                </array>
+            </dict>
+            <key>diginets_icon</key>
+            <dict>
+                <key>CFBundleIconFiles</key>
+                <array>
+                    <string>diginets_icon</string>
+                </array>
+            </dict>
+            <key>bi_icon</key>
+            <dict>
+                <key>CFBundleIconFiles</key>
+                <array>
+                    <string>bi_icon</string>
+                </array>
+            </dict>
+            <key>nxcook_icon</key>
+            <dict>
+                <key>CFBundleIconFiles</key>
+                <array>
+                    <string>nxcook_icon</string>
+                </array>
+            </dict>
+            <key>nxsport_icon</key>
+            <dict>
+                <key>CFBundleIconFiles</key>
+                <array>
+                    <string>nxsport_icon</string>
+                </array>
+            </dict>
+            <key>bpkh_icon</key>
+            <dict>
+                <key>CFBundleIconFiles</key>
+                <array>
+                    <string>bpkh_icon</string>
+                </array>
+            </dict>
+            <key>disini_icon</key>
+            <dict>
+                <key>CFBundleIconFiles</key>
+                <array>
+                    <string>disini_icon</string>
+                </array>
+            </dict>
+            <key>gudeg_icon</key>
+            <dict>
+                <key>CFBundleIconFiles</key>
+                <array>
+                    <string>gudeg_icon</string>
+                </array>
+            </dict>
+            <key>kmi_icon</key>
+            <dict>
+                <key>CFBundleIconFiles</key>
+                <array>
+                    <string>kmi_icon</string>
+                </array>
+            </dict>
+        </dict>
+    </dict>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
+	<key>CFBundleShortVersionString</key>
+	<string>$(MARKETING_VERSION)</string>
+	<key>CFBundleVersion</key>
+	<string>$(CURRENT_PROJECT_VERSION)</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>NSCameraUsageDescription</key>
+	<string>Video Call, Conference Room, Content Creation and Live Streaming.</string>
+    <key>NSLocationWhenInUseUsageDescription</key>
+    <string>Access Location For Multiple Login.</string>
+    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
+    <string>Access Location For Multiple Login.</string>
+	<key>NSContactsUsageDescription</key>
+	<string>Get File Contact from Local Dictionary for Send Message.</string>
+	<key>NSDocumentsFolderUsageDescription</key>
+	<string>Get File from Local Dictionary for Send Message.</string>
+	<key>NSMicrophoneUsageDescription</key>
+	<string>VoIP Call, Video Call, Conference Room, and Live Streaming.</string>
+	<key>NSMotionUsageDescription</key>
+	<string>Service nuSDK.</string>
+	<key>NSPhotoLibraryAddUsageDescription</key>
+	<string>Get File Photos from Local Dictionary for Send Message and Content Creation.</string>
+	<key>NSPhotoLibraryUsageDescription</key>
+	<string>Get File Photos from Local Dictionary for Send Message and Content Creation.</string>
+	<key>NSSpeechRecognitionUsageDescription</key>
+	<string>Used for speech recognition features.</string>
+    <key>NSAppTransportSecurity</key>
+    <dict>
+    <key>NSAllowsArbitraryLoads</key>
+    <true/>
+    </dict>
+	<key>NSUserActivityTypes</key>
+	<array>
+		<string>INSendMessageIntent</string>
+	</array>
+    <key>LSApplicationQueriesSchemes</key>
+    <array>
+         <string>whatsapp</string>
+         <string>googlegmail</string>
+         <string>ms-outlook</string>
+         <string>readdle-spark</string>
+         <string>ymail</string>
+    </array>
+	<key>UIAppFonts</key>
+	<array>
+		<string>Poppins-Light.ttf</string>
+		<string>Poppins-Medium.ttf</string>
+		<string>Poppins-SemiBoldItalic.ttf</string>
+		<string>Poppins-Regular.ttf</string>
+		<string>Poppins-LightItalic.ttf</string>
+		<string>Poppins-SemiBold.ttf</string>
+		<string>Poppins-MediumItalic.ttf</string>
+	</array>
+	<key>UIApplicationSceneManifest</key>
+	<dict>
+		<key>UIApplicationSupportsMultipleScenes</key>
+		<false/>
+		<key>UISceneConfigurations</key>
+		<dict>
+			<key>UIWindowSceneSessionRoleApplication</key>
+			<array>
+				<dict>
+					<key>UISceneConfigurationName</key>
+					<string>Default Configuration</string>
+					<key>UISceneDelegateClassName</key>
+					<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
+					<key>UISceneStoryboardFile</key>
+					<string>Main</string>
+				</dict>
+			</array>
+		</dict>
+	</dict>
+	<key>UIApplicationSupportsIndirectInputEvents</key>
+	<true/>
+	<key>UIBackgroundModes</key>
+	<array>
+		<string>audio</string>
+		<string>bluetooth-central</string>
+		<string>bluetooth-peripheral</string>
+		<string>external-accessory</string>
+		<string>fetch</string>
+		<string>processing</string>
+		<string>remote-notification</string>
+		<string>voip</string>
+	</array>
+	<key>UILaunchStoryboardName</key>
+	<string>LaunchScreen</string>
+	<key>UIMainStoryboardFile</key>
+	<string>Main</string>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>armv7</string>
+	</array>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UIViewControllerBasedStatusBarAppearance</key>
+	<true/>
+</dict>
+</plist>

+ 33 - 0
AppBuilder/AppBuilder/LaunchScreenViewController.swift

@@ -0,0 +1,33 @@
+//
+//  LaunchScreenViewController.swift
+//  DigiNetS
+//
+//  Created by Qindi on 31/08/22.
+//
+
+import UIKit
+import NotificationBannerSwift
+import NexilisLite
+
+class LaunchScreenViewController: UIViewController {
+    @IBOutlet weak var imageSS: UIImageView!
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+
+        if !CheckConnection.isConnectedToNetwork() {
+            let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+            imageView.tintColor = .white
+            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)
+            banner.show()
+            return
+        }
+        if PrefsUtil.getIconDock() != nil {
+            let data = try? Data(contentsOf: URL(string: PrefsUtil.getUrlDock()!)!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
+            if data != nil {
+                imageSS.image = UIImage(data: data!)
+            }
+        }
+    }
+
+}

+ 230 - 0
AppBuilder/AppBuilder/PrefsUtil.swift

@@ -0,0 +1,230 @@
+//
+//  PrefsUtil.swift
+//  AppBuilder
+//
+//  Created by Kevin Maulana on 23/03/22.
+//
+
+import Foundation
+
+
+class PrefsUtil {
+    static let CPAAS_MODE_FLOATING = 0
+    static let CPAAS_MODE_DOCKED = 1
+    static let CPAAS_MODE_BURGER = 2
+    static let CPAAS_MODE_MIX = 4
+    static let DEFAULT_CPAAS_MODE = CPAAS_MODE_DOCKED
+    
+    static func getCpaasMode() -> Int {
+        let mode = UserDefaults.standard.integer(forKey: "cpaas_mode")
+        if(mode != 0) {
+            return mode - 1
+        }
+        return PrefsUtil.DEFAULT_CPAAS_MODE
+    }
+    
+    static func setCpaasMode(mode: Int){
+        UserDefaults.standard.set(mode+1, forKey: "cpaas_mode")
+    }
+    
+    static var CUSTOM_TAB = "1,2,3,4"
+    
+    static func getCustomTab() -> String {
+        if let cust = UserDefaults.standard.string(forKey: "custom_tab"){
+            if(!cust.isEmpty){
+                return cust
+            }
+        }
+        return PrefsUtil.CUSTOM_TAB
+    }
+    
+    static func getURLFirstTab() -> String? {
+        return UserDefaults.standard.string(forKey: "app_builder_url_first_tab")
+    }
+    
+    static func getURLThirdTab() -> String? {
+        return UserDefaults.standard.string(forKey: "app_builder_url_third_tab")
+    }
+    static func getURLBase() -> String {
+        return UserDefaults.standard.string(forKey: "app_builder_url_base") ?? "https://nexilis.io/"
+    }
+    static func getURLQMS() -> String? {
+        return UserDefaults.standard.string(forKey: "app_builder_url_qms")
+    }
+    static func getIconDock() -> String {
+        return UserDefaults.standard.string(forKey: "app_builder_icon_dock") ?? ""
+    }
+    static func getIconSS() -> String? {
+        return UserDefaults.standard.string(forKey: "app_builder_icon_ss")
+    }
+    static func getBackground() -> String {
+        return UserDefaults.standard.string(forKey: "app_builder_background") ?? ""
+    }
+    
+    static func getBackgroundLight() -> String {
+        UserDefaults.standard.string(forKey: "app_builder_background_light") ?? ""
+    }
+
+    static func getBackgroundDark() -> String {
+        UserDefaults.standard.string(forKey: "app_builder_background_dark") ?? ""
+    }
+    
+    static func getUrlSS() -> String? {
+        return PrefsUtil.getURLBase() + "get_file_from_path?img=" + PrefsUtil.getIconSS()!
+    }
+    static func getUrlDock() -> String? {
+        return PrefsUtil.getURLBase() + "get_file_from_path?img=" + PrefsUtil.getIconDock()
+    }
+    
+    static func getURLPrivacyPolicy() -> String {
+        return UserDefaults.standard.string(forKey: "app_builder_url_privacy_policy") ?? "https://nexilis.io/privacypolicy"
+    }
+    
+    static func getEnablePrivacyPolicy() -> Bool {
+        return UserDefaults.standard.bool(forKey: "app_builder_enable_privacy_policy")
+    }
+    
+    static func getAgreePrivacyPolicy() -> Bool {
+        return UserDefaults.standard.bool(forKey: "agree_privacy_policy")
+    }
+    
+    static func setAgreePrivacyPolicy(value: Bool){
+        UserDefaults.standard.set(value, forKey: "agree_privacy_policy")
+    }
+    static func getTerms() -> Bool {
+        return UserDefaults.standard.bool(forKey: "terms_app")
+    }
+    
+    static func setTerms(value: Bool){
+        UserDefaults.standard.set(value, forKey: "terms_app")
+    }
+    
+    static func getCustomButtons() -> String {
+        UserDefaults.standard.string(forKey: "app_builder_custom_buttons") ?? ""
+    }
+    
+    static func getCustomFBIcon() -> String {
+        UserDefaults.standard.string(forKey: "app_builder_button_icon") ?? ""
+    }
+    
+    static func getIconCenterAnim() -> String? {
+        UserDefaults.standard.string(forKey: "fb_icon_center_anim")
+    }
+    
+}
+//public static String getHeaderColorSetting(Context pContext) {
+//        final SharedPreferences sharedPref = pContext.getSharedPreferences("PREF_SYS", Context.MODE_PRIVATE);
+//        String header_color = sharedPref.getString("header_color", "#00000000");
+//        return header_color;
+//    }
+//
+//    public static String getHeaderTextColorSetting(Context pContext) {
+//        final SharedPreferences sharedPref = pContext.getSharedPreferences("PREF_SYS", Context.MODE_PRIVATE);
+//        String header_text_color = sharedPref.getString("header_text_color", "#FF000000");
+//        return header_text_color;
+//    }
+//
+//    public static void setContentFilter(Context pContext, String new_value) {
+//        final SharedPreferences sharedPref = pContext.getSharedPreferences("PREF_SYS", Context.MODE_PRIVATE);
+//        SharedPreferences.Editor edit = sharedPref.edit();
+//        edit.putString("content_filter",new_value);
+//        edit.apply();
+//    }
+//
+//    public static String getContentFilter(Context pContext) {
+//        final SharedPreferences sharedPref = pContext.getSharedPreferences("PREF_SYS", Context.MODE_PRIVATE);
+//        String header_text_color = sharedPref.getString("content_filter", "1,2,3,4,5");
+//        return header_text_color;
+//    }
+//
+//    public static void setContentSort(Context pContext, int new_value) {
+//        final SharedPreferences sharedPref = pContext.getSharedPreferences("PREF_SYS", Context.MODE_PRIVATE);
+//        SharedPreferences.Editor edit = sharedPref.edit();
+//        edit.putInt("content_sort",new_value);
+//        edit.apply();
+//    }
+//
+//    public static int getContentSort(Context pContext) {
+//        final SharedPreferences sharedPref = pContext.getSharedPreferences("PREF_SYS", Context.MODE_PRIVATE);
+//        int header_text_color = sharedPref.getInt("content_sort", 1);
+//        return header_text_color;
+//    }
+//
+//    public static void setContentClassification(Context pContext, String new_value) {
+//        final SharedPreferences sharedPref = pContext.getSharedPreferences("PREF_SYS", Context.MODE_PRIVATE);
+//        SharedPreferences.Editor edit = sharedPref.edit();
+//        edit.putString("content_class",new_value);
+//        edit.apply();
+//    }
+//
+//    public static String getContentClassification(Context pContext) {
+//        final SharedPreferences sharedPref = pContext.getSharedPreferences("PREF_SYS", Context.MODE_PRIVATE);
+//        String header_text_color = sharedPref.getString("content_class", "1,2,3,4");
+//        return header_text_color;
+//    }
+//
+//    public static final int CPAAS_MODE_FLOATING = 0;
+//    public static final int CPAAS_MODE_DOCKED = 1;
+//    public static final int CPAAS_MODE_BURGER = 2;
+//    public static final int CPAAS_MODE_MIX = 4;
+//    public static final int DEFAULT_CPAAS_MODE = CPAAS_MODE_DOCKED;
+//    public static int getCpaasMode(Context pContext) {
+//        final SharedPreferences sharedPref = pContext.getSharedPreferences("PREF_SYS", Context.MODE_PRIVATE);
+//        int mode_index = sharedPref.getInt("cpaas_mode", DEFAULT_CPAAS_MODE);
+//        return mode_index;
+//    }
+//
+//    public static void setCpaasMode(Context pContext, int new_value) {
+//        final SharedPreferences sharedPref = pContext.getSharedPreferences("PREF_SYS", Context.MODE_PRIVATE);
+//        SharedPreferences.Editor edit = sharedPref.edit();
+//        edit.putInt("cpaas_mode",new_value);
+//        edit.apply();
+//    }
+//
+//    public static final int CPAAS_FLOAT_MODE_IN_APP = 3;
+//    public static final int CPAAS_FLOAT_MODE_OUT_APP = 4;
+//    public static int getCpaasFloatMode(Context pContext) {
+//        final SharedPreferences sharedPref = pContext.getSharedPreferences("PREF_SYS", Context.MODE_PRIVATE);
+//        int mode_index = sharedPref.getInt("cpaas_float_mode", CPAAS_FLOAT_MODE_IN_APP);
+//        return mode_index;
+//    }
+//    public static void setCpaasFloatMode(Context pContext, int new_value) {
+//        final SharedPreferences sharedPref = pContext.getSharedPreferences("PREF_SYS", Context.MODE_PRIVATE);
+//        SharedPreferences.Editor edit = sharedPref.edit();
+//        edit.putInt("cpaas_float_mode",new_value);
+//        edit.apply();
+//    }
+//
+//    public static String getURLFirstTab() {
+//        return CoreDataSqlite_PrefsDB.get("app_builder_url_first_tab", "");
+//    }
+//
+//    public static String getURLThirdTab() {
+//        return  CoreDataSqlite_PrefsDB.get("app_builder_url_third_tab", "");
+//    }
+//
+//    public static String getURLBase() {
+//        return  CoreDataSqlite_PrefsDB.get("app_builder_url_base", Util_RandomCrypt.decrypt("3<rl;duhpt<<=vswwk"));
+//    }
+//
+//    public static void setURLFirstTab(String new_value) {
+//        CoreDataSqlite_PrefsDB.put("app_builder_url_first_tab", new_value);
+//    }
+//
+//    public static void setURLThirdTab(String new_value) {
+//        CoreDataSqlite_PrefsDB.put("app_builder_url_third_tab", new_value);
+//    }
+//
+//    public static void setURLBase(String new_value) {
+//        CoreDataSqlite_PrefsDB.put("app_builder_url_base", new_value);
+//    }
+//
+//    public static String DEFAULT_TAB_AMOUNT = "4";
+//
+//    public static String getTabAmount(){
+//        return CoreDataSqlite_PrefsDB.get("app_builder_tab_amount", DEFAULT_TAB_AMOUNT);
+//    }
+//
+//    public static void setTabAmount(Context pContext, String new_value){
+//        CoreDataSqlite_PrefsDB.put("app_builder_tab_amount", new_value);
+//    }

+ 120 - 0
AppBuilder/AppBuilder/SceneDelegate.swift

@@ -0,0 +1,120 @@
+//
+//  SceneDelegate.swift
+//  TestQmeraLite
+//
+//  Created by Qindi on 29/11/21.
+//
+
+import UIKit
+import NexilisLite
+
+class SceneDelegate: UIResponder, UIWindowSceneDelegate {
+
+    var window: UIWindow?
+    var splashWindow: UIWindow?
+
+    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
+        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
+        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
+        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
+        guard let _ = (scene as? UIWindowScene) else { return }
+        if let launchStoryboardName = InfoPList.launchStoryboardName,
+                   let windowScene          = self.window?.windowScene
+        {
+            splashWindow = splashWindow ??
+            {
+                let window = UIWindow(windowScene: windowScene)
+                    window.windowLevel = .statusBar
+
+                let storyboard = UIStoryboard(name: launchStoryboardName, bundle: nil)
+
+                window.rootViewController = storyboard.instantiateInitialViewController()
+                window.isHidden           = false
+
+                // ⏳Wait for 5 seconds, then remove.
+                //
+                DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2))
+                {
+                    UIView.animate(withDuration: -1, // system default
+                        animations:
+                        {
+                            self.splashWindow?.alpha = 0
+                        },
+                        completion:
+                        { _ in
+                            self.splashWindow?.isHidden = true
+                            self.splashWindow = nil
+                        }
+                    )
+                }
+                
+                let tabBarAppearance: UITabBarAppearance = UITabBarAppearance()
+                tabBarAppearance.configureWithTransparentBackground()
+                if let rootViewController = window.rootViewController {
+                    // Check if dark mode is enabled
+                    let isDarkMode = rootViewController.traitCollection.userInterfaceStyle == .dark
+                    if isDarkMode {
+                        tabBarAppearance.backgroundColor = .black.withAlphaComponent(0.7)
+                    } else {
+                        tabBarAppearance.backgroundColor = .white.withAlphaComponent(0.9)
+                    }
+                    if Utils.getReverseTab() == "1" {
+                        tabBarAppearance.backgroundColor = .black.withAlphaComponent(0.7)
+                    }
+                }
+                if #available(iOS 13.0, *) {
+                    UITabBar.appearance().standardAppearance = tabBarAppearance
+                }
+                if #available(iOS 15.0, *) {
+                    UITabBar.appearance().scrollEdgeAppearance = tabBarAppearance
+                }
+
+                return window
+            }()
+        }
+    }
+
+    func sceneDidDisconnect(_ scene: UIScene) {
+        // Called as the scene is being released by the system.
+        // This occurs shortly after the scene enters the background, or when its session is discarded.
+        // Release any resources associated with this scene that can be re-created the next time the scene connects.
+        // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
+    }
+
+    func sceneDidBecomeActive(_ scene: UIScene) {
+        // Called when the scene has moved from an inactive state to an active state.
+        // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
+    }
+
+    func sceneWillResignActive(_ scene: UIScene) {
+        // Called when the scene will move from an active state to an inactive state.
+        // This may occur due to temporary interruptions (ex. an incoming phone call).
+    }
+
+    func sceneWillEnterForeground(_ scene: UIScene) {
+        // Called as the scene transitions from the background to the foreground.
+        // Use this method to undo the changes made on entering the background.
+    }
+
+    func sceneDidEnterBackground(_ scene: UIScene) {
+        // Called as the scene transitions from the foreground to the background.
+        // Use this method to save data, release shared resources, and store enough scene-specific state information
+        // to restore the scene back to its current state.
+    }
+
+
+}
+
+struct InfoPList
+{
+    private static func value(for name: String) -> String? { Bundle.main.object(forInfoDictionaryKey: name) as? String }
+
+    static var bundleIdentifier:         String? { self.value(for: "CFBundleIdentifier") }
+    static var bundleDisplayName:        String? { self.value(for: "CFBundleDisplayName") }
+    static var bundleShortVersionString: String? { self.value(for: "CFBundleShortVersionString") }
+    static var bundleVersion:            String? { self.value(for: "CFBundleVersion") }
+
+    static var launchStoryboardName: String? { self.value(for: "UILaunchStoryboardName") }
+    static var mainStoryboardName:   String? { self.value(for: "UIMainStoryboardFile") }
+}
+

+ 1433 - 0
AppBuilder/AppBuilder/SecondTabViewController.swift

@@ -0,0 +1,1433 @@
+//
+//  SecondTabViewController.swift
+//  AppBuilder
+//
+//  Created by Kevin Maulana on 30/03/22.
+//
+
+import UIKit
+import FMDB
+import NexilisLite
+import Speech
+
+class SecondTabViewController: UIViewController, UIScrollViewDelegate, UIGestureRecognizerDelegate, UITextFieldDelegate {
+    
+    var isChooser: ((String, String) -> ())?
+    
+    var isAdmin: Bool = false
+    
+    var chats: [Chat] = []
+    
+    var groups: [Group] = []
+    
+    var cancelSearchButton = UIBarButtonItem()
+    var menuItem = UIBarButtonItem()
+    var menuBroadcast = UIBarButtonItem()
+    var voiceItem = UIBarButtonItem()
+    
+    var childrenMenu = [UIAction]()
+    
+    var groupMap: [String:Int] = [:]
+    
+    var isAllowSpeech = false
+    var alertController = LibAlertController()
+    
+    var noData = false
+    
+    let textViewSearch = UITextField()
+    let imageVoiceSb = UIImageView()
+    let imageNewChatSb = UIImageView()
+    
+    override var preferredStatusBarStyle: UIStatusBarStyle {
+        return self.traitCollection.userInterfaceStyle == .dark ? .default : .lightContent // Change this to .default for black text color
+    }
+
+    lazy var searchController: UISearchController = {
+        var searchController = UISearchController(searchResultsController: nil)
+        searchController.delegate = self
+        searchController.searchResultsUpdater = self
+        searchController.searchBar.autocapitalizationType = .none
+        searchController.searchBar.delegate = self
+//        searchController.searchBar.setMagnifyingGlassColorTo(color: self.traitCollection.userInterfaceStyle == .dark ? .white : .black)
+//        searchController.searchBar.updateHeight(height: 30, radius: 15, borderColor: UIColor.clear.cgColor)
+        searchController.searchBar.setImage(UIImage(), for: .search, state: .normal)
+        searchController.searchBar.setPositionAdjustment(UIOffset(horizontal: 10, vertical: 0), for: .search)
+        searchController.searchBar.setCustomBackgroundImage(image: UIImage(named: self.traitCollection.userInterfaceStyle == .dark ? "nx_search_bar_dark" : "nx_search_bar", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
+        searchController.obscuresBackgroundDuringPresentation = false
+        searchController.searchBar.searchTextField.attributedPlaceholder = NSAttributedString(string: "Search...".localized(), attributes: [NSAttributedString.Key.foregroundColor: UIColor.gray, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 11)])
+        return searchController
+    }()
+    
+    lazy var segment: UISegmentedControl = {
+        var segment = UISegmentedControl(items: ["Chats".localized(), "Forums".localized()])
+        segment.sizeToFit()
+        segment.selectedSegmentIndex = 0
+        segment.addTarget(self, action: #selector(segmentChanged(sender:)), for: .valueChanged)
+        segment.setTitleTextAttributes([NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 12.0)], for: .normal)
+        return segment
+    }()
+    
+    var fillteredData: [Any] = []
+    
+    var isSearchBarEmpty: Bool {
+        return searchController.searchBar.text!.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
+    }
+    
+    var isFilltering: Bool {
+        return !isSearchBarEmpty
+    }
+    @IBOutlet var tableView: UITableView!
+    
+    var speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "id"))
+
+    var recognitionRequest : SFSpeechAudioBufferRecognitionRequest?
+    var recognitionTask : SFSpeechRecognitionTask?
+    let audioEngine = AVAudioEngine()
+    
+    func filterContentForSearchText(_ searchText: String) {
+        if !searchText.isEmpty {
+            switch segment.selectedSegmentIndex {
+            case 1:
+                fillteredData = self.groups.filter { $0.name.lowercased().contains(searchText.lowercased()) }
+            default:
+                fillteredData = self.chats.filter { $0.name.lowercased().contains(searchText.lowercased()) || $0.messageText.lowercased().contains(searchText.lowercased()) }
+            }
+        }
+        tableView.reloadData()
+    }
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        let me = UserDefaults.standard.string(forKey: "me")!
+        Database.shared.database?.inTransaction({ fmdb, rollback in
+            if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select FIRST_NAME, LAST_NAME, IMAGE_ID, USER_TYPE from BUDDY where F_PIN = '\(me)'"), cursor.next() {
+                isAdmin = cursor.string(forColumnIndex: 3) == "23" || cursor.string(forColumnIndex: 3) == "24"
+                cursor.close()
+            }
+        })
+        
+//        var childrenMenu : [UIAction] = []
+//        
+//        if(isAdmin){
+//            childrenMenu.append(UIAction(title: "Broadcast Message".localized(), image: UIImage(systemName: "envelope.open"), handler: {[weak self](_) in
+//                let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "broadcastNav")
+//                self?.navigationController?.present(controller, animated: true, completion: nil)
+//            }))
+//        }
+        
+//        let startConvIcon = resizeImage(image: self.traitCollection.userInterfaceStyle == .dark ?  UIImage(systemName: "square.and.pencil")!.withTintColor(.white) : UIImage(systemName: "square.and.pencil")!, targetSize: CGSize(width: 25, height: 25))
+//        let viewStartConv = UIButton(frame: CGRect(x: 0, y: 0, width: startConvIcon.size.width, height: startConvIcon.size.height))
+//        viewStartConv.setImage(startConvIcon, for: .normal)
+//        viewStartConv.addTarget(self, action: #selector(startConversation), for: .touchUpInside)
+//        let brodcastIcon = resizeImage(image: self.traitCollection.userInterfaceStyle == .dark ? UIImage(named: "ic_broadcast")!.withTintColor(.white) : UIImage(named: "ic_broadcast")!, targetSize: CGSize(width: 25, height: 25))
+//        let viewbrodcast = UIButton(frame: CGRect(x: 0, y: 0, width: brodcastIcon.size.width, height: brodcastIcon.size.height))
+//        viewbrodcast.setImage(brodcastIcon, for: .normal)
+//        viewbrodcast.addTarget(self, action: #selector(openBroadcast), for: .touchUpInside)
+//        
+//        menuItem = UIBarButtonItem(customView: viewStartConv)
+//        menuBroadcast = UIBarButtonItem(customView: viewbrodcast)
+        
+//        menuItem = UIBarButtonItem(image: UIImage(systemName: "square.and.pencil"), style: .plain, target: self, action: #selector(startConversation))
+//        menuBroadcast = UIBarButtonItem(image: UIImage(systemName: "info.bubble"), style: .plain, target: self, action: #selector(openBroadcast))
+//        voiceItem = UIBarButtonItem(image: UIImage(systemName: "mic.fill"), style: .plain, target: self, action: #selector(recordAudio))
+        
+        definesPresentationContext = true
+        
+        NotificationCenter.default.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerStatusChat), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReload(notification:)), name: NSNotification.Name(rawValue: "onMember"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReload(notification:)), name: NSNotification.Name(rawValue: "onUpdatePersonInfo"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReloadTab(notification:)), name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReloadTab(notification:)), name: NSNotification.Name(rawValue: "onTopic"), object: nil)
+        
+        
+        
+        tableView.tableHeaderView = segment
+        tableView.tableFooterView = UIView()
+        
+        if PrefsUtil.getCpaasMode() == PrefsUtil.CPAAS_MODE_DOCKED {
+            tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 80, right: 0)
+        }
+        
+        pullBuddy()
+        navigationController?.setNavigationBarHidden(true, animated: false)
+        
+        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(collapseDocked))
+        tapGesture.cancelsTouchesInView = false
+        tapGesture.delegate = self
+        self.view.addGestureRecognizer(tapGesture)
+    }
+    
+    @objc func collapseDocked() {
+        if ViewController.isExpandButton {
+            ViewController.expandButton()
+        }
+        if textViewSearch.isFirstResponder {
+            textViewSearch.resignFirstResponder()
+        }
+    }
+    
+    @objc func openBroadcast() {
+        let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "broadcastNav")
+        controller.modalPresentationStyle = .fullScreen
+        self.navigationController?.present(controller, animated: true, completion: nil)
+    }
+    
+    @objc func startConversation(){
+        let navigationController = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "contactChatNav") as! UINavigationController
+        navigationController.view.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .black : .white
+        Utils.addBackground(view: navigationController.view)
+        navigationController.modalPresentationStyle = .fullScreen
+        navigationController.navigationBar.tintColor = .white
+        navigationController.navigationBar.barTintColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
+        navigationController.navigationBar.isTranslucent = false
+        let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
+        UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
+        let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
+        navigationController.navigationBar.titleTextAttributes = textAttributes
+        navigationController.navigationBar.overrideUserInterfaceStyle = .dark
+        navigationController.navigationBar.barStyle = .black
+        self.navigationController?.present(navigationController, animated: true, completion: nil)
+    }
+    
+    @objc func recordAudio(){
+        if !isAllowSpeech {
+            setupSpeech()
+        } else {
+            runVoice()
+        }
+    }
+    
+    func setupSpeech() {
+
+        self.speechRecognizer?.delegate = self
+
+        SFSpeechRecognizer.requestAuthorization { (authStatus) in
+
+            var isButtonEnabled = false
+
+            switch authStatus {
+            case .authorized:
+                isButtonEnabled = true
+
+            case .denied:
+                isButtonEnabled = false
+                //print("User denied access to speech recognition")
+
+            case .restricted:
+                isButtonEnabled = false
+                //print("Speech recognition restricted on this device")
+
+            case .notDetermined:
+                isButtonEnabled = false
+                //print("Speech recognition not yet authorized")
+            @unknown default:
+                isButtonEnabled = false
+            }
+
+            OperationQueue.main.addOperation() {
+                self.isAllowSpeech = isButtonEnabled
+                if isButtonEnabled {
+                    UserDefaults.standard.set(isButtonEnabled, forKey: "allowSpeech")
+                    self.runVoice()
+                }
+            }
+        }
+    }
+    
+    func startRecording() {
+
+        // Clear all previous session data and cancel task
+        if recognitionTask != nil {
+            recognitionTask?.cancel()
+            recognitionTask = nil
+        }
+
+        // Create instance of audio session to record voice
+        let audioSession = AVAudioSession.sharedInstance()
+        do {
+            try audioSession.setCategory(AVAudioSession.Category.record, mode: AVAudioSession.Mode.measurement, options: AVAudioSession.CategoryOptions.defaultToSpeaker)
+            try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
+        } catch {
+            //print("audioSession properties weren't set because of an error.")
+        }
+
+        self.recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
+
+        let inputNode = audioEngine.inputNode
+
+        guard let recognitionRequest = recognitionRequest else {
+            fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object")
+        }
+
+        recognitionRequest.shouldReportPartialResults = true
+
+        self.recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in
+
+            var isFinal = false
+
+            if result != nil {
+                self.alertController.dismiss(animated: true)
+                self.audioEngine.stop()
+                self.recognitionRequest?.endAudio()
+                isFinal = (result?.isFinal)!
+            }
+
+            if error != nil || isFinal {
+                if error == nil {
+                    self.searchController.searchBar.searchTextField.text = result!.bestTranscription.formattedString
+                    self.updateSearchResults(for: self.searchController)
+                } else {
+                    self.audioEngine.stop()
+                    self.recognitionRequest?.endAudio()
+                }
+                self.voiceItem.image = UIImage(systemName: "mic.fill")
+                inputNode.removeTap(onBus: 0)
+
+                self.recognitionRequest = nil
+                self.recognitionTask = nil
+            }
+        })
+
+        let recordingFormat = inputNode.outputFormat(forBus: 0)
+        inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
+            self.recognitionRequest?.append(buffer)
+        }
+
+        self.audioEngine.prepare()
+
+        do {
+            try self.audioEngine.start()
+        } catch {
+            //print("audioEngine couldn't start because of an error.")
+        }
+    }
+    
+    func runVoice() {
+        if !audioEngine.isRunning {
+            self.voiceItem.image = UIImage(systemName: "mic")
+            alertController = LibAlertController(title: "Start Recording".localized(), message: "Say something, I'm listening!".localized(), preferredStyle: .alert)
+            self.present(alertController, animated: true)
+            self.startRecording()
+        }
+    }
+    
+    override func viewDidAppear(_ animated: Bool) {
+        self.navigationController?.navigationBar.topItem?.title = "Chats".localized() + " & " + "Forums".localized()
+        self.navigationController?.navigationBar.setNeedsLayout()
+        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
+            var viewController = UIApplication.shared.windows.first!.rootViewController
+            if !(viewController is ViewController) {
+                viewController = self.parent
+            }
+            if ViewController.middleButton.isHidden {
+                ViewController.isExpandButton = false
+                if let viewController = viewController as? ViewController {
+                    if viewController.tabBar.isHidden {
+                        viewController.tabBar.isHidden = false
+                        ViewController.alwaysHideButton = false
+                        ViewController.middleButton.isHidden = false
+                    }
+                }
+            } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
+                DispatchQueue.main.async {
+                    if let viewController = viewController as? ViewController {
+                        if viewController.tabBar.isHidden {
+                            ViewController.alwaysHideButton = false
+                            viewController.tabBar.isHidden = false
+                        }
+                    }
+                }
+            }
+        })
+        getData()
+        DispatchQueue.global().async {
+            self.getOpenGroups(listGroups: self.groups, completion: { g in
+                DispatchQueue.main.async {
+                    for og in g {
+                        if self.groups.first(where: { $0.id == og.id }) == nil {
+                            self.groups.append(og)
+                        }
+                    }
+                    self.groups.sort { (a, b) -> Bool in
+                        if Int(a.official) == 1 {
+                            return true
+                        } else if Int(b.official) == 1 {
+                            return false
+                        } else {
+                            return Int(a.official) ?? 0 > Int(b.official) ?? 0
+                        }
+                    }
+                    DispatchQueue.main.async {
+                        self.tableView.reloadData()
+                    }
+                }
+            })
+        }
+    }
+    
+    override func viewWillAppear(_ animated: Bool) {
+//        tabBarController?.navigationItem.leftBarButtonItem = cancelSearchButton
+        let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: self.traitCollection.userInterfaceStyle == .dark ? .white : UIColor.black, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
+        UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
+        let attributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: self.traitCollection.userInterfaceStyle == .dark ? .white : UIColor.black, NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 16)]
+        let navBarAppearance = UINavigationBarAppearance()
+        navBarAppearance.configureWithTransparentBackground()
+        navBarAppearance.titleTextAttributes = attributes
+        navigationController?.navigationBar.standardAppearance = navBarAppearance
+        navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
+        navigationController?.navigationBar.backgroundColor = .clear
+        navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
+        navigationController?.navigationBar.shadowImage = UIImage()
+        navigationController?.navigationBar.isTranslucent = true
+        navigationController?.setNavigationBarHidden(false, animated: false)
+        navigationController?.navigationBar.tintColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
+        navigationController?.navigationBar.overrideUserInterfaceStyle = self.traitCollection.userInterfaceStyle == .dark ? .dark : .light
+        navigationController?.navigationBar.barStyle = .default
+//        tabBarController?.navigationItem.leftBarButtonItem = voiceItem
+//        let myData = User.getData(pin: User.getMyPin())
+//        if User.isOfficial(official_account: myData?.official ?? "") || User.isOfficialRegular(official_account: myData?.official ?? "") || User.isInternal(userType: myData?.userType ?? "") {
+//            let fixedSpace = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
+//            fixedSpace.width = 15.0
+//            tabBarController?.navigationItem.rightBarButtonItems = [menuBroadcast, fixedSpace, menuItem]
+//        } else {
+//            tabBarController?.navigationItem.rightBarButtonItem = menuItem
+//        }
+//        tabBarController?.navigationItem.searchController = searchController
+        let customView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: 30))
+        customView.isUserInteractionEnabled = true
+        
+        let imageViewSearch = UIImageView(image: UIImage(named: self.traitCollection.userInterfaceStyle == .dark ? "nx_search_bar_dark" : "nx_search_bar", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
+        imageViewSearch.contentMode = .scaleToFill
+        customView.addSubview(imageViewSearch)
+        imageViewSearch.anchor(top: customView.topAnchor, left: customView.leftAnchor, bottom: customView.bottomAnchor, right: customView.rightAnchor, height: 30)
+        imageViewSearch.isUserInteractionEnabled = true
+        
+        let imageSetting = UIImageView(image: UIImage(named: "nx_setting_sb", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
+        imageSetting.contentMode = .scaleToFill
+        imageViewSearch.addSubview(imageSetting)
+        imageSetting.anchor(top: imageViewSearch.topAnchor, right: customView.rightAnchor, paddingTop: 5, paddingRight: 18, width: 20, height: 20)
+        imageSetting.isUserInteractionEnabled = true
+        imageSetting.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(settingTapped)))
+        
+        imageVoiceSb.image = UIImage(named: "nx_mic", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!
+        imageVoiceSb.contentMode = .scaleAspectFit
+        imageViewSearch.addSubview(imageVoiceSb)
+        imageVoiceSb.anchor(top: imageViewSearch.topAnchor, right: imageSetting.leftAnchor, paddingTop: 5, paddingRight: 15, width: 20, height: 20)
+        imageVoiceSb.isUserInteractionEnabled = true
+        imageVoiceSb.isHidden = true
+        imageVoiceSb.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(recordAudio)))
+        
+        imageNewChatSb.image = UIImage(systemName: "square.and.pencil")!
+        imageNewChatSb.tintColor = .nxColor
+        imageNewChatSb.contentMode = .scaleAspectFit
+        imageViewSearch.addSubview(imageNewChatSb)
+        imageNewChatSb.anchor(top: imageViewSearch.topAnchor, right: imageVoiceSb.leftAnchor, paddingTop: 5, paddingRight: 15, width: 20, height: 20)
+        imageNewChatSb.isUserInteractionEnabled = true
+        imageNewChatSb.isHidden = true
+        imageNewChatSb.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(startConversation)))
+        
+        textViewSearch.placeholder = "Search...".localized()
+        textViewSearch.isUserInteractionEnabled = true
+        imageViewSearch.addSubview(textViewSearch)
+        textViewSearch.font = .systemFont(ofSize: 11)
+        textViewSearch.anchor(top: imageViewSearch.topAnchor, left: imageViewSearch.leftAnchor, bottom: imageViewSearch.bottomAnchor, right: imageViewSearch.rightAnchor, paddingTop: 5, paddingLeft: 20, paddingBottom: 5, paddingRight: 120)
+        textViewSearch.delegate = self
+        
+        tabBarController?.navigationItem.titleView = customView
+        let lang = UserDefaults.standard.string(forKey: "i18n_language")
+        speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: lang ?? "en"))
+        backgroundImage.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .black : .white
+        DispatchQueue.global().async {
+            DispatchQueue.main.async {
+                let listBg = PrefsUtil.getBackgroundLight().isEmpty && PrefsUtil.getBackgroundDark().isEmpty ? PrefsUtil.getBackground() :
+                                    self.traitCollection.userInterfaceStyle == .dark ? PrefsUtil.getBackgroundDark() : PrefsUtil.getBackgroundLight()
+                if listBg.isEmpty {
+                   return
+                }
+                var bgChoosen = ""
+                let arrayBg = listBg.split(separator: ",")
+                bgChoosen = String(arrayBg[Int.random(in: 0..<arrayBg.count)])
+                let urlString = PrefsUtil.getURLBase() + "get_file_from_path?img=" + bgChoosen
+                if let cachedImage = ImageCache.shared.image(forKey: urlString) {
+                    DispatchQueue.main.async() {  [self] in
+                        backgroundImage.image = cachedImage
+                    }
+                    return
+                }
+                Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
+                    guard let data = data, error == nil else { return }
+                    // always update the UI from the main thread
+                    DispatchQueue.main.async() { [self] in
+                        if UIImage(data: data) != nil {
+                            backgroundImage.image = UIImage(data: data)!
+                            ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
+                        }
+                    }
+                }
+            }
+        }
+        if segment.numberOfSegments == 2 {
+            segment.setTitle("Chats".localized(), forSegmentAt: 0)
+            segment.setTitle("Forums".localized(), forSegmentAt: 1)
+        }
+        if segment.selectedSegmentIndex == 0 {
+            Utils.inTabChats = true
+//            searchController.searchBar.placeholder = "Search chats & messages".localized()
+//            searchController.searchBar.searchTextField.attributedPlaceholder = NSAttributedString(string: "Search chats & messages".localized(), attributes: [NSAttributedString.Key.foregroundColor: UIColor.gray, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)])
+        } else {
+//            searchController.searchBar.placeholder = "Search groups name".localized()
+//            searchController.searchBar.searchTextField.attributedPlaceholder = NSAttributedString(string: "Search groups name".localized(), attributes: [NSAttributedString.Key.foregroundColor: UIColor.gray, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)])
+        }
+//        removeAllData()
+//        getData()
+    }
+    
+//    func removeAllData() {
+//        groups.removeAll()
+//        groupMap.removeAll()
+//        chats.removeAll()
+//        tableView.reloadData()
+//    }
+    
+    override func viewWillDisappear(_ animated: Bool) {
+        tabBarController?.navigationItem.leftBarButtonItem = nil
+        tabBarController?.navigationItem.searchController = nil
+        tabBarController?.navigationItem.rightBarButtonItem = nil
+        tabBarController?.navigationItem.rightBarButtonItems = nil
+        tabBarController?.navigationItem.titleView = nil
+        Utils.inTabChats = false
+        if ViewController.isExpandButton {
+            ViewController.expandButton()
+        }
+    }
+    
+    @objc func settingTapped() {
+        imageVoiceSb.isHidden = !imageVoiceSb.isHidden
+        imageNewChatSb.isHidden = !imageNewChatSb.isHidden
+    }
+    
+    @objc func onReloadTab(notification: NSNotification) {
+        DispatchQueue.main.async {
+            self.getData()
+        }
+    }
+    
+    @objc func onReload(notification: NSNotification) {
+        let data:[AnyHashable : Any] = notification.userInfo!
+        if data["member"] as? String == UserDefaults.standard.string(forKey: "me")! {
+            DispatchQueue.main.async {
+                self.getData()
+            }
+        } else if data["state"] as? Int == 99 {
+            DispatchQueue.main.async {
+                self.getData()
+            }
+        }
+    }
+    
+    @objc func onReceiveMessage(notification: NSNotification) {
+        DispatchQueue.main.async { [self] in
+            let data:[AnyHashable : Any] = notification.userInfo!
+            if let dataMessage = data["message"] as? TMessage {
+                let chatData = dataMessage.mBodies
+                if chatData[CoreMessage_TMessageKey.IS_CALL_CENTER] == nil || chatData[CoreMessage_TMessageKey.IS_CALL_CENTER] == "0" {
+                    var indexChat: Int?
+                    if chatData[CoreMessage_TMessageKey.MESSAGE_SCOPE_ID] == "3" && chatData[CoreMessage_TMessageKey.F_PIN] != User.getMyPin() {
+                        indexChat = chats.firstIndex(where: { $0.fpin == chatData[CoreMessage_TMessageKey.F_PIN] })
+                    } else if chatData[CoreMessage_TMessageKey.MESSAGE_SCOPE_ID] == "4" && chatData[CoreMessage_TMessageKey.F_PIN] != User.getMyPin() {
+                        indexChat = chats.firstIndex(where: { (chatData[CoreMessage_TMessageKey.CHAT_ID] ?? "").isEmpty ? $0.pin == chatData[CoreMessage_TMessageKey.L_PIN] : $0.pin == chatData[CoreMessage_TMessageKey.CHAT_ID] })
+                    }
+                    let newChat = Chat.getData(messageId: chatData[CoreMessage_TMessageKey.MESSAGE_ID] ?? "")
+                    if newChat.count > 0 {
+                        if indexChat != nil {
+                            chats.remove(at: indexChat!)
+                            chats.insert(newChat[0], at: 0)
+                            let indexPathToMove = IndexPath(row: indexChat!, section: 0)
+                            let indexPathNewPosition = IndexPath(row: 0, section: 0)
+                            tableView.performBatchUpdates({
+                                tableView.moveRow(at: indexPathToMove, to: indexPathNewPosition)
+                            }, completion: nil)
+                            tableView.beginUpdates()
+                            tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: .none)
+                            tableView.endUpdates()
+                        } else {
+                            chats.insert(newChat[0], at: 0)
+                            tableView.reloadData()
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    @objc func onStatusChat(notification: NSNotification) {
+        DispatchQueue.main.async { [self] in
+            let data:[AnyHashable : Any] = notification.userInfo!
+            if let dataMessage = data["message"] as? TMessage {
+                var idMessage = dataMessage.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)
+                if idMessage.contains(",") {
+                    let listString = dataMessage.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID).components(separatedBy: ",")
+                    idMessage = listString[listString.count - 1]
+                }
+                let indexChat = chats.firstIndex(where: { $0.messageId == idMessage })
+                if indexChat != nil {
+                    if dataMessage.getBody(key: CoreMessage_TMessageKey.DELETE_MESSAGE_FLAG) == "1" {
+                        chats[indexChat!].lock = "1"
+                    }
+                    tableView.beginUpdates()
+                    tableView.reloadRows(at: [IndexPath(row: indexChat!, section: 0)], with: .none)
+                    tableView.endUpdates()
+                }
+            }
+        }
+    }
+    
+    @objc func segmentChanged(sender: Any) {
+        switch segment.selectedSegmentIndex {
+        case 1:
+            Utils.inTabChats = false
+//            searchController.searchBar.placeholder = "Search groups name".localized()
+//            searchController.searchBar.searchTextField.attributedPlaceholder = NSAttributedString(string: "Search groups name".localized(), attributes: [NSAttributedString.Key.foregroundColor: UIColor.gray, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)])
+        default:
+            Utils.inTabChats = true
+//            searchController.searchBar.placeholder = "Search chats & messages".localized()
+//            searchController.searchBar.searchTextField.attributedPlaceholder = NSAttributedString(string: "Search chats & messages".localized(), attributes: [NSAttributedString.Key.foregroundColor: UIColor.gray, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)])
+        }
+        filterContentForSearchText(searchController.searchBar.text!)
+    }
+    
+    // MARK: - Data source
+    
+    func getData() {
+        getChats {
+            self.getGroups { g1 in
+                self.groupMap.removeAll()
+                self.groups = g1
+                self.groups.sort { (a, b) -> Bool in
+                    if Int(a.official) == 1 {
+                        return true
+                    } else if Int(b.official) == 1 {
+                        return false
+                    } else {
+                        return Int(a.official) ?? 0 > Int(b.official) ?? 0
+                    }
+                }
+                DispatchQueue.main.async {
+                    self.tableView.reloadData()
+                }
+            }
+        }
+    }
+    
+    func getChats(completion: @escaping ()->()) {
+        DispatchQueue.global().async {
+            self.chats = Chat.getData()
+            completion()
+        }
+    }
+    
+    private func getGroupRecursive(fmdb: FMDatabase, id: String = "", parent: String = "") -> [Group] {
+        var data: [Group] = []
+        var query = "select g.group_id, g.f_name, g.image_id, g.quote, g.created_by, g.created_date, g.parent, g.group_type, g.is_open, g.official, g.is_education, g.level, g.chat_modifier from GROUPZ g where "
+        if id.isEmpty {
+            query += "g.parent = '\(parent)'"
+        } else {
+            query += "g.group_id = '\(id)'"
+        }
+        query += "order by 12 asc, 13 asc, 2 asc"
+        if let cursor = Database.shared.getRecords(fmdb: fmdb, query: query) {
+            while cursor.next() {
+                let group = Group(
+                    id: cursor.string(forColumnIndex: 0) ?? "",
+                    name: cursor.string(forColumnIndex: 1) ?? "",
+                    profile: cursor.string(forColumnIndex: 2) ?? "",
+                    quote: cursor.string(forColumnIndex: 3) ?? "",
+                    by: cursor.string(forColumnIndex: 4) ?? "",
+                    date: cursor.string(forColumnIndex: 5) ?? "",
+                    parent: cursor.string(forColumnIndex: 6) ?? "",
+                    chatId: "",
+                    groupType: cursor.string(forColumnIndex: 7) ?? "",
+                    isOpen: cursor.string(forColumnIndex: 8) ?? "",
+                    official: cursor.string(forColumnIndex: 9) ?? "",
+                    isEducation: cursor.string(forColumnIndex: 10) ?? "",
+                    level: cursor.string(forColumnIndex: 11) ?? "")
+                
+                if group.chatId.isEmpty {
+                    let lounge = Group(id: group.id, name: "Lounge".localized(), profile: "", quote: group.quote, by: group.by, date: group.date, parent: group.id, chatId: group.chatId, groupType: group.groupType, isOpen: group.isOpen, official: group.official, isEducation: group.isEducation, isLounge: true, level: group.level != "-1" ? group.level : "2")
+                    group.childs.append(lounge)
+                }
+                
+                if let topicCursor = Database.shared.getRecords(fmdb: fmdb, query: "select chat_id, title, thumb from DISCUSSION_FORUM where group_id = '\(group.id)'") {
+                    while topicCursor.next() {
+                        let topic = Group(id: group.id,
+                                          name: topicCursor.string(forColumnIndex: 1) ?? "",
+                                          profile: topicCursor.string(forColumnIndex: 2) ?? "",
+                                          quote: group.quote,
+                                          by: group.by,
+                                          date: group.date,
+                                          parent: group.id,
+                                          chatId: topicCursor.string(forColumnIndex: 0) ?? "",
+                                          groupType: group.groupType,
+                                          isOpen: group.isOpen,
+                                          official: group.official,
+                                          isEducation: group.isEducation,
+                                          level: group.level != "-1" ? group.level : "2")
+                        group.childs.append(topic)
+                    }
+                    topicCursor.close()
+                }
+                
+                if !group.id.isEmpty {
+//                    if group.official == "1" {
+//                        let idMe = UserDefaults.standard.string(forKey: "me") as String?
+//                        if let cursorUser = Database.shared.getRecords(fmdb: fmdb, query: "SELECT user_type FROM BUDDY where f_pin='\(idMe!)'"), cursorUser.next() {
+//                            group.childs.append(contentsOf: getGroupRecursive(fmdb: fmdb, parent: group.id))
+//                            cursorUser.close()
+//                        }
+//                    } else if group.official != "1"{
+//                        group.childs.append(contentsOf: getGroupRecursive(fmdb: fmdb, parent: group.id))
+//                    }
+                    group.childs.append(contentsOf: getGroupRecursive(fmdb: fmdb, parent: group.id))
+//                    group.childs = group.childs.sorted(by: { $0.name < $1.name })
+//                    let dataLounge = group.childs.filter({$0.name == "Lounge".localized()})
+//                    group.childs = group.childs.filter({ $0.name != "Lounge".localized() })
+//                    group.childs.insert(contentsOf: dataLounge, at: 0)
+                }
+                data.append(group)
+            }
+            cursor.close()
+        }
+        return data
+    }
+    
+    private func getOpenGroups(listGroups: [Group], completion: @escaping ([Group]) -> ()) {
+        if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getOpenGroups(p_account: "1,2,3,6,5,7", offset: "0", search: "")) {
+            var dataGroups: [Group] = []
+            if (response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") == "00") {
+                let data = response.getBody(key: CoreMessage_TMessageKey.DATA)
+                if let json = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: []) as? [[String: Any?]] {
+                    for dataJson in json {
+                        let group = Group(
+                            id: dataJson[CoreMessage_TMessageKey.GROUP_ID] as? String ?? "",
+                            name: dataJson[CoreMessage_TMessageKey.GROUP_NAME] as? String ?? "",
+                            profile: dataJson[CoreMessage_TMessageKey.THUMB_ID] as? String ?? "",
+                            quote: dataJson[CoreMessage_TMessageKey.QUOTE] as? String ?? "",
+                            by: dataJson[CoreMessage_TMessageKey.BLOCK] as? String ?? "",
+                            date: "",
+                            parent: "",
+                            chatId: "",
+                            groupType: "NOTJOINED",
+                            isOpen: dataJson[CoreMessage_TMessageKey.IS_OPEN] as? String ?? "",
+                            official: "0",
+                            isEducation: "")
+                        dataGroups.append(group)
+                    }
+                }
+            }
+            completion(dataGroups)
+        }
+    }
+    
+    private func getGroups(id: String = "", parent: String = "", completion: @escaping ([Group]) -> ()) {
+        DispatchQueue.global().async {
+            Database.shared.database?.inTransaction({ fmdb, rollback in
+                completion(self.getGroupRecursive(fmdb: fmdb, id: id, parent: parent))
+            })
+        }
+    }
+    
+    private func pullBuddy() {
+        if let me = UserDefaults.standard.string(forKey: "me") {
+            DispatchQueue.global().async {
+                let _ = Nexilis.write(message: CoreMessage_TMessageBank.getBatchBuddiesInfos(p_f_pin: me, last_update: 0))
+            }
+        }
+    }
+    
+    private func joinOpenGroup(groupId: String, flagMember: String = "0", completion: @escaping (Bool) -> ()) {
+        DispatchQueue.global().async {
+            var result: Bool = false
+            let idMe = UserDefaults.standard.string(forKey: "me") as String?
+            if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getAddGroupMember(p_group_id: groupId, p_member_pin: idMe!, p_position: "0")), response.isOk() {
+                result = true
+            }
+            completion(result)
+        }
+    }
+
+    @IBOutlet weak var backgroundImage: UIImageView!
+    
+
+    /*
+    // MARK: - Navigation
+
+    // In a storyboard-based application, you will often want to do a little preparation before navigation
+    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        // Get the new view controller using segue.destination.
+        // Pass the selected object to the new view controller.
+    }
+    */
+
+}
+
+// MARK: - Table view data source
+
+extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
+    
+    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        if noData {
+            return
+        }
+        tableView.deselectRow(at: indexPath, animated: true)
+        switch segment.selectedSegmentIndex {
+        case 0:
+            let data: Chat
+            if isFilltering {
+                data = fillteredData[indexPath.row] as! Chat
+            } else {
+                data = chats[indexPath.row]
+            }
+            if let chooser = isChooser {
+                if data.pin == "-999"{
+                    return
+                }
+                chooser(data.messageScope, data.pin)
+                dismiss(animated: true, completion: nil)
+                return
+            }
+            if data.messageScope == "3" {
+                let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
+                editorPersonalVC.hidesBottomBarWhenPushed = true
+                editorPersonalVC.unique_l_pin = data.pin
+                navigationController?.show(editorPersonalVC, sender: nil)
+            } else {
+                let editorGroupVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorGroupVC") as! EditorGroup
+                editorGroupVC.hidesBottomBarWhenPushed = true
+                editorGroupVC.unique_l_pin = data.pin
+                navigationController?.show(editorGroupVC, sender: nil)
+            }
+        case 1:
+            expandCollapseGroup(tableView: tableView, indexPath: indexPath)
+        default:
+            expandCollapseGroup(tableView: tableView, indexPath: indexPath)
+        }
+    }
+    
+    func expandCollapseGroup(tableView: UITableView, indexPath: IndexPath) {
+        let group: Group
+        if isFilltering {
+            if indexPath.row == 0 {
+                group = fillteredData[indexPath.section] as! Group
+            } else {
+                if (fillteredData[indexPath.section] as! Group).childs.count > 0 {
+                    group = (fillteredData[indexPath.section] as! Group).childs[indexPath.row - 1]
+                } else {
+                    return
+                }
+            }
+        } else {
+            if indexPath.row == 0 {
+                group = groups[indexPath.section]
+            } else {
+                group = groups[indexPath.section].childs[indexPath.row - 1]
+            }
+        }
+        if (checkOverrideAction(groupHolder: group)) {
+            return;
+        }
+        group.isSelected = !group.isSelected
+        if !group.isSelected{
+            var sects = 0
+            var sect = indexPath.section
+            var id = group.id
+            if let _ = groupMap[id] {
+                var loooop = true
+                repeat {
+                    let c = sect + 1
+                    if isFilltering {
+                        if let o = self.fillteredData[c] as? Group {
+                            if o.parent == id {
+                                sects = sects + 1
+                                sect = c
+                                id = o.id
+                                (self.fillteredData[c] as! Group).isSelected = false
+                                self.groupMap.removeValue(forKey: (self.fillteredData[c] as! Group).id)
+                            }
+                            else {
+                                loooop = false
+                            }
+                        }
+                    }
+                    else {
+                        if c < self.groups.count && self.groups[c].parent == id {
+                            sects = sects + 1
+                            sect = c
+                            id = self.groups[c].id
+                            self.groups[c].isSelected = false
+                            self.groupMap.removeValue(forKey: self.groups[c].id)
+                        }
+                        else {
+                            loooop = false
+                        }
+                    }
+                } while(loooop)
+            }
+            for i in stride(from: sects, to: 0, by: -1){
+                if isFilltering {
+                    self.fillteredData.remove(at: indexPath.section + i)
+                }
+                else {
+                    self.groups.remove(at: indexPath.section + i)
+                }
+            }
+            groupMap.removeValue(forKey: group.id)
+        }
+        if group.groupType == "NOTJOINED" {
+            let alert = LibAlertController(title: "Do you want to join this group?".localized(), message: "Groups : \(group.name)\nMembers: \(group.by)".localized(), preferredStyle: .alert)
+            alert.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil))
+            alert.addAction(UIAlertAction(title: "Join".localized(), style: .default, handler: {(_) in
+                self.joinOpenGroup(groupId: group.id, completion: { result in
+                    if result {
+                        DispatchQueue.main.async {
+                            self.groupMap.removeAll()
+                            let editorGroupVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorGroupVC") as! EditorGroup
+                            editorGroupVC.hidesBottomBarWhenPushed = true
+                            editorGroupVC.unique_l_pin = group.id
+                            self.navigationController?.show(editorGroupVC, sender: nil)
+                        }
+                    }
+                })
+            }))
+            self.present(alert, animated: true, completion: nil)
+            return
+        }
+        if group.childs.count == 0 {
+            Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                let idMe = UserDefaults.standard.string(forKey: "me") as String?
+                if let cursorMember = Database.shared.getRecords(fmdb: fmdb, query: "select f_pin from GROUPZ_MEMBER where group_id = '\(group.id)' and f_pin = '\(idMe!)'"), cursorMember.next() {
+                    let groupId = group.chatId.isEmpty ? group.id : group.chatId
+                    if let chooser = isChooser {
+                        chooser("4", groupId)
+                        dismiss(animated: true, completion: nil)
+                        return
+                    }
+                    self.groupMap.removeAll()
+                    let editorGroupVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorGroupVC") as! EditorGroup
+                    editorGroupVC.hidesBottomBarWhenPushed = true
+                    editorGroupVC.unique_l_pin = groupId
+                    navigationController?.show(editorGroupVC, sender: nil)
+                    cursorMember.close()
+                } else {
+                    var viewController = UIApplication.shared.windows.first!.rootViewController
+                    if !(viewController is ViewController) {
+                        viewController = self.parent
+                    }
+                    if let viewController = viewController as? ViewController {
+                        viewController.view.makeToast("You are not a member of this group".localized(), duration: 0.5)
+                    }
+                }
+            })
+        } else {
+            if indexPath.row == 0 {
+                tableView.reloadData()
+            } else {
+                getGroups(id: group.id) { g in
+                    DispatchQueue.main.async {
+                        //print("index path section: \(indexPath.section)")
+                        //print("index path row: \(indexPath.row)")
+                        //print("index path item: \(indexPath.item)")
+                        if self.isFilltering {
+//                                self.fillteredData.remove(at: indexPath.section)
+                            if self.fillteredData[indexPath.section] is Group {
+                                self.groupMap[(self.fillteredData[indexPath.section] as! Group).id] = 1
+                                self.fillteredData.insert(contentsOf: g, at: indexPath.section + 1)
+                            }
+                        } else {
+//                                self.groups.remove(at: indexPath.section)
+                            self.groupMap[self.groups[indexPath.section].id] = 1
+                            self.groups.insert(contentsOf: g, at: indexPath.section + 1)
+                        }
+                        //print("groupMap: \(self.groupMap)")
+                        tableView.reloadData()
+                        
+                        self.expandCollapseGroup(tableView: tableView, indexPath: IndexPath(row: 0, section: indexPath.section + 1))
+                    }
+                }
+            }
+        }
+    }
+    
+    func checkOverrideAction(groupHolder: Group) -> Bool {
+        if groupHolder.isLounge {
+            return false
+        }
+        let groupId = groupHolder.chatId.isEmpty ? groupHolder.id : groupHolder.chatId
+        switch (groupId){
+            case "18d1c6cffb70215af7b49" //bpkh konsultasi
+            , "18d1c6e37a20215af7b49"
+            , "18d1c6f852d0215af7b49"
+            , "18d1c6ff83a0215af7b49"
+            , "18d1c705e970215af7b49"
+            , "18d30db3bde0230d00c15" //ina konsultasi bot
+            , "18d30e64ce30230d00c15"
+            , "18d30e9b6d80230d00c15"
+            , "18d30ee00610230d00c15"
+            , "18d30f02f850230d00c15":
+                APIS.openSmartChatbot();
+                return true;
+            case "18d30daa4540230d00c15" //ina cc
+            , "18d30e59a950230d00c15"
+            , "18d30e9292b0230d00c15"
+            , "18d30ed8e250230d00c15"
+            , "18d30efa66c0230d00c15"
+            , "18d35b220540215af7b49" //bpkhcc
+            , "18d35b2f5ee0215af7b49"
+            , "18d35b356530215af7b49"
+            , "18d35b411510215af7b49"
+            , "18d35b46ae90215af7b49":
+                APIS.openContactCenter();
+                return true;
+            case "18d1c6d9f330215af7b49": //bpkh haji
+                Nexilis.openUrl(url: Utils.decrypt(str: "6]tov!l_opgn=hgz?ykmgv?yoro3kt?uo>yoro3kt??@yvzzn"))
+                return true;
+            case "18d1c6eefd40215af7b49": //bpkh bpjs
+                Nexilis.openUrl(url: Utils.decrypt(str: "1>ojq`g@tkqc.cbu:tfhbq:tjmjyfo:pj/tjmjyfo::;tquui"))
+                return true;
+            case "18d30e711c20230d00c15": //ina bpjs
+                Nexilis.openUrl(url: Utils.decrypt(str: "6]tov!l_ypvh=hgz?ykmgv?yoro3kt?sui>ykrgyomojrkyz??@yvzzn"))
+                return true;
+            case "18d30e47ae60230d00c15": //ina KTP, KK, SKL
+                Nexilis.openUrl(url: Utils.decrypt(str: "1>ojq`g@qul.cbu:tfhbq:tjmjyfo:npd/tfmbtjhjemftu::;tquui"))
+                return true;
+            case "18d30eb2e910230d00c15": //SIM, SKKB, SKBN
+                Nexilis.openUrl(url: Utils.decrypt(str: "4[rmt}j]qmw;fex=wiket=wmpm1ir=qsg<wipewmkmhpiwx==>wtxxl"))
+                return true;
+            case "18da1c0200f0215af7b49": //BPKH index BMI
+                Nexilis.openUrl(url: Utils.decrypt(str: "4[rmt}j]mqf}1ihrm=mqf=wmpm1ir=sm<wmpm1ir==>wtxxl"))
+                return true;
+            default:
+                break;
+        }
+        return false
+    }
+    
+    func numberOfSections(in tableView: UITableView) -> Int {
+        if isFilltering {
+            if segment.selectedSegmentIndex == 1 {
+                return fillteredData.count
+            }
+            return 1
+        } else {
+            if segment.selectedSegmentIndex == 1 {
+                return groups.count
+            }
+            return 1
+        }
+    }
+    
+    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+        var value = 0
+        if isFilltering {
+            if segment.selectedSegmentIndex == 1, let groups = fillteredData as? [Group] {
+                let group = groups[section]
+                if group.isSelected {
+                    if let _ = groupMap[group.id] {
+                        value = 1
+                    }
+                    else {
+                        value = group.childs.count + 1
+                    }
+                } else {
+                    value = 1
+                }
+            } else {
+                value = fillteredData.count
+            }
+            return value
+        }
+        switch segment.selectedSegmentIndex {
+        case 0:
+            value = chats.count
+        case 1:
+            let group = groups[section]
+            if group.isSelected {
+                if let _ = groupMap[group.id] {
+                    value = 1
+                }
+                else {
+                    value = group.childs.count + 1
+                }
+            } else {
+                value = 1
+            }
+        default:
+            value = chats.count
+        }
+        if value == 0 {
+            noData = true
+            value = 1
+            tableView.separatorStyle = .none
+        } else {
+            noData = false
+            tableView.separatorStyle = .singleLine
+        }
+        return value
+    }
+    
+    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        var cell: UITableViewCell!
+        switch segment.selectedSegmentIndex {
+        case 0:
+            cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifierChat", for: indexPath)
+            let content = cell.contentView
+            if content.subviews.count > 0 {
+                content.subviews.forEach { $0.removeFromSuperview() }
+            }
+            if noData {
+                let labelNochat = UILabel()
+                labelNochat.text = "There are no conversations".localized()
+                labelNochat.font = .systemFont(ofSize: 13)
+                labelNochat.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
+                content.addSubview(labelNochat)
+                labelNochat.anchor(centerX: content.centerXAnchor, centerY: content.centerYAnchor)
+                cell.backgroundColor = .clear
+                cell.selectionStyle = .none
+                return cell
+            }
+            let data: Chat
+            if isFilltering {
+                data = fillteredData[indexPath.row] as! Chat
+            } else {
+                if chats.count == 0 {
+                    let labelNochat = UILabel()
+                    labelNochat.text = "There are no conversations".localized()
+                    labelNochat.font = .systemFont(ofSize: 13)
+                    labelNochat.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
+                    content.addSubview(labelNochat)
+                    labelNochat.anchor(centerX: content.centerXAnchor, centerY: content.centerYAnchor)
+                    cell.backgroundColor = .clear
+                    cell.selectionStyle = .none
+                    return cell
+                }
+                data = chats[indexPath.row]
+            }
+            let imageView = UIImageView()
+            content.addSubview(imageView)
+            imageView.translatesAutoresizingMaskIntoConstraints = false
+            NSLayoutConstraint.activate([
+                imageView.leadingAnchor.constraint(equalTo: content.leadingAnchor, constant: 10.0),
+                imageView.topAnchor.constraint(equalTo: content.topAnchor, constant: 10.0),
+                imageView.bottomAnchor.constraint(equalTo: content.bottomAnchor, constant: -10.0),
+                imageView.widthAnchor.constraint(equalToConstant: 55.0),
+                imageView.heightAnchor.constraint(equalToConstant: 55.0)
+            ])
+            if data.profile.isEmpty && data.pin != "-999" {
+                if data.messageScope == "3" {
+                    imageView.image = UIImage(named: "Profile---Purple", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
+                } else {
+                    imageView.image = UIImage(named: "Conversation---Purple", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
+                }
+            } else {
+                getImage(name: data.profile, placeholderImage: UIImage(named: data.pin == "-999" ? "pb_button" : data.messageScope == "3" ? "Profile---Purple" : "Conversation---Purple", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), isCircle: true, tableView: tableView, indexPath: indexPath, completion: { result, isDownloaded, image in
+                    imageView.image = image
+                })
+            }
+            let titleView = UILabel()
+            content.addSubview(titleView)
+            titleView.translatesAutoresizingMaskIntoConstraints = false
+            NSLayoutConstraint.activate([
+                titleView.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: 10.0),
+                titleView.topAnchor.constraint(equalTo: content.topAnchor, constant: 10.0),
+                titleView.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -40.0),
+            ])
+            titleView.text = data.name
+            titleView.font = UIFont.systemFont(ofSize: 14, weight: .medium)
+            
+            let messageView = UILabel()
+            content.addSubview(messageView)
+            messageView.translatesAutoresizingMaskIntoConstraints = false
+            NSLayoutConstraint.activate([
+                messageView.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: 10.0),
+                messageView.topAnchor.constraint(equalTo: titleView.bottomAnchor, constant: 5.0),
+                messageView.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -40.0),
+            ])
+            messageView.textColor = .gray
+            if data.messageText.contains("■") {
+                data.messageText = data.messageText.components(separatedBy: "■")[0]
+                data.messageText = data.messageText.trimmingCharacters(in: .whitespacesAndNewlines)
+            }
+            let text = Utils.previewMessageText(chat: data)
+            let idMe = UserDefaults.standard.string(forKey: "me") as String?
+            if let attributeText = text as? NSMutableAttributedString {
+                let stringMessage = NSMutableAttributedString(string: "")
+                if data.fpin == idMe {
+                    if data.lock == "1" {
+                        if data.messageScope == "4" {
+                            stringMessage.append(NSAttributedString(string: "You".localized() + ": ", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12, weight: .medium)]))
+                        }
+                        stringMessage.append(("🚫 _"+"You were deleted this message".localized()+"_").richText())
+                    } else {
+                        let imageStatus = NSTextAttachment()
+                        let status = getRealStatus(messageId: data.messageId)
+                        if status == "0" {
+                            imageStatus.image = UIImage(systemName: "xmark.circle")!.withTintColor(UIColor.red, renderingMode: .alwaysOriginal)
+                        } else if status == "1" {
+                            imageStatus.image = UIImage(systemName: "clock.arrow.circlepath")!.withTintColor(UIColor.lightGray, renderingMode: .alwaysOriginal)
+                        } else if status == "2" {
+                            imageStatus.image = UIImage(named: "checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.lightGray)
+                        } else if (status == "3") {
+                            imageStatus.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.lightGray)
+                        } else if (status == "8") {
+                            imageStatus.image = UIImage(named: "message_status_ack", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal)
+                        } else {
+                            imageStatus.image = UIImage(named: "double-checklist", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(UIColor.systemBlue)
+                        }
+                        imageStatus.bounds = CGRect(x: 0, y: -2, width: 15, height: 15)
+                        let imageStatusString = NSAttributedString(attachment: imageStatus)
+                        stringMessage.append(imageStatusString)
+                        stringMessage.append(NSAttributedString(string: " "))
+                        if data.messageScope == "4" {
+                            stringMessage.append(NSAttributedString(string: "You".localized() + ": ", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12, weight: .medium)]))
+                        }
+                        stringMessage.append(attributeText)
+                    }
+                } else {
+                    if data.messageScope == "4" {
+                        stringMessage.append(NSAttributedString(string: User.getData(pin: data.fpin)!.firstName + ": ", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12, weight: .medium)]))
+                    }
+                    if data.lock == "1" {
+                        stringMessage.append(("🚫 _"+"This message was deleted".localized()+"_").richText())
+                    } else {
+                        stringMessage.append(attributeText)
+                    }
+                }
+                messageView.attributedText = stringMessage
+            }
+            messageView.numberOfLines = 2
+            
+            let timeView = UILabel()
+            content.addSubview(timeView)
+            timeView.translatesAutoresizingMaskIntoConstraints = false
+            NSLayoutConstraint.activate([
+                timeView.topAnchor.constraint(equalTo: content.topAnchor, constant: 10.0),
+                timeView.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -20.0),
+            ])
+            timeView.textColor = .gray
+            timeView.font = UIFont.systemFont(ofSize: 14)
+            
+            let date = Date(milliseconds: Int64(data.serverDate)!)
+            let calendar = Calendar.current
+            
+            if (calendar.isDateInToday(date)) {
+                let formatter = DateFormatter()
+                formatter.dateFormat = "HH:mm"
+                formatter.locale = NSLocale(localeIdentifier: "id") as Locale?
+                timeView.text = formatter.string(from: date as Date)
+            } else {
+                let startOfNow = calendar.startOfDay(for: Date())
+                let startOfTimeStamp = calendar.startOfDay(for: date)
+                let components = calendar.dateComponents([.day], from: startOfNow, to: startOfTimeStamp)
+                let day = -(components.day!)
+                if day == 1 {
+                    timeView.text = "Yesterday".localized()
+                } else {
+                    if day < 7 {
+                        let formatter = DateFormatter()
+                        formatter.dateFormat = "EEEE"
+                        let lang = UserDefaults.standard.string(forKey: "i18n_language")
+                        if lang == "id" {
+                            formatter.locale = NSLocale(localeIdentifier: "id") as Locale?
+                        }
+                        timeView.text = formatter.string(from: date)
+                    } else {
+                        let formatter = DateFormatter()
+                        formatter.dateFormat = "M/dd/yy"
+                        formatter.locale = NSLocale(localeIdentifier: "id") as Locale?
+                        let stringFormat = formatter.string(from: date as Date)
+                        timeView.text = stringFormat
+                    }
+                }
+            }
+            
+            if data.counter != "0" {
+                timeView.textColor = .systemRed
+                let viewCounter = UIView()
+                content.addSubview(viewCounter)
+                viewCounter.translatesAutoresizingMaskIntoConstraints = false
+                NSLayoutConstraint.activate([
+                    viewCounter.topAnchor.constraint(equalTo: timeView.bottomAnchor, constant: 5.0),
+                    viewCounter.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -20),
+                    viewCounter.widthAnchor.constraint(greaterThanOrEqualToConstant: 20),
+                    viewCounter.heightAnchor.constraint(equalToConstant: 20)
+                ])
+                viewCounter.backgroundColor = .systemRed
+                viewCounter.layer.cornerRadius = 10
+                viewCounter.clipsToBounds = true
+                viewCounter.layer.borderWidth = 0.5
+                viewCounter.layer.borderColor = UIColor.secondaryColor.cgColor
+
+                let labelCounter = UILabel()
+                viewCounter.addSubview(labelCounter)
+                labelCounter.translatesAutoresizingMaskIntoConstraints = false
+                NSLayoutConstraint.activate([
+                    labelCounter.centerYAnchor.constraint(equalTo: viewCounter.centerYAnchor),
+                    labelCounter.leadingAnchor.constraint(equalTo: viewCounter.leadingAnchor, constant: 2),
+                    labelCounter.trailingAnchor.constraint(equalTo: viewCounter.trailingAnchor, constant: -2),
+                ])
+                labelCounter.font = UIFont.systemFont(ofSize: 11)
+                if Int(data.counter)! > 99 {
+                    labelCounter.text = "99+"
+                } else {
+                    labelCounter.text = data.counter
+                }
+                labelCounter.textColor = .secondaryColor
+                labelCounter.textAlignment = .center
+            }
+        case 1:
+            cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifierGroup", for: indexPath)
+            var content = cell.defaultContentConfiguration()
+            content.textProperties.font = UIFont.systemFont(ofSize: 14)
+            let group: Group
+            if isFilltering {
+                if indexPath.row == 0 {
+                    group = fillteredData[indexPath.section] as! Group
+                } else {
+                    if (fillteredData[indexPath.section] as! Group).childs.count > 0 {
+                        group = (fillteredData[indexPath.section] as! Group).childs[indexPath.row - 1]
+                    } else {
+                        return cell
+                    }
+                }
+            } else {
+                if indexPath.row == 0 {
+                    if indexPath.section > (groups.count - 1) {
+                        return cell
+                    }
+                    group = groups[indexPath.section]
+                } else {
+                    group = groups[indexPath.section].childs[indexPath.row - 1]
+                }
+            }
+            if group.official == "1" && group.parent == "" {
+                content.attributedText = self.set(image: UIImage(named: "ic_official_flag", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, with: "  \(group.name)", size: 15, y: -4, colorText: self.traitCollection.userInterfaceStyle == .dark ? .white : .black)
+            }
+            else if group.isOpen == "1" && group.parent == "" {
+                if self.traitCollection.userInterfaceStyle == .dark {
+                    content.attributedText = self.set(image: UIImage(systemName: "globe")!.withTintColor(.white), with: "  \(group.name)", size: 15, y: -4, colorText: self.traitCollection.userInterfaceStyle == .dark ? .white : .black)
+                } else {
+                    content.attributedText = self.set(image: UIImage(systemName: "globe")!, with: "  \(group.name)", size: 15, y: -4, colorText: self.traitCollection.userInterfaceStyle == .dark ? .white : .black)
+                }
+            } else if group.parent == "" {
+                if self.traitCollection.userInterfaceStyle == .dark {
+                    content.attributedText = self.set(image: UIImage(systemName: "lock.fill")!.withTintColor(.white), with: "  \(group.name)", size: 15, y: -4, colorText: self.traitCollection.userInterfaceStyle == .dark ? .white : .black)
+                } else {
+                    content.attributedText = self.set(image: UIImage(systemName: "lock.fill")!, with: "  \(group.name)", size: 15, y: -4, colorText: self.traitCollection.userInterfaceStyle == .dark ? .white : .black)
+                }
+            } else {
+                content.text = group.name
+            }
+            if group.childs.count > 0 {
+                let iconName = (group.isSelected) ? "chevron.up.circle" : "chevron.down.circle"
+                let imageView = UIImageView(image: UIImage(systemName: iconName))
+                imageView.tintColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
+                cell.accessoryView = imageView
+            }
+            else {
+                cell.accessoryView = nil
+                cell.accessoryType = .none
+            }
+            content.imageProperties.maximumSize = CGSize(width: 40, height: 40)
+            getImage(name: group.profile, placeholderImage: UIImage(named: "Conversation---Purple", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), isCircle: true, tableView: tableView, indexPath: indexPath) { result, isDownloaded, image in
+                content.image = image
+            }
+            cell.contentConfiguration = content
+            if !group.level.isEmpty {
+                if group.level != "-1" && Int(group.level)! < 7 {
+                    cell.contentView.layoutMargins = .init(top: 0.0, left: CGFloat(25 * Int(group.level)!), bottom: 0.0, right: 0)
+                } else if Int(group.level)! > 6 {
+                    cell.contentView.layoutMargins = .init(top: 0.0, left: CGFloat(25 * (Int(group.level)! - 6)), bottom: 0.0, right: 0)
+                }
+            }
+        default:
+            cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifierContact", for: indexPath)
+            var content = cell.defaultContentConfiguration()
+            content.text = ""
+            cell.contentConfiguration = content
+        }
+        cell.backgroundColor = .clear
+        cell.separatorInset = UIEdgeInsets(top: 0, left: 60.0, bottom: 0, right: 0)
+        return cell
+    }
+    
+    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+        return 75.0
+    }
+    
+    private func getRealStatus(messageId: String) -> String {
+        var status = "1"
+        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+            if let cursorStatus = Database.shared.getRecords(fmdb: fmdb, query: "SELECT status, f_pin FROM MESSAGE_STATUS WHERE message_id='\(messageId)'") {
+                var listStatus: [Int] = []
+                while cursorStatus.next() {
+                    listStatus.append(Int(cursorStatus.string(forColumnIndex: 0)!)!)
+                }
+                cursorStatus.close()
+                status = "\(listStatus.min() ?? 2)"
+            }
+        })
+        return status
+    }
+    
+}
+
+
+extension SecondTabViewController: UISearchControllerDelegate, UISearchBarDelegate, UISearchResultsUpdating {
+    
+    func updateSearchResults(for searchController: UISearchController) {
+        filterContentForSearchText(searchController.searchBar.text!.trimmingCharacters(in: .whitespacesAndNewlines))
+    }
+    
+    func searchBarBookmarkButtonClicked(_ searchBar: UISearchBar) {
+        recordAudio()
+    }
+    
+    func set(image: UIImage, with text: String, size: CGFloat, y: CGFloat, colorText: UIColor = UIColor.black) -> NSAttributedString {
+        let attachment = NSTextAttachment()
+        attachment.image = image
+        attachment.bounds = CGRect(x: 0, y: y, width: size, height: size)
+        let attachmentStr = NSAttributedString(attachment: attachment)
+        
+        let mutableAttributedString = NSMutableAttributedString()
+        mutableAttributedString.append(attachmentStr)
+        
+        let attributedStringColor = [NSAttributedString.Key.foregroundColor : colorText]
+        let textString = NSAttributedString(string: text, attributes: attributedStringColor)
+        mutableAttributedString.append(textString)
+        
+        
+        return mutableAttributedString
+    }
+    
+    func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
+        searchBar.showsCancelButton = true
+        let cBtn = searchBar.value(forKey: "cancelButton") as! UIButton
+        cBtn.setTitle("Cancel".localized(), for: .normal)
+    }
+    
+    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
+        searchBar.showsCancelButton = false
+    }
+    
+}
+
+extension SecondTabViewController: SFSpeechRecognizerDelegate {
+
+    func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
+        if available {
+            self.isAllowSpeech = true
+        } else {
+            self.isAllowSpeech = false
+        }
+    }
+}

+ 617 - 0
AppBuilder/AppBuilder/ThirdTabViewController.swift

@@ -0,0 +1,617 @@
+//
+//  ThirdTabViewController.swift
+//  AppBuilder
+//
+//  Created by Kevin Maulana on 30/03/22.
+//
+
+import UIKit
+import WebKit
+import NexilisLite
+import Speech
+
+class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureRecognizerDelegate, WKNavigationDelegate, WKScriptMessageHandler  {
+
+    var webView: WKWebView!
+    var address = ""
+    private var lastContentOffset: CGFloat = 0
+    
+    var isAllowSpeech = false
+    
+    var speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en"))
+
+    var recognitionRequest : SFSpeechAudioBufferRecognitionRequest?
+    var recognitionTask : SFSpeechRecognitionTask?
+    let audioEngine = AVAudioEngine()
+    var alertController = LibAlertController()
+    
+    var dateRefresh: Date?
+    public static var forceRefresh = false
+    public static var inView = false
+    public static var atFirstPage = true
+    public static var showModal = false
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        
+        self.view.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .black : .white
+        
+        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(collapseDocked))
+        tapGesture.cancelsTouchesInView = false
+        tapGesture.delegate = self
+        let configuration = WKWebViewConfiguration()
+        configuration.allowsInlineMediaPlayback = true
+        let customUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1 \(Utils.getUserAgent())"
+        let finalUserAgent = "\(customUserAgent)"
+        configuration.applicationNameForUserAgent = finalUserAgent
+        webView = WKWebView(frame: .zero, configuration: configuration)
+        view.addSubview(webView)
+        webView.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
+            webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
+            webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
+            webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
+        ])
+        webView.scrollView.addGestureRecognizer(tapGesture)
+        let refreshControl = UIRefreshControl()
+        refreshControl.addTarget(self, action: #selector(reloadWebView(_:)), for: .valueChanged)
+        webView.scrollView.addSubview(refreshControl)
+        webView.scrollView.delegate = self
+        webView.navigationDelegate = self
+        webView.allowsBackForwardNavigationGestures = true
+        
+        let contentController = self.webView.configuration.userContentController
+        contentController.add(self, name: "checkProfile")
+        contentController.add(self, name: "setIsProductModalOpen")
+        contentController.add(self, name: "toggleVoiceSearch")
+        contentController.add(self, name: "blockUser")
+        contentController.add(self, name: "showAlert")
+        contentController.add(self, name: "closeProfile")
+        contentController.add(self, name: "tabShowHide")
+        
+        let source: String = "var meta = document.createElement('meta');" +
+            "meta.name = 'viewport';" +
+            "meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no';" +
+            "var head = document.getElementsByTagName('head')[0];" +
+            "head.appendChild(meta);" +
+        "$('#header-layout').find('.col-8').removeClass('col-8').addClass('col');" +
+        "$('#header-layout').find('.col-4').removeClass('col-4').addClass('col');"
+        let script: WKUserScript = WKUserScript(source: source, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
+        contentController.addUserScript(script)
+        
+        let cookieScript1 = "document.cookie = '\(Utils.getCookiesMobile().components(separatedBy: ";")[0])';"
+        let cookieScriptInjection1 = WKUserScript(source: cookieScript1, injectionTime: .atDocumentStart, forMainFrameOnly: false)
+        configuration.userContentController.addUserScript(cookieScriptInjection1)
+        
+        let cookieScript2 = "document.cookie = '\(Utils.getCookiesMobile().components(separatedBy: ";")[1])';"
+        let cookieScriptInjection2 = WKUserScript(source: cookieScript2, injectionTime: .atDocumentStart, forMainFrameOnly: false)
+        configuration.userContentController.addUserScript(cookieScriptInjection2)
+        
+        NotificationCenter.default.addObserver(self, selector: #selector(onShowAC(notification:)), name: NSNotification.Name(rawValue: "onShowAC"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onRefreshWebView(notification:)), name: NSNotification.Name(rawValue: "onRefreshWebView"), object: nil)
+    }
+    
+    func loadURLWithCookie(url: URL) {
+        var urlRequest = URLRequest(url: url)
+        // Setting cookies
+        let cookieHeader = Utils.getCookiesMobile()
+        urlRequest.addValue(cookieHeader, forHTTPHeaderField: "Cookie")
+        
+        // Setting user agent
+        let customUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1 \(Utils.getUserAgent())"
+        urlRequest.setValue(customUserAgent, forHTTPHeaderField: "User-Agent")
+        webView.load(urlRequest)
+    }
+    
+    override func viewWillAppear(_ animated: Bool) {
+        if ThirdTabViewController.inView {
+           return
+        }
+        ThirdTabViewController.inView = true
+        let me = UserDefaults.standard.string(forKey: "me")
+        
+        var myURL : URL?
+        let lang = UserDefaults.standard.string(forKey: "i18n_language")
+        var intLang = 0
+        if lang == "id" {
+            speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "id"))
+            intLang = 1
+        }
+        if PrefsUtil.getURLThirdTab() != nil {
+            ViewController.tab3 = PrefsUtil.getURLThirdTab()!
+        }
+        switch(ViewController.tab3){
+        case "0":
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main-only?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
+            myURL = URL(string: address)
+        case "1":
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-main-only?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
+            myURL = URL(string: address)
+        case "2":
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
+            myURL = URL(string: address)
+        case "3":
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-commerce?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
+            myURL = URL(string: address)
+        case "4":
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-video?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
+            myURL = URL(string: address)
+        default:
+            if(!ViewController.tab3.isEmpty){
+                if(ViewController.tab3.lowercased().contains("https://") || ViewController.sURL.lowercased().contains("http://")){
+                    address = ViewController.tab3
+                    myURL = URL(string: address)
+                }
+                else {
+                    if ViewController.tab3.contains("nexilis/pages"){
+                        address = "\(PrefsUtil.getURLBase())\(ViewController.tab3)?f_pin=\(me ?? "")&lang=\(intLang)&theme=\(self.traitCollection.userInterfaceStyle == .dark ? "0" : "1")"
+                    } else {
+                        address = "https://\(ViewController.tab3)"
+                    }
+                    myURL = URL(string: address)
+                }
+            }
+        }
+        //print(address)
+        if let u = myURL{
+            self.webView.evaluateJavaScript("{window.localStorage.setItem('currentTab','\(ViewController.tab3)')}")
+            if ((dateRefresh == nil || Int(Date().timeIntervalSince(dateRefresh!)) >= 60) && ThirdTabViewController.atFirstPage) || ThirdTabViewController.forceRefresh {
+//                let myRequest = URLRequest(url: u)
+//                let myRequest = URLRequest(url: u)
+                loadURLWithCookie(url: u)
+            } else {
+                self.webView.evaluateJavaScript("if(resumeAll){resumeAll();}")
+            }
+            dateRefresh = Date()
+            ThirdTabViewController.forceRefresh = false
+        }
+        navigationController?.setNavigationBarHidden(true, animated: false)
+    }
+    
+    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
+        if Utils.getIsLoadThemeFromOther() {
+            self.webView.evaluateJavaScript("{window.localStorage.setItem('mobileConfiguration','"+Utils.getMyTheme()+"')}")
+        }
+    }
+    
+    override func viewDidAppear(_ animated: Bool) {
+        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
+//            if (self.isUsingMyWebview() && self.webView.url != nil && !self.webView.url!.absoluteString.contains("nexilis/pages/tab1-main-only") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab3-main-only") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab1-main") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab3-commerce") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab1-video") && !self.webView.url!.absoluteString.contains("nexilis/pages/tab3-main")) || ThirdTabViewController.showModal {
+//                ViewController.alwaysHideButton = true
+//                self.hideTabBar()
+//                ThirdTabViewController.atFirstPage = false
+//            } else {
+                var viewController = UIApplication.shared.windows.first!.rootViewController
+                if !(viewController is ViewController) {
+                    viewController = self.parent
+                }
+                if ViewController.middleButton.isHidden {
+                    ViewController.isExpandButton = false
+                    if let viewController = viewController as? ViewController {
+                        if viewController.tabBar.isHidden {
+                            viewController.tabBar.isHidden = false
+                            ViewController.middleButton.isHidden = false
+                            ViewController.alwaysHideButton = false
+                        }
+                    }
+                } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
+                    DispatchQueue.main.async {
+                        if let viewController = viewController as? ViewController {
+                            if viewController.tabBar.isHidden {
+                                viewController.tabBar.isHidden = false
+                                ViewController.alwaysHideButton = false
+                            }
+                        }
+                    }
+                }
+//            }
+        })
+    }
+    
+    @objc func onShowAC(notification: NSNotification) {
+        self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+        view.endEditing(true)
+        resignFirstResponder()
+    }
+    
+    @objc func onRefreshWebView(notification: NSNotification) {
+        ThirdTabViewController.forceRefresh = true
+    }
+    
+    override func viewWillDisappear(_ animated: Bool) {
+        if self.webView.scrollView.contentOffset.y < 0 { // Move tableView to top
+            self.webView.scrollView.setContentOffset(CGPoint.zero, animated: true)
+        }
+        self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+        view.endEditing(true)
+        resignFirstResponder()
+        ThirdTabViewController.inView = false
+        self.webView.evaluateJavaScript("hideAddToCart();")
+    }
+    
+    func scrollViewDidScroll(_ scrollView: UIScrollView) {
+        if (self.lastContentOffset > scrollView.contentOffset.y && scrollView.contentOffset.y < (scrollView.contentSize.height - scrollView.frame.size.height)) {
+            showTabBar();
+        }
+        else if (self.lastContentOffset != 0 && self.lastContentOffset < scrollView.contentOffset.y && self.lastContentOffset >= 0) {
+            hideTabBar();
+        }
+        self.lastContentOffset = scrollView.contentOffset.y
+        self.collapseDocked()
+    }
+
+    
+    @objc func collapseDocked() {
+        if ViewController.isExpandButton {
+            ViewController.expandButton()
+        }
+    }
+    
+    @objc func reloadWebView(_ sender: UIRefreshControl) {
+        webView.reload()
+        sender.endRefreshing()
+    }
+
+    func hideTabBar() {
+        var viewController = UIApplication.shared.windows.first!.rootViewController
+        if !(viewController is ViewController) {
+            viewController = self.parent
+        }
+        if ViewController.middleButton.isDescendant(of: viewController!.view) {
+            DispatchQueue.main.async {
+                if ViewController.isExpandButton {
+                    ViewController.expandButton()
+                }
+                ViewController.hideDockedButton()
+                if let viewController = viewController as? ViewController {
+                    viewController.tabBar.isHidden = true
+                }
+                ViewController.removeMiddleButton()
+            }
+        } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
+            DispatchQueue.main.async {
+                if let viewController = viewController as? ViewController {
+                    if !viewController.tabBar.isHidden {
+                        viewController.tabBar.isHidden = true
+                    }
+                }
+            }
+        }
+    }
+
+    func showTabBar() {
+        if(ViewController.alwaysHideButton){
+            return
+        }
+        var viewController = UIApplication.shared.windows.first!.rootViewController
+        if !(viewController is ViewController) {
+            viewController = self.parent
+        }
+        if ViewController.middleButton.isHidden {
+            if let viewController = viewController as? ViewController {
+                viewController.tabBar.isHidden = false
+                ViewController.middleButton.isHidden = false
+            }
+        } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
+            DispatchQueue.main.async {
+                if let viewController = viewController as? ViewController {
+                    if viewController.tabBar.isHidden {
+                        viewController.tabBar.isHidden = false
+                    }
+                }
+            }
+        }
+    }
+
+    func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
+        scrollView.pinchGestureRecognizer?.isEnabled = false
+    }
+
+
+    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
+        if message.name == "checkProfile" {
+            guard let dict = message.body as? [String: AnyObject],
+                  let param1 = dict["param1"] as? String,
+                  let param2 = dict["param2"] as? String else {
+                return
+            }
+            if ViewController.checkIsChangePerson() {
+                if param2 == "like" {
+                    self.webView.evaluateJavaScript("likeProduct('\(param1)',1,true);")
+                } else if param2 == "comment" {
+                    self.webView.evaluateJavaScript("openComment('\(param1.split(separator: "|")[0])',\(param1.split(separator: "|")[1]),true);")
+                } else if param2 == "report_user" {
+                    self.webView.evaluateJavaScript("reportUser('\(param1)',true);")
+                } else if param2 == "report_content" {
+                    self.webView.evaluateJavaScript("reportContent('\(param1.split(separator: "|")[0])','\(param1.split(separator: "|")[1])',true);")
+                } else if param2 == "block_user" {
+                    self.webView.evaluateJavaScript("blockUser('\(param1)',true);")
+                } else if param2 == "follow_user" {
+                    self.webView.evaluateJavaScript("followUser('\(param1.split(separator: "|")[0])',\(param1.split(separator: "|")[1]),true);")
+                } else if param2 == "homepage" || param2 == "gif" {
+                    self.webView.evaluateJavaScript("window.location.href = '\(param1)';")
+                } else if param2 == "block_content" {
+                    self.webView.evaluateJavaScript("blockContent('\(param1)',true);")
+                } else {
+                    self.webView.evaluateJavaScript("openNewPost(true);")
+                }
+            } else {
+                self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+            }
+        } else if message.name == "setIsProductModalOpen" {
+            guard let dict = message.body as? [String: AnyObject],
+                  let param1 = dict["param1"] as? Bool else {
+                return
+            }
+            if param1 {
+                if self.webView.scrollView.contentOffset.y < 0 { // Move tableView to top
+                    self.webView.scrollView.setContentOffset(CGPoint.zero, animated: true)
+                }
+            }
+            ThirdTabViewController.showModal = param1
+        } else if message.name == "toggleVoiceSearch" {
+            if !isAllowSpeech {
+                setupSpeech()
+            } else {
+                runVoice()
+            }
+        } else if message.name == "blockUser" {
+            guard let dict = message.body as? [String: AnyObject],
+                  let param1 = dict["param1"] as? String,
+                  let param2 = dict["param2"] as? Bool else {
+                return
+            }
+            if param2 {
+                DispatchQueue.global().async {
+                    if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getBlock(l_pin: param1)) {
+                        if response.isOk() {
+                            DispatchQueue.main.async {
+                                Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                                    _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
+                                        "ex_block" : "1"
+                                    ], _where: "f_pin = '\(param1)'")
+                                })
+                            }
+                        }
+                    }
+                }
+            } else {
+                DispatchQueue.global().async {
+                    if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getUnBlock(l_pin: param1)) {
+                        if response.isOk() {
+                            DispatchQueue.main.async {
+                                Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                                    _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
+                                        "ex_block" : "0"
+                                    ], _where: "f_pin = '\(param1)'")
+                                })
+                            }
+                        }
+                    }
+                }
+            }
+        } else if message.name == "showAlert" {
+            guard let dict = message.body as? [String: AnyObject],
+                  let param1 = dict["param1"] as? String else {
+                return
+            }
+            showToast(message: param1, controller: self.tabBarController!)
+        } else if message.name == "blockUser" {
+            guard let dict = message.body as? [String: AnyObject],
+                  let param1 = dict["param1"] as? String,
+                  let param2 = dict["param2"] as? Bool else {
+                return
+            }
+            if param2 {
+                DispatchQueue.global().async {
+                    if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getBlock(l_pin: param1)) {
+                        if response.isOk() {
+                            DispatchQueue.main.async {
+                                Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                                    _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
+                                        "ex_block" : "1"
+                                    ], _where: "f_pin = '\(param1)'")
+                                })
+                            }
+                        }
+                    }
+                }
+            } else {
+                DispatchQueue.global().async {
+                    if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getUnBlock(l_pin: param1)) {
+                        if response.isOk() {
+                            DispatchQueue.main.async {
+                                Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                                    _ = Database.shared.updateRecord(fmdb: fmdb, table: "BUDDY", cvalues: [
+                                        "ex_block" : "0"
+                                    ], _where: "f_pin = '\(param1)'")
+                                })
+                            }
+                        }
+                    }
+                }
+            }
+        } else if message.name == "tabShowHide" {
+            guard let dict = message.body as? [String: AnyObject],
+                  let param1 = dict["param1"] as? Bool else {
+                return
+            }
+            if param1 {
+                ViewController.alwaysHideButton = false
+                showTabBar()
+            } else {
+                if self.viewIfLoaded?.window != nil {
+                    ViewController.alwaysHideButton = true
+                    hideTabBar()
+                }
+            }
+        }
+    }
+    
+    func setupSpeech() {
+
+        self.speechRecognizer?.delegate = self
+
+        SFSpeechRecognizer.requestAuthorization { (authStatus) in
+
+            var isButtonEnabled = false
+
+            switch authStatus {
+            case .authorized:
+                isButtonEnabled = true
+
+            case .denied:
+                isButtonEnabled = false
+                //print("User denied access to speech recognition")
+
+            case .restricted:
+                isButtonEnabled = false
+                //print("Speech recognition restricted on this device")
+
+            case .notDetermined:
+                isButtonEnabled = false
+                //print("Speech recognition not yet authorized")
+            @unknown default:
+                isButtonEnabled = false
+            }
+
+            OperationQueue.main.addOperation() {
+                self.isAllowSpeech = isButtonEnabled
+                if isButtonEnabled {
+                    UserDefaults.standard.set(isButtonEnabled, forKey: "allowSpeech")
+                    self.runVoice()
+                }
+            }
+        }
+    }
+    
+    func runVoice() {
+        if !audioEngine.isRunning {
+            alertController = LibAlertController(title: "Start Recording".localized(), message: "Say something, I'm listening!".localized(), preferredStyle: .alert)
+            self.present(alertController, animated: true)
+            self.webView.evaluateJavaScript("toggleVoiceButton(true)")
+            self.startRecording()
+        }
+    }
+    
+    func startRecording() {
+
+        // Clear all previous session data and cancel task
+        if recognitionTask != nil {
+            recognitionTask?.cancel()
+            recognitionTask = nil
+        }
+
+        // Create instance of audio session to record voice
+        let audioSession = AVAudioSession.sharedInstance()
+        do {
+            try audioSession.setCategory(AVAudioSession.Category.record, mode: .default, options: [])
+            try audioSession.setMode(AVAudioSession.Mode.measurement)
+            try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
+        } catch {
+            //print("audioSession properties weren't set because of an error.")
+        }
+
+        self.recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
+
+        let inputNode = audioEngine.inputNode
+
+        guard let recognitionRequest = recognitionRequest else {
+            fatalError("Unable to create an SFSpeechAudioBufferRecognitionRequest object")
+        }
+
+        recognitionRequest.shouldReportPartialResults = true
+
+        self.recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { (result, error) in
+
+            var isFinal = false
+            var text = ""
+
+            if result != nil {
+                text = result?.bestTranscription.formattedString ?? ""
+                isFinal = (result?.isFinal)!
+                self.alertController.dismiss(animated: true)
+                self.audioEngine.stop()
+                self.recognitionRequest?.endAudio()
+            } else {
+                self.alertController.dismiss(animated: true)
+            }
+
+            if error != nil || isFinal {
+                if error == nil {
+                    self.webView.evaluateJavaScript("toggleVoiceButton(false)")
+                    self.webView.evaluateJavaScript("submitVoiceSearch('\(text)')")
+                } else {
+                    self.audioEngine.stop()
+                    self.recognitionRequest?.endAudio()
+                }
+                inputNode.removeTap(onBus: 0)
+
+                self.recognitionRequest = nil
+                self.recognitionTask = nil
+
+                self.isAllowSpeech = true
+            }
+        })
+
+        let recordingFormat = inputNode.outputFormat(forBus: 0)
+        inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
+            self.recognitionRequest?.append(buffer)
+        }
+
+        self.audioEngine.prepare()
+
+        do {
+            try self.audioEngine.start()
+        } catch {
+            //print("audioEngine couldn't start because of an error.")
+        }
+    }
+    
+    func isUsingMyWebview() -> Bool{
+        return PrefsUtil.getURLThirdTab() == "0" || PrefsUtil.getURLThirdTab() == "1" || PrefsUtil.getURLThirdTab() == "2" || PrefsUtil.getURLThirdTab() == "3" || PrefsUtil.getURLThirdTab() == "4"
+    }
+
+}
+
+extension ThirdTabViewController: SFSpeechRecognizerDelegate {
+
+    func speechRecognizer(_ speechRecognizer: SFSpeechRecognizer, availabilityDidChange available: Bool) {
+        if available {
+            self.isAllowSpeech = true
+        } else {
+            self.isAllowSpeech = false
+        }
+    }
+}
+
+extension ThirdTabViewController: WKUIDelegate {
+    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
+        if self.viewIfLoaded?.window != nil {
+          if let urlStr = navigationAction.request.url?.absoluteString {
+              collapseDocked()
+              if urlStr.contains("nexilis/pages/tab1-main-only") || urlStr.contains("nexilis/pages/tab3-main-only") || urlStr.contains("nexilis/pages/tab1-main") || urlStr.contains("nexilis/pages/tab3-commerce") || urlStr.contains("nexilis/pages/tab1-video") || urlStr.contains("nexilis/pages/tab3-main") {
+                  ViewController.alwaysHideButton = false
+                  showTabBar()
+                  ThirdTabViewController.atFirstPage = true
+              }
+    //                  else if isUsingMyWebview() {
+    //                      ViewController.alwaysHideButton = true
+    //                      hideTabBar()
+    //                      ThirdTabViewController.atFirstPage = false
+    //                  }
+          }
+        }
+        decisionHandler(.allow)
+    }
+    func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
+        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
+            let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
+            completionHandler(.useCredential, credential)
+        }
+        else {
+            completionHandler(.cancelAuthenticationChallenge, nil)
+        }
+    }
+}

+ 1336 - 0
AppBuilder/AppBuilder/ViewController.swift

@@ -0,0 +1,1336 @@
+//
+//  ViewController.swift
+//  TestQmeraLite
+//
+//  Created by Qindi on 29/11/21.
+//
+
+import UIKit
+import NexilisLite
+import AVKit
+import AVFoundation
+import SwiftUI
+import Speech
+import Alamofire
+import WebKit
+
+class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMABDelegate, WKNavigationDelegate {
+    let playerController = AVPlayerViewController()
+    static var sURL = "https://www.google.com"
+    static var tab3 = "0"
+    public var isShow: Bool = false
+    public static var chatButton = UIButton()
+    public static var callButton = UIButton()
+    public static var ccButton = UIButton()
+    public static var streamingButton = UIButton()
+    public static var postButton = UIButton()
+    public static var middleButton = UIButton()
+    var buttonChatGR : UITapGestureRecognizer?
+    var buttonCallGR : UITapGestureRecognizer?
+    var buttonCCGR : UITapGestureRecognizer?
+    var buttonStreamGR : UITapGestureRecognizer?
+    var floating : FloatingButton?
+    var firstTab : FirstTabViewController?
+    var secondTab : SecondTabViewController?
+    var thirdTab : ThirdTabViewController?
+    var fourthTab : FourthTabViewController?
+    let emptyTab = EmptyTabViewController()
+    public static var isTab1 = true
+    public static var isTab2 = false
+    public static var isTab3 = false
+    public static var isTab4 = false
+    public static var isExpandButton = false
+    public static var alwaysHideButton = false
+    static var listPullFB: [String] = []
+    static var datePullFB: Date?
+    let welcomeVC = UIViewController()
+    let privacyPolicyVC = UIViewController()
+    var termVC: UIViewController?
+    let welcomeDesc = UILabel()
+    let termText = "Read our Terms of Service. Tap \"Agree and Continue\" to accept Terms of Service.".localized()
+    let term = "Terms of Service.".localized()
+    var firstLoad = true
+    let privacyWV = WKWebView()
+    let indicatorCounterFB = UIView()
+    let labelCounterFB = UILabel()
+    
+    public static var def: ViewController?
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        DispatchQueue.main.async { [self] in
+            while !Utils.getFinishInitPrefsr() {
+               
+            }
+            startView()
+        }
+    }
+    
+    override func viewDidDisappear(_ animated: Bool) {
+        Utils.randomizeBackground(view: self.navigationController?.view)
+    }
+    
+    func startView() {
+        navigationController?.view.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .black : .white
+        Utils.addBackground(view: self.navigationController?.view)
+        let topBorder = CALayer()
+        topBorder.backgroundColor = UIColor.borderTabColor.cgColor
+        topBorder.frame = CGRect(x: 0, y: 0, width: tabBar.frame.size.width, height: 1)
+        tabBar.layer.addSublayer(topBorder)
+        
+        ViewController.def = self
+        title = Bundle.main.displayName
+        let customTab = PrefsUtil.getCustomTab().split(separator: ",")
+        let cpaasMode = PrefsUtil.getCpaasMode()
+        var tabs : [UIViewController] = []
+        firstTab = storyboard?.instantiateViewController(withIdentifier: "firstTabVC") as? FirstTabViewController
+        secondTab = storyboard?.instantiateViewController(withIdentifier: "secondTabVC") as? SecondTabViewController
+        thirdTab = storyboard?.instantiateViewController(withIdentifier: "thirdTabVC") as? ThirdTabViewController
+        fourthTab = storyboard?.instantiateViewController(withIdentifier: "fourthTabVC") as? FourthTabViewController
+        
+        self.delegate = self
+        
+        firstTab?.tabBarItem = UITabBarItem(title: "", image: resizeImage(image: self.traitCollection.userInterfaceStyle == .dark ? UIImage(named: "tab_1_icon")!.withTintColor(.white) : UIImage(named: "tab_1_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(named: "tab_1_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal).withTintColor(self.traitCollection.userInterfaceStyle == .dark ? .lightGray : .mainColor))
+        secondTab?.tabBarItem = UITabBarItem(title: "", image: resizeImage(image: self.traitCollection.userInterfaceStyle == .dark ? UIImage(named: "tab_2_icon")!.withTintColor(.white) : UIImage(named: "tab_2_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(named: "tab_2_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal).withTintColor(self.traitCollection.userInterfaceStyle == .dark ? .lightGray : .mainColor))
+        thirdTab?.tabBarItem = UITabBarItem(title: "", image: resizeImage(image: self.traitCollection.userInterfaceStyle == .dark ? UIImage(named: "tab_3_icon")!.withTintColor(.white) : UIImage(named: "tab_3_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(named: "tab_3_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal).withTintColor(self.traitCollection.userInterfaceStyle == .dark ? .lightGray : .mainColor))
+        fourthTab?.tabBarItem = UITabBarItem(title: "", image: resizeImage(image: self.traitCollection.userInterfaceStyle == .dark ? UIImage(named: "tab_4_icon")!.withTintColor(.white) : UIImage(named: "tab_4_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(named: "tab_4_icon")!, targetSize: CGSize(width: 25, height: 25)).withRenderingMode(.alwaysOriginal).withTintColor(self.traitCollection.userInterfaceStyle == .dark ? .lightGray : .mainColor))
+        var i = 0
+        var j = 0
+        while j < customTab.count {
+            if(((i == 1 && customTab.count == 3) || i == 2) &&
+               (cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX)){
+                tabs.append(emptyTab)
+            }
+            else {
+                switch(customTab[j]){
+                case "1":
+                    tabs.append(firstTab!)
+                case "2":
+                    tabs.append(secondTab!)
+                case "3":
+                    tabs.append(thirdTab!)
+                case "4":
+                    tabs.append(fourthTab!)
+                default:
+                    break
+                }
+                j += 1
+            }
+            i += 1
+        }
+        DispatchQueue.global().async {
+            if !Utils.getTab1Icon().isEmpty {
+                ViewController.getDataImageFromUrl(from: URL(string: "\(PrefsUtil.getURLBase())get_file_from_path?img=\(Utils.getTab1Icon())")!) { data, response, error in
+                    guard let data = data, error == nil else { return }
+                    // always update the UI from the main thread
+                    DispatchQueue.main.async() { [self] in
+                        tabs[0].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                    }
+                }
+            }
+            if !Utils.getTab2Icon().isEmpty {
+                ViewController.getDataImageFromUrl(from: URL(string: "\(PrefsUtil.getURLBase())get_file_from_path?img=\(Utils.getTab2Icon())")!) { data, response, error in
+                    guard let data = data, error == nil else { return }
+                    // always update the UI from the main thread
+                    DispatchQueue.main.async() { [self] in
+                        tabs[1].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                    }
+                }
+            }
+            if !Utils.getTab3Icon().isEmpty {
+                ViewController.getDataImageFromUrl(from: URL(string: "\(PrefsUtil.getURLBase())get_file_from_path?img=\(Utils.getTab3Icon())")!) { data, response, error in
+                    guard let data = data, error == nil else { return }
+                    // always update the UI from the main thread
+                    DispatchQueue.main.async() { [self] in
+                        if cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX {
+                            tabs[3].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                        } else {
+                            tabs[2].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                        }
+                    }
+                }
+            }
+            if !Utils.getTab4Icon().isEmpty {
+                ViewController.getDataImageFromUrl(from: URL(string: "\(PrefsUtil.getURLBase())get_file_from_path?img=\(Utils.getTab4Icon())")!) { data, response, error in
+                    guard let data = data, error == nil else { return }
+                    // always update the UI from the main thread
+                    DispatchQueue.main.async() { [self] in
+                        if cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX {
+                            tabs[4].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                        } else {
+                            tabs[3].tabBarItem = UITabBarItem(title: "", image: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), selectedImage: resizeImage(image: UIImage(data: data)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal))
+                        }
+                    }
+                }
+            }
+        }
+        if((cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX)){
+            createMidFloatingButton()
+            navigationController?.setNavigationBarHidden(true, animated: false)
+            ViewController.pullActionButton()
+        }
+//        if((cpaasMode == PrefsUtil.CPAAS_MODE_FLOATING || cpaasMode == PrefsUtil.CPAAS_MODE_MIX)) {
+//            let rect = CGRect(x: self.view.bounds.width - 100, y: self.view.bounds.height / 2, width: 50, height: 250)
+//            floating = FloatingButton()
+//            floating?.frame = rect
+//            floating?.isShow = true
+//
+//            view.addSubview(floating!)
+//            navigationController?.setNavigationBarHidden(true, animated: false)
+//        }
+        
+        self.setViewControllers(tabs, animated: false)
+        if(cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX){
+            if(customTab.count == 3){
+                self.tabBar.items?[1].isEnabled = false
+            }
+            self.tabBar.items?[2].isEnabled = false
+        }
+        let center: NotificationCenter = NotificationCenter.default
+        center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil)
+        center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil)
+        checkCounter()
+        willappear()
+//        Nexilis.debugBroadcast()
+    }
+    
+    static func getiPhoneModel() -> String {
+        var systemInfo = utsname()
+        uname(&systemInfo)
+        let machineMirror = Mirror(reflecting: systemInfo.machine)
+        let identifier = machineMirror.children.reduce("") { identifier, element in
+            guard let value = element.value as? Int8, value != 0 else { return identifier }
+            return identifier + String(UnicodeScalar(UInt8(value)))
+        }
+        
+        var model = ""
+        
+        if let modelName = mapToDevice(identifier: identifier) {
+            model = modelName
+        } else {
+            model = "Unknown"
+        }
+        
+        return model
+    }
+
+    static func mapToDevice(identifier: String) -> String? {
+        // Add mappings for iPhone models as needed
+        switch identifier {
+            case "iPhone1,1", "iPhone1,2", "iPhone2,1", "iPhone3,1", "iPhone3,2", "iPhone3,3", "iPhone4,1", "iPhone5,1", "iPhone5,2", "iPhone5,3", "iPhone5,4", "iPhone6,1", "iPhone6,2", "iPhone7,1", "iPhone7,2", "iPhone8,1", "iPhone8,2", "iPhone8,4", "iPhone9,1", "iPhone9,2", "iPhone9,3", "iPhone9,4", "iPhone10,1", "iPhone10,2", "iPhone10,4", "iPhone10,5": return "iPhone under X"
+            default: return "iPhone X or newer"
+        }
+    }
+    
+    func getPrefs(key: String) -> TMessage {
+        let tMessage = NexilisLite.TMessage()
+        let me = UserDefaults.standard.string(forKey: "me")
+        tMessage.mCode = "PPR"
+        tMessage.mStatus = CoreMessage_TMessageUtil.getTID()
+        tMessage.mBodies[CoreMessage_TMessageKey.F_PIN] = me
+        tMessage.mBodies[CoreMessage_TMessageKey.KEY] = key
+        return tMessage
+    }
+    
+    @objc func checkCounter() {
+        DispatchQueue.global().async {
+            DispatchQueue.main.async { [self] in
+                if self.viewControllers?.firstIndex(of: secondTab!) != nil {
+                    let counter = queryCountCounter()
+                    let indexSecondTab = self.viewControllers?.firstIndex(of: secondTab!)
+                    let viewSecondTab = self.tabBar.items?[indexSecondTab!].value(forKey: "view") as! UIView
+                    if counter > 0 {
+                        if !indicatorCounterFB.isDescendant(of: viewSecondTab) {
+                            let viewSecondTab = self.tabBar.items?[indexSecondTab!].value(forKey: "view") as! UIView
+                            indicatorCounterFB.backgroundColor = .red
+                            indicatorCounterFB.layer.cornerRadius = 7.5
+                            indicatorCounterFB.clipsToBounds = true
+                            viewSecondTab.addSubview(indicatorCounterFB)
+                            indicatorCounterFB.anchor(top: viewSecondTab.topAnchor, right: viewSecondTab.rightAnchor, paddingRight: 45, height: 15, minWidth: 15, maxWidth: 20)
+                            indicatorCounterFB.addSubview(labelCounterFB)
+                            labelCounterFB.anchor(left: indicatorCounterFB.leftAnchor, right: indicatorCounterFB.rightAnchor, paddingLeft: 5, paddingRight: 5, centerX: indicatorCounterFB.centerXAnchor, centerY: indicatorCounterFB.centerYAnchor)
+                            labelCounterFB.font = .systemFont(ofSize: 10)
+                            labelCounterFB.textColor = .white
+                        }
+                        if counter > 99 {
+                            labelCounterFB.text = "99+"
+                        } else {
+                            labelCounterFB.text = "\(counter)"
+                        }
+                    } else {
+                        if indicatorCounterFB.isDescendant(of: viewSecondTab) {
+                            indicatorCounterFB.removeFromSuperview()
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    private func queryCountCounter() -> Int32 {
+        var counter: Int32?
+        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+            if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "SELECT SUM(counter) FROM MESSAGE_SUMMARY"), cursor.next() {
+                counter = cursor.int(forColumnIndex: 0)
+                cursor.close()
+            }
+        })
+        return counter ?? 0
+    }
+
+//    override func viewDidLayoutSubviews() {
+//        super.viewDidLayoutSubviews()
+//        tabBar.frame.size.height = 65
+//        tabBar.frame.origin.y = view.frame.height - 65
+//    }
+    
+    func settingDelegate() {
+        if self.navigationController?.visibleViewController == fourthTab {
+            return
+        }
+        if self.viewControllers?.firstIndex(of: fourthTab!) == nil {
+            let vc = fourthTab!
+            vc.notInTab = true
+            self.navigationController?.show(vc, sender: nil)
+        } else {
+            self.selectedIndex = (self.viewControllers?.firstIndex(of: fourthTab!))!
+        }
+    }
+    
+    static var alertChangeProfile = LibAlertController()
+    
+    public static func checkIsChangePerson() -> Bool {
+        let isChangeProfile = Utils.getSetProfile()
+        if !isChangeProfile {
+            alertChangeProfile.dismiss(animated: false)
+            alertChangeProfile = LibAlertController(title: "Change Profile".localized(), message: "You must change your name to use this feature".localized().localized(), preferredStyle: .alert)
+            alertChangeProfile.addAction(UIAlertAction(title: "Cancel".localized(), style: .destructive, handler: {_ in
+                if ViewController.def?.viewControllers?.firstIndex(of: (ViewController.def?.firstTab)!) == ViewController.def?.selectedIndex {
+                    ViewController.def?.firstTab?.webView?.evaluateJavaScript("if(resumeAll){resumeAll();}")
+                }
+                if ViewController.def?.viewControllers?.firstIndex(of: (ViewController.def?.thirdTab)!) == ViewController.def?.selectedIndex {
+                    ViewController.def?.thirdTab?.webView?.evaluateJavaScript("if(resumeAll){resumeAll();}")
+                }
+            }))
+            alertChangeProfile.addAction(UIAlertAction(title: "OK".localized(), style: UIAlertAction.Style.default, handler: {(_) in
+                ViewController.resetTabSelected()
+                let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "signupsignin") as! SignUpSignIn
+                controller.forceLogin = true
+                controller.isDismiss = { newThumb in
+                    FirstTabViewController.forceRefresh = true
+                    ThirdTabViewController.forceRefresh = true
+                    FirstTabViewController.showModal = false
+                    ThirdTabViewController.showModal = false
+                }
+                let navigationController = CustomNavigationController(rootViewController: controller)
+                navigationController.modalPresentationStyle = .fullScreen
+                navigationController.navigationBar.tintColor = .white
+                navigationController.navigationBar.barTintColor = UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.rootViewController?.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .mainColor
+                navigationController.navigationBar.isTranslucent = false
+                navigationController.navigationBar.overrideUserInterfaceStyle = .dark
+                navigationController.navigationBar.barStyle = .black
+                let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
+                UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
+                let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
+                navigationController.navigationBar.titleTextAttributes = textAttributes
+                ViewController.def?.show(b: false)
+                ViewController.def?.thirdTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+                ViewController.def?.firstTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+                let rootVC = UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.rootViewController
+                if rootVC?.presentedViewController == nil {
+                    rootVC?.present(navigationController, animated: true, completion: nil)
+                } else {
+                    rootVC?.presentedViewController?.present(navigationController, animated: true, completion: nil)
+                }
+            }))
+            let rootVC = UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.rootViewController
+            if rootVC?.presentedViewController == nil {
+                rootVC?.present(alertChangeProfile, animated: true, completion: nil)
+            } else {
+                rootVC?.presentedViewController?.present(alertChangeProfile, animated: true, completion: nil)
+            }
+            return false
+        }
+        return true
+    }
+    public static func resetTabSelected(){
+        ViewController.isTab1 = true
+        ViewController.isTab2 = false
+        ViewController.isTab3 = false
+        ViewController.isTab4 = false
+//        if ViewController.isTab1 {
+//            ViewController.imageTab1.image = UIImage(named: "tab_1_nexilis")!
+//        }
+//        else {
+//            ViewController.imageTab1.image = UIImage(named: "tab_1_nexilis_off")!
+//        }
+//        if ViewController.isTab2 {
+//            ViewController.imageTab2.image = UIImage(named: "tab_2_nexilis")!
+//        }
+//        else {
+//            ViewController.imageTab2.image = UIImage(named: "tab_2_nexilis_off")!
+//        }
+//        if ViewController.isTab3 {
+//            ViewController.imageTab3.image = UIImage(named: "tab_3_nexilis")!
+//        }
+//        else {
+//            ViewController.imageTab3.image = UIImage(named: "tab_3_nexilis_off")!
+//        }
+//        if ViewController.isTab4 {
+//            ViewController.imageTab4.image = UIImage(named: "tab_4_nexilis")!
+//        }
+//        else {
+//            ViewController.imageTab4.image = UIImage(named: "tab_4_nexilis_off")!
+//        }
+    }
+    
+    override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
+        let cpaasMode = PrefsUtil.getCpaasMode()
+        let customTab = PrefsUtil.getCustomTab().split(separator: ",")
+        if(cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX){
+            if(customTab.count == 2){
+                ViewController.isTab1 = item == tabBar.items?[0]
+                ViewController.isTab2 = item == tabBar.items?[2]
+            }
+            else if(customTab.count == 3){
+                ViewController.isTab1 = item == tabBar.items?[0]
+                ViewController.isTab2 = item == tabBar.items?[2]
+                ViewController.isTab3 = item == tabBar.items?[3]
+            }
+            else if(customTab.count == 4){
+                ViewController.isTab1 = item == tabBar.items?[0]
+                ViewController.isTab2 = item == tabBar.items?[1]
+                ViewController.isTab3 = item == tabBar.items?[3]
+                ViewController.isTab4 = item == tabBar.items?[4]
+            }
+        }
+        else{
+            ViewController.isTab1 = item == tabBar.items?[0]
+            ViewController.isTab2 = item == tabBar.items?[1]
+            if(customTab.count > 2){
+                ViewController.isTab3 = item == tabBar.items?[2]
+            }
+            if(customTab.count > 3){
+                ViewController.isTab4 = item == tabBar.items?[3]
+            }
+        }
+    }
+    
+    func createMidFloatingButton(){
+        var minYIpX: CGFloat = 0
+        let iPhoneModel = ViewController.getiPhoneModel()
+        if iPhoneModel == "iPhone X or newer" {
+            minYIpX += 20
+        }
+        var widthHeightButton: CGFloat = 45
+        if Utils.getIconDockSize() == "1" {
+            widthHeightButton = 55
+        }
+        ViewController.chatButton = UIButton(frame: CGRect(x: self.view.bounds.width / 2 - 22.5 , y: self.view.bounds.height - 80 - minYIpX, width: widthHeightButton, height: widthHeightButton))
+        ViewController.chatButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
+        ViewController.chatButton.layer.shadowColor = UIColor.black.cgColor
+        ViewController.chatButton.layer.shadowOpacity = 0.1
+        ViewController.chatButton.layer.shadowOffset = CGSize(width: 4, height: 4)
+        ViewController.chatButton.addTarget(self, action: #selector(chatTap), for: .touchUpInside)
+
+        ViewController.callButton = UIButton(frame: CGRect(x: self.view.bounds.width / 2 - 22.5 , y: self.view.bounds.height - 80 - minYIpX, width: widthHeightButton, height: widthHeightButton))
+        ViewController.callButton.setBackgroundImage(UIImage(named: "pb_button_call", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
+        ViewController.callButton.layer.shadowColor = UIColor.black.cgColor
+        ViewController.callButton.layer.shadowOpacity = 0.1
+        ViewController.callButton.layer.shadowOffset = CGSize(width: 4, height: 4)
+        ViewController.callButton.addTarget(self, action: #selector(callTap), for: .touchUpInside)
+
+        ViewController.ccButton = UIButton(frame: CGRect(x: self.view.bounds.width / 2 - 22.5 , y: self.view.bounds.height - 80 - minYIpX, width: widthHeightButton, height: widthHeightButton))
+        ViewController.ccButton.setBackgroundImage(UIImage(named: "pb_button_cc", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
+        ViewController.ccButton.layer.shadowColor = UIColor.black.cgColor
+        ViewController.ccButton.layer.shadowOpacity = 0.1
+        ViewController.ccButton.layer.shadowOffset = CGSize(width: 4, height: 4)
+        ViewController.ccButton.addTarget(self, action: #selector(ccTap), for: .touchUpInside)
+
+        ViewController.streamingButton = UIButton(frame: CGRect(x: self.view.bounds.width / 2 - 22.5 , y: self.view.bounds.height - 80 - minYIpX, width: widthHeightButton, height: widthHeightButton))
+        ViewController.streamingButton.setBackgroundImage(UIImage(named: "pb_button_stream", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
+        ViewController.streamingButton.layer.shadowColor = UIColor.black.cgColor
+        ViewController.streamingButton.layer.shadowOpacity = 0.1
+        ViewController.streamingButton.layer.shadowOffset = CGSize(width: 4, height: 4)
+        ViewController.streamingButton.addTarget(self, action: #selector(streamTap), for: .touchUpInside)
+
+        ViewController.postButton = UIButton(frame: CGRect(x: self.view.bounds.width / 2 - 22.5 , y: self.view.bounds.height - 80 - minYIpX, width: widthHeightButton, height: widthHeightButton))
+        ViewController.postButton.setBackgroundImage(UIImage(named: "pb_button_post", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
+        ViewController.postButton.layer.shadowColor = UIColor.black.cgColor
+        ViewController.postButton.layer.shadowOpacity = 0.1
+        ViewController.postButton.layer.shadowOffset = CGSize(width: 4, height: 4)
+        ViewController.postButton.addTarget(self, action: #selector(postTap), for: .touchUpInside)
+        let buttonCenterX = self.view.bounds.width / 2
+        let buttonCenterY = self.view.bounds.height - self.tabBar.bounds.height
+        //print("buttonCenterX \(buttonCenterX)")
+        //print("buttonCenterY \(buttonCenterY)")
+        ViewController.middleButton = UIButton(frame: CGRect(x: buttonCenterX - 40 , y: buttonCenterY - 40, width: 80, height: 80))
+        if !PrefsUtil.getIconDock().isEmpty {
+            if PrefsUtil.getIconDock().contains(".gif") {
+                ViewController.middleButton.sd_setBackgroundImage(with: URL(string: PrefsUtil.getIconCenterAnim()!), for: .normal, completed: { (image, error, cacheType, imageURL) in
+                    if let error = error {
+                        //print("Error loading image: \(error.localizedDescription)")
+                    } else {
+                        //print("Image loaded successfully")
+                    }
+                })
+            } else {
+                DispatchQueue.global().async {
+                    let urlString = PrefsUtil.getUrlDock()!
+                    if let cachedImage = ImageCache.shared.image(forKey: urlString) {
+                        DispatchQueue.main.async() {
+                            ViewController.middleButton.setBackgroundImage(cachedImage, for: .normal)
+                        }
+                        return
+                    }
+                    Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
+                        guard let data = data, error == nil else { return }
+                        // always update the UI from the main thread
+                        DispatchQueue.main.async() {
+                            if UIImage(data: data) != nil {
+                                ViewController.middleButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
+                            }
+                        }
+                    }
+                }
+            }
+        } else {
+            ViewController.middleButton.setBackgroundImage(UIImage(named: "pb_button", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
+        }
+        ViewController.middleButton.layer.shadowColor = UIColor.black.cgColor
+        ViewController.middleButton.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
+        ViewController.middleButton.layer.shadowOpacity = 1.0
+        ViewController.middleButton.layer.shadowRadius = 5.0
+        ViewController.middleButton.layer.masksToBounds = false
+        ViewController.middleButton.layer.cornerRadius = 4.0
+        ViewController.middleButton.addTarget(self, action: #selector(middleBtnTapped), for: .touchUpInside)
+        let longPressMidButton = UILongPressGestureRecognizer(target: self, action: #selector(longPressMidBtn(gestureRecognizer:)))
+        ViewController.middleButton.addGestureRecognizer(longPressMidButton)
+        self.view.addSubview(ViewController.chatButton)
+        self.view.addSubview(ViewController.callButton)
+        self.view.addSubview(ViewController.ccButton)
+        self.view.addSubview(ViewController.postButton)
+        self.view.addSubview(ViewController.streamingButton)
+        self.view.addSubview(ViewController.middleButton)
+        
+        ViewController.hideDockedButton()
+    }
+    
+    @objc func longPressMidBtn(gestureRecognizer: UILongPressGestureRecognizer) {
+        if gestureRecognizer.state == .began {
+            if self.viewControllers?.firstIndex(of: fourthTab!) == nil {
+                let vc = fourthTab!
+                vc.notInTab = true
+                self.navigationController?.show(vc, sender: nil)
+            } else {
+                self.selectedIndex = (self.viewControllers?.firstIndex(of: fourthTab!))!
+            }
+        }
+    }
+    
+    func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
+        if(viewController == secondTab){
+            if(!ViewController.checkIsChangePerson()){
+                return false
+            }
+        }
+        return true
+    }
+    
+    func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
+        if viewController != secondTab {
+            let idxTabChat = self.viewControllers?.firstIndex(where: {$0 == secondTab})
+            if idxTabChat != nil {
+                let vcTabChats = self.viewControllers![idxTabChat!] as! SecondTabViewController
+                if vcTabChats.searchController.isActive {
+                    vcTabChats.searchController.isActive = false
+                }
+            }
+        }
+    }
+    
+    override func viewWillAppear(_ animated: Bool) {
+        if !firstLoad {
+            willappear()
+        } else {
+            firstLoad = false
+        }
+    }
+    
+    func willappear() {
+        let acceptTerm = PrefsUtil.getTerms()
+        let enable_privacy_policy = PrefsUtil.getEnablePrivacyPolicy()
+        if !acceptTerm {
+            showWelocomeView()
+            return
+        } else if enable_privacy_policy && !PrefsUtil.getAgreePrivacyPolicy() {
+            showPrivacyPolicyView()
+            return
+        } else {
+            if !Utils.getForceAnonymous() && !Utils.getSetProfile() {
+                Nexilis.showForceSignIn()
+                return
+            }
+        }
+        self.selectedViewController?.viewWillAppear(false)
+    }
+    
+    func showPrivacyPolicyView() {
+        if let privacyView = privacyPolicyVC.view {
+            let bgImage = UIImageView()
+            privacyView.addSubview(bgImage)
+            bgImage.anchor(top: privacyView.topAnchor, left: privacyView.leftAnchor, bottom: privacyView.bottomAnchor, right: privacyView.rightAnchor)
+            bgImage.backgroundColor = .white
+            DispatchQueue.global().async {
+                DispatchQueue.main.async {
+                    let listBg = PrefsUtil.getBackgroundLight().isEmpty && PrefsUtil.getBackgroundDark().isEmpty ? PrefsUtil.getBackground() :
+                                        self.traitCollection.userInterfaceStyle == .dark ? PrefsUtil.getBackgroundDark() : PrefsUtil.getBackgroundLight()
+                    if listBg.isEmpty {
+                       return
+                    }
+                    var bgChoosen = ""
+                    let arrayBg = listBg.split(separator: ",")
+                    bgChoosen = String(arrayBg[Int.random(in: 0..<arrayBg.count)])
+                    let urlString = PrefsUtil.getURLBase() + "get_file_from_path?img=" + bgChoosen
+                    if let cachedImage = ImageCache.shared.image(forKey: urlString) {
+                        DispatchQueue.main.async() {
+                            bgImage.image = cachedImage
+                        }
+                        return
+                    }
+                    Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
+                        guard let data = data, error == nil else { return }
+                        // always update the UI from the main thread
+                        DispatchQueue.main.async() {
+                            if UIImage(data: data) != nil {
+                                bgImage.image = UIImage(data: data)!
+                                ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
+                            }
+                        }
+                    }
+                }
+            }
+            
+            let containerButton = UIView()
+            privacyView.addSubview(containerButton)
+            containerButton.anchor(left: privacyView.safeAreaLayoutGuide.leftAnchor, bottom: privacyView.safeAreaLayoutGuide.bottomAnchor, paddingLeft: 10, paddingBottom: 10, minHeight: 40)
+            containerButton.rightAnchor.constraint(lessThanOrEqualTo: privacyView.safeAreaLayoutGuide.rightAnchor, constant: -10).isActive = true
+            containerButton.isUserInteractionEnabled = true
+            let tapgestureAgree = UITapGestureRecognizer(target: self, action: #selector(tappedOnAgreePrivacy(_ :)))
+            tapgestureAgree.numberOfTapsRequired = 1
+            containerButton.addGestureRecognizer(tapgestureAgree)
+            
+            let imageAgree = UIImageView()
+            imageAgree.image = UIImage(systemName: "arrow.forward.circle")
+            imageAgree.tintColor = .black
+            containerButton.addSubview(imageAgree)
+            imageAgree.anchor(left: containerButton.leftAnchor, centerY: containerButton.centerYAnchor, width: 40, height: 40)
+            
+            let titleAgree = UILabel()
+            titleAgree.text = "Agree and Continue".localized()
+            titleAgree.textColor = .black
+            containerButton.addSubview(titleAgree)
+            titleAgree.anchor(left: imageAgree.rightAnchor, right: containerButton.rightAnchor, paddingLeft: 5, centerY: containerButton.centerYAnchor)
+            
+            privacyWV.isOpaque = false
+            privacyWV.backgroundColor = UIColor.clear
+            privacyWV.scrollView.backgroundColor = UIColor.clear
+            //print("URL: \(PrefsUtil.getURLPrivacyPolicy())")
+            let lang = UserDefaults.standard.string(forKey: "i18n_language")
+            var urlPrivacyPolicy = PrefsUtil.getURLPrivacyPolicy()
+            if lang == "id" {
+                urlPrivacyPolicy = urlPrivacyPolicy.replacingOccurrences(of: "/en/", with: "/id/")
+            }
+            privacyWV.load(URLRequest(url: URL(string: urlPrivacyPolicy)!))
+            privacyView.addSubview(privacyWV)
+            privacyWV.navigationDelegate = self
+            privacyWV.anchor(top: privacyView.safeAreaLayoutGuide.topAnchor, left: privacyView.leftAnchor, right: privacyView.rightAnchor, height: privacyView.bounds.height - 80)
+            
+        }
+        privacyPolicyVC.modalPresentationStyle = .fullScreen
+        privacyPolicyVC.modalTransitionStyle = .crossDissolve
+        self.present(privacyPolicyVC, animated: true)
+    }
+    
+    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
+        let js = "(function() { document.body.style.background='transparent'; })();"
+        privacyWV.evaluateJavaScript(js) { (_, error) in
+            //print(error as Any)
+        }
+    }
+    
+    func showWelocomeView() {
+        if let viewWelcome = welcomeVC.view {
+            viewWelcome.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .black : .white
+            Utils.addBackground(view: viewWelcome)
+            let bgImage = UIImageView()
+            viewWelcome.addSubview(bgImage)
+            bgImage.anchor(top: viewWelcome.topAnchor, left: viewWelcome.leftAnchor, bottom: viewWelcome.bottomAnchor, right: viewWelcome.rightAnchor)
+            DispatchQueue.global().async {
+                DispatchQueue.main.async {
+                    let listBg = PrefsUtil.getBackgroundLight().isEmpty && PrefsUtil.getBackgroundDark().isEmpty ? PrefsUtil.getBackground() :
+                                        self.traitCollection.userInterfaceStyle == .dark ? PrefsUtil.getBackgroundDark() : PrefsUtil.getBackgroundLight()
+                    if listBg.isEmpty {
+                       return
+                    }
+                    var bgChoosen = ""
+                    let arrayBg = listBg.split(separator: ",")
+                    bgChoosen = String(arrayBg[Int.random(in: 0..<arrayBg.count)])
+                    let urlString = PrefsUtil.getURLBase() + "get_file_from_path?img=" + bgChoosen
+                    if let cachedImage = ImageCache.shared.image(forKey: urlString) {
+                        DispatchQueue.main.async() {
+                            bgImage.image = cachedImage
+                        }
+                        return
+                    }
+                    Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: urlString)!) { data, response, error in
+                        guard let data = data, error == nil else { return }
+                        // always update the UI from the main thread
+                        DispatchQueue.main.async() {
+                            if UIImage(data: data) != nil {
+                                bgImage.image = UIImage(data: data)!
+                                ImageCache.shared.save(image: UIImage(data: data)!, forKey: urlString)
+                            }
+                        }
+                    }
+                }
+            }
+            let welcomeTitle = UILabel()
+            welcomeTitle.text = "Welcome to".localized() + " " + (Bundle.main.displayName ?? "")
+            welcomeTitle.font = .systemFont(ofSize: 25, weight: .bold)
+            welcomeTitle.numberOfLines = 0
+            viewWelcome.addSubview(welcomeTitle)
+            welcomeTitle.anchor(top: viewWelcome.safeAreaLayoutGuide.topAnchor, left: viewWelcome.safeAreaLayoutGuide.leftAnchor, right: viewWelcome.safeAreaLayoutGuide.rightAnchor, paddingTop: 10, paddingLeft: 10, paddingRight: 10)
+            
+            let logoImage = UIImageView()
+            logoImage.image = UIImage(named: getHighResolutionAppIconName() ?? "")
+            viewWelcome.addSubview(logoImage)
+            logoImage.anchor(centerX: viewWelcome.centerXAnchor, centerY: viewWelcome.centerYAnchor, width: 200, height: 200)
+            
+            let containerButton = UIView()
+            viewWelcome.addSubview(containerButton)
+            containerButton.anchor(left: viewWelcome.safeAreaLayoutGuide.leftAnchor, bottom: viewWelcome.safeAreaLayoutGuide.bottomAnchor, paddingLeft: 10, paddingBottom: 10, minHeight: 40)
+            containerButton.rightAnchor.constraint(lessThanOrEqualTo: viewWelcome.safeAreaLayoutGuide.rightAnchor, constant: -10).isActive = true
+            containerButton.isUserInteractionEnabled = true
+            let tapgestureAgree = UITapGestureRecognizer(target: self, action: #selector(tappedOnAgree(_ :)))
+            tapgestureAgree.numberOfTapsRequired = 1
+            containerButton.addGestureRecognizer(tapgestureAgree)
+            
+            let imageAgree = UIImageView()
+            imageAgree.image = UIImage(systemName: "arrow.forward.circle")
+            imageAgree.tintColor = self.traitCollection.userInterfaceStyle == .dark ? UIColor.white: UIColor.black
+            containerButton.addSubview(imageAgree)
+            imageAgree.anchor(left: containerButton.leftAnchor, centerY: containerButton.centerYAnchor, width: 40, height: 40)
+            
+            let titleAgree = UILabel()
+            titleAgree.text = "Agree and Continue".localized()
+            titleAgree.textColor = self.traitCollection.userInterfaceStyle == .dark ? UIColor.white: UIColor.black
+            containerButton.addSubview(titleAgree)
+            titleAgree.anchor(left: imageAgree.rightAnchor, right: containerButton.rightAnchor, paddingLeft: 5, centerY: containerButton.centerYAnchor)
+            
+            let formattedText = String.format(strings: [term], inString: termText, color: self.traitCollection.userInterfaceStyle == .dark ? UIColor.white: UIColor.black)
+            welcomeDesc.isUserInteractionEnabled = true
+            welcomeDesc.attributedText = formattedText
+            welcomeDesc.numberOfLines = 0
+            viewWelcome.addSubview(welcomeDesc)
+            welcomeDesc.anchor(left: viewWelcome.safeAreaLayoutGuide.leftAnchor, bottom: containerButton.topAnchor, right: viewWelcome.rightAnchor, paddingLeft: 10, paddingBottom: 10, paddingRight: 10)
+            let tapgesture = UITapGestureRecognizer(target: self, action: #selector(tappedOnLabelTerms(_ :)))
+            tapgesture.numberOfTapsRequired = 1
+            welcomeDesc.addGestureRecognizer(tapgesture)
+            
+        }
+        welcomeVC.modalPresentationStyle = .fullScreen
+        welcomeVC.modalTransitionStyle = .crossDissolve
+        self.present(welcomeVC, animated: true)
+    }
+    
+    func getHighResolutionAppIconName() -> String? {
+        guard let infoPlist = Bundle.main.infoDictionary else { return nil }
+        guard let bundleIcons = infoPlist["CFBundleIcons"] as? NSDictionary else { return nil }
+        guard let bundlePrimaryIcon = bundleIcons["CFBundlePrimaryIcon"] as? NSDictionary else { return nil }
+        guard let bundleIconFiles = bundlePrimaryIcon["CFBundleIconFiles"] as? NSArray else { return nil }
+        guard let appIcon = bundleIconFiles.lastObject as? String else { return nil }
+        return appIcon
+    }
+    
+    func showWebviewTerm() {
+        termVC = UIViewController()
+        if let viewTerm = termVC!.view {
+            let webView = WKWebView()
+            let lang = UserDefaults.standard.string(forKey: "i18n_language")
+            var urlTerm = "https://nexilis.io/newuniverse-tos"
+            if lang == "id" {
+                urlTerm = "https://nexilis.io/newuniverse-tos-id"
+            }
+            let url = URL (string: urlTerm)
+            let requestObj = URLRequest(url: url!)
+            webView.load(requestObj)
+            viewTerm.addSubview(webView)
+            webView.anchor(top: viewTerm.safeAreaLayoutGuide.topAnchor, left: viewTerm.safeAreaLayoutGuide.leftAnchor, bottom: viewTerm.safeAreaLayoutGuide.bottomAnchor, right: viewTerm.safeAreaLayoutGuide.rightAnchor)
+        }
+        let navigationController = CustomNavigationController(rootViewController: termVC!)
+        navigationController.navigationBar.tintColor = .mainColor
+        navigationController.navigationBar.barTintColor = .white
+        navigationController.navigationBar.isTranslucent = false
+        let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.mainColor]
+        navigationController.navigationBar.titleTextAttributes = textAttributes
+        termVC!.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Close".localized(), style: .plain, target: self, action: #selector(closeTerm))
+        welcomeVC.present(navigationController, animated: true)
+    }
+    
+    @objc func closeTerm() {
+        termVC!.dismiss(animated: true)
+    }
+    
+    @objc func tappedOnLabelTerms(_ gesture: UITapGestureRecognizer) {
+        let termString = termText as NSString
+        let termRange = termString.range(of: term)
+
+        let tapLocation = gesture.location(in: welcomeDesc)
+        let index = welcomeDesc.indexOfAttributedTextCharacterAtPoint(point: tapLocation)
+            
+        if checkRange(termRange, contain: index) == true {
+            showWebviewTerm()
+            return
+        }
+
+    }
+    
+    @objc func tappedOnAgree(_ gesture: UITapGestureRecognizer) {
+        PrefsUtil.setTerms(value: true)
+        welcomeVC.dismiss(animated: true)
+    }
+    
+    @objc func tappedOnAgreePrivacy(_ gesture: UITapGestureRecognizer) {
+        PrefsUtil.setAgreePrivacyPolicy(value: true)
+        privacyPolicyVC.dismiss(animated: true)
+    }
+    
+    func checkRange(_ range: NSRange, contain index: Int) -> Bool {
+        return index > range.location && index < range.location + range.length
+    }
+    
+    @objc func middleBtnTapped() {
+        ViewController.expandButton()
+    }
+
+
+
+    public func show(b: Bool) {
+        if(!b){
+            if(ViewController.isExpandButton){
+                ViewController.expandButton()
+            }
+        }
+    }
+    
+    @objc func ccTap() {
+        //print("ccTap")
+        if(ViewController.checkIsChangePerson()){
+            show(b: false)
+            ViewController.def?.thirdTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+            ViewController.def?.firstTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+            if ViewController.listPullFB.count != 0 && ViewController.listPullFB.count > 2 {
+                let package_id = ViewController.listPullFB[2].split(separator: "|")[0]
+                var app_id = ""
+                if package_id.contains("_fb") {
+                    let listSplit = package_id.split(separator: "_", maxSplits: 1)
+                    let numIdx = listSplit[listSplit.firstIndex(where: { $0.contains("fb") }) ?? 0]
+                    let indexTap = Int(String(numIdx).substring(from: 2, to: numIdx.count))!
+                    if listSplit.count == 2 {
+                        app_id = String(listSplit[1])
+                    }
+                    if indexTap == 99 {
+                        openTabPost()
+                    } else {
+                        Nexilis.buttonClicked(index: indexTap, id: app_id)
+                    }
+                } else {
+                    if !app_id.isEmpty {
+                        Nexilis.buttonClicked(index: 0, id: app_id)
+                    }
+                }
+            } else {
+                Nexilis.buttonClicked(index: 9)
+            }
+        }
+    }
+    
+    @objc func streamTap() {
+        //print("streamTap")
+        if(ViewController.checkIsChangePerson()){
+            show(b: false)
+            ViewController.def?.thirdTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+            ViewController.def?.firstTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+            if ViewController.listPullFB.count != 0 && ViewController.listPullFB.count > 4 {
+                let package_id = ViewController.listPullFB[4].split(separator: "|")[0]
+                var app_id = ""
+                if package_id.contains("_fb") {
+                    let listSplit = package_id.split(separator: "_", maxSplits: 1)
+                    let numIdx = listSplit[listSplit.firstIndex(where: { $0.contains("fb") }) ?? 0]
+                    let indexTap = Int(String(numIdx).substring(from: 2, to: numIdx.count))!
+                    if listSplit.count == 2 {
+                        app_id = String(listSplit[1])
+                    }
+                    if indexTap == 99 {
+                        openTabPost()
+                    } else {
+                        Nexilis.buttonClicked(index: indexTap, id: app_id)
+                    }
+                } else {
+                    if !app_id.isEmpty {
+                        Nexilis.buttonClicked(index: 0, id: app_id)
+                    }
+                }
+            } else {
+                Nexilis.buttonClicked(index: 8)
+            }
+        }
+    }
+    
+    @objc func callTap() {
+        //print("callTap")
+        if(ViewController.checkIsChangePerson()){
+            show(b: false)
+            ViewController.def?.thirdTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+            ViewController.def?.firstTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+            if ViewController.listPullFB.count != 0 && ViewController.listPullFB.count > 1 {
+                let package_id = ViewController.listPullFB[1].split(separator: "|")[0]
+                var app_id = ""
+                if package_id.contains("_fb") {
+                    let listSplit = package_id.split(separator: "_", maxSplits: 1)
+                    let numIdx = listSplit[listSplit.firstIndex(where: { $0.contains("fb") }) ?? 0]
+                    let indexTap = Int(String(numIdx).substring(from: 2, to: numIdx.count))!
+                    if listSplit.count == 2 {
+                        app_id = String(listSplit[1])
+                    }
+                    if indexTap == 99 {
+                        openTabPost()
+                    } else {
+                        Nexilis.buttonClicked(index: indexTap, id: app_id)
+                    }
+                } else {
+                    if !app_id.isEmpty {
+                        Nexilis.buttonClicked(index: 0, id: app_id)
+                    }
+                }
+            } else {
+                Nexilis.buttonClicked(index: 7)
+            }
+        }
+    }
+    
+    @objc func chatTap() {
+        //print("chatTap")
+//        APIS.openWhiteboard()
+//        return
+        if(ViewController.checkIsChangePerson()){
+            show(b: false)
+            ViewController.def?.thirdTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+            ViewController.def?.firstTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+            if ViewController.listPullFB.count != 0 && ViewController.listPullFB.count > 0 {
+                let package_id = ViewController.listPullFB[0].split(separator: "|")[0]
+                var app_id = ""
+                if package_id.contains("_fb") {
+                    let listSplit = package_id.split(separator: "_", maxSplits: 1)
+                    let numIdx = listSplit[listSplit.firstIndex(where: { $0.contains("fb") }) ?? 0]
+                    let indexTap = Int(String(numIdx).substring(from: 2, to: numIdx.count))!
+                    if listSplit.count == 2 {
+                        app_id = String(listSplit[1])
+                    }
+                    if indexTap == 99 {
+                        openTabPost()
+                    } else {
+                        Nexilis.buttonClicked(index: indexTap, id: app_id)
+                    }
+                } else {
+                    if !app_id.isEmpty {
+                        Nexilis.buttonClicked(index: 0, id: app_id)
+                    }
+                }
+            } else {
+                Nexilis.buttonClicked(index: 6)
+            }
+        }
+    }
+    
+    @objc func postTap() {
+        if(ViewController.checkIsChangePerson()){
+            show(b: false)
+            ViewController.def?.thirdTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+            ViewController.def?.firstTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
+            if ViewController.listPullFB.count != 0 && ViewController.listPullFB.count > 3 {
+                let package_id = ViewController.listPullFB[3].split(separator: "|")[0]
+                var app_id = ""
+                if package_id.contains("_fb") {
+                    let listSplit = package_id.split(separator: "_", maxSplits: 1)
+                    let numIdx = listSplit[listSplit.firstIndex(where: { $0.contains("fb") }) ?? 0]
+                    let indexTap = Int(String(numIdx).substring(from: 2, to: numIdx.count))!
+                    if listSplit.count == 2 {
+                        app_id = String(listSplit[1])
+                    }
+                    if indexTap == 99 {
+                        openTabPost()
+                    } else {
+                        Nexilis.buttonClicked(index: indexTap, id: app_id)
+                    }
+                } else {
+                    if !app_id.isEmpty {
+                        Nexilis.buttonClicked(index: 0, id: app_id)
+                    }
+                }
+            } else {
+                openTabPost()
+            }
+        }
+        
+    }
+    
+    func openTabPost() {
+        let customTab = PrefsUtil.getCustomTab().split(separator: ",")
+        let cpaasMode = PrefsUtil.getCpaasMode()
+        var i = 0
+        var j = 0
+        //print("custom tab post tap = \(customTab)")
+        while j < customTab.count {
+            if(((i == 1 && customTab.count == 3) || i == 2) &&
+               (cpaasMode == PrefsUtil.CPAAS_MODE_DOCKED || cpaasMode == PrefsUtil.CPAAS_MODE_MIX)){
+                
+            }
+            else {
+                if customTab[j] == "3" {
+                    break
+                }
+                j += 1
+            }
+            i += 1
+        }
+        if(j < customTab.count){
+            self.selectedIndex = i
+            
+            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(1), execute: {
+                let me = UserDefaults.standard.string(forKey: "me")
+                let address = "\(PrefsUtil.getURLBase())nexilis/pages/tab5-new-post?f_pin=\(me ?? "")"
+                self.thirdTab?.webView.evaluateJavaScript("{window.localStorage.setItem('currentTab','\(ViewController.tab3)')}")
+                self.thirdTab?.webView.evaluateJavaScript("window.location = '\(address)'")
+                
+            })
+        }
+    }
+    
+    static func pullActionButton() {
+        if datePullFB == nil || Int(Date().timeIntervalSince(datePullFB!)) >= 60 {
+            datePullFB = Date()
+            DispatchQueue.global().async {
+                if !PrefsUtil.getCustomButtons().isEmpty {
+                    DispatchQueue.main.async { [self] in
+                        let customButtons = PrefsUtil.getCustomButtons().components(separatedBy: ",")
+                        var customIcons = PrefsUtil.getCustomFBIcon().components(separatedBy: ",")
+                        if Utils.getIsLoadThemeFromOther() {
+                            customIcons = Utils.getButtonIcon().components(separatedBy: ",")
+                        }
+                        for i in 0..<customButtons.count {
+                            let package_id = customButtons[i]
+                            let app_id = ""
+                            let icon = customIcons[i]
+                            listPullFB.append("\(package_id)|\(app_id)")
+                            DispatchQueue.global().async {
+                                ViewController.getDataImageFromUrl(from: URL(string: PrefsUtil.getURLBase() + "get_file_from_path?img=\(icon)")!) { data, response, error in
+                                    guard let data = data, error == nil else { return }
+                                    // always update the UI from the main thread
+                                    DispatchQueue.main.async() {
+                                        if i == 0 {
+                                            ViewController.chatButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                        } else if i == 1 {
+                                            ViewController.callButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                        }  else if i == 2 {
+                                            ViewController.ccButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                        }  else if i == 3 {
+                                            ViewController.postButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                        }  else if i == 4 {
+                                            ViewController.streamingButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    return
+                }
+                if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.pullFloatingButton(), timeout: 30 * 1000) {
+                    if response.isOk() {
+                        let data = response.getBody(key: CoreMessage_TMessageKey.DATA, default_value: "")
+                        if !data.isEmpty {
+                            if let jsonArray = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [AnyObject] {
+                                DispatchQueue.main.async { [self] in
+                                    listPullFB.removeAll()
+                                    if jsonArray.count != 0 {
+                                        var count = 0
+                                        for json in jsonArray {
+                                            let package_id = json["package_act"] as! String
+                                            let app_id = (json["app_id"] as? String) ?? ""
+                                            let icon = (json["icon"] as? String) ?? ""
+                                            listPullFB.append("\(package_id)|\(app_id)")
+                                            if count == 0 {
+                                                if !icon.isEmpty {
+                                                    DispatchQueue.global().async {
+                                                        ViewController.getDataImageFromUrl(from: URL(string: "https://nexilis.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) { data, response, error in
+                                                            guard let data = data, error == nil else { return }
+                                                            // always update the UI from the main thread
+                                                            DispatchQueue.main.async() {
+                                                                ViewController.chatButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                                            }
+                                                        }
+                                                    }
+                                                } else {
+                                                    ViewController.chatButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
+                                                }
+                                            } else if count == 1 {
+                                                if !icon.isEmpty {
+                                                    DispatchQueue.global().async {
+                                                        ViewController.getDataImageFromUrl(from: URL(string: "https://nexilis.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) { data, response, error in
+                                                            guard let data = data, error == nil else { return }
+                                                            // always update the UI from the main thread
+                                                            DispatchQueue.main.async() {
+                                                                ViewController.callButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                                            }
+                                                        }
+                                                    }
+                                                } else {
+                                                    ViewController.callButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
+                                                }
+                                            } else if count == 2 {
+                                                if !icon.isEmpty {
+                                                    DispatchQueue.global().async {
+                                                        ViewController.getDataImageFromUrl(from: URL(string: "https://nexilis.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) { data, response, error in
+                                                            guard let data = data, error == nil else { return }
+                                                            // always update the UI from the main thread
+                                                            DispatchQueue.main.async() {
+                                                                ViewController.ccButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                                            }
+                                                        }
+                                                    }
+                                                } else {
+                                                    ViewController.ccButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
+                                                }
+                                            } else if count == 3 {
+                                                if !icon.isEmpty {
+                                                    DispatchQueue.global().async {
+                                                        ViewController.getDataImageFromUrl(from: URL(string: "https://nexilis.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) { data, response, error in
+                                                            guard let data = data, error == nil else { return }
+                                                            // always update the UI from the main thread
+                                                            DispatchQueue.main.async() {
+                                                                ViewController.postButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                                            }
+                                                        }
+                                                    }
+                                                } else {
+                                                    ViewController.postButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
+                                                }
+                                            } else if count == 4 {
+                                                if !icon.isEmpty {
+                                                    DispatchQueue.global().async {
+                                                        ViewController.getDataImageFromUrl(from: URL(string: "https://nexilis.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) { data, response, error in
+                                                            guard let data = data, error == nil else { return }
+                                                            // always update the UI from the main thread
+                                                            DispatchQueue.main.async() {
+                                                                ViewController.streamingButton.setBackgroundImage(UIImage(data: data), for: .normal)
+                                                            }
+                                                        }
+                                                    }
+                                                } else {
+                                                    ViewController.streamingButton.setBackgroundImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withRenderingMode(.alwaysOriginal), for: .normal)
+                                                }
+                                            }
+                                            count += 1
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    public static func showDockedButton() {
+        ViewController.chatButton.isHidden = false
+        ViewController.callButton.isHidden = false
+        ViewController.ccButton.isHidden = false
+        ViewController.streamingButton.isHidden = false
+        ViewController.postButton.isHidden = false
+    }
+    
+    public static func hideDockedButton() {
+        ViewController.chatButton.isHidden = true
+        ViewController.callButton.isHidden = true
+        ViewController.ccButton.isHidden = true
+        ViewController.streamingButton.isHidden = true
+        ViewController.postButton.isHidden = true
+    }
+    
+    public static func expandButton() {
+        let cpaasMode = PrefsUtil.getCpaasMode()
+        if cpaasMode != PrefsUtil.CPAAS_MODE_DOCKED && cpaasMode != PrefsUtil.CPAAS_MODE_MIX {
+            return
+        }
+        if ViewController.alwaysHideButton && !ViewController.isExpandButton {
+            return
+        }
+        var minYIpX: CGFloat = 0
+        let iPhoneModel = getiPhoneModel()
+        if iPhoneModel == "iPhone X or newer" {
+            minYIpX += 20
+        }
+        if ViewController.isExpandButton {
+            ViewController.isExpandButton = false
+            let xChatPosition = ViewController.chatButton.frame.origin.x + 90
+            let yChatPosition = ViewController.chatButton.frame.origin.y + 20
+
+            let xCallPosition = ViewController.callButton.frame.origin.x + 55
+            let yCallPosition = ViewController.callButton.frame.origin.y + 70
+
+            let xCCPosition = ViewController.ccButton.frame.origin.x
+            let yCCPosition = ViewController.ccButton.frame.origin.y + 90
+
+            let xPostPosition = ViewController.postButton.frame.origin.x - 55
+            let yPostPosition = ViewController.postButton.frame.origin.y + 70
+
+            let xStreamingPosition = ViewController.streamingButton.frame.origin.x - 90
+            let yStreamingPosition = ViewController.streamingButton.frame.origin.y + 20
+            UIView.animate(withDuration: 0.5, animations: {
+//                if !ViewController.isBlue {
+//                    ViewController.middleButton.transform = CGAffineTransform(rotationAngle: 0)
+//                }
+                ViewController.chatButton.frame.origin = CGPoint(x: xChatPosition, y: yChatPosition + minYIpX)
+                ViewController.callButton.frame.origin = CGPoint(x: xCallPosition, y: yCallPosition + minYIpX)
+                ViewController.ccButton.frame.origin = CGPoint(x: xCCPosition, y: yCCPosition + minYIpX)
+                ViewController.streamingButton.frame.origin = CGPoint(x: xStreamingPosition, y: yStreamingPosition + minYIpX)
+                ViewController.postButton.frame.origin = CGPoint(x: xPostPosition, y: yPostPosition + minYIpX)
+            })
+            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
+                if !ViewController.isExpandButton {
+                    ViewController.hideDockedButton()
+                }
+            })
+        } else {
+            ViewController.isExpandButton = true
+            ViewController.showDockedButton()
+            let xChatPosition = ViewController.chatButton.frame.origin.x - 90
+            let yChatPosition = ViewController.chatButton.frame.origin.y - 20
+
+            let xCallPosition = ViewController.callButton.frame.origin.x - 55
+            let yCallPosition = ViewController.callButton.frame.origin.y - 70
+
+            let xCCPosition = ViewController.ccButton.frame.origin.x
+            let yCCPosition = ViewController.ccButton.frame.origin.y - 90
+
+            let xPostPosition = ViewController.postButton.frame.origin.x + 55
+            let yPostPosition = ViewController.postButton.frame.origin.y - 70
+
+            let xStreamingPosition = ViewController.streamingButton.frame.origin.x + 90
+            let yStreamingPosition = ViewController.streamingButton.frame.origin.y - 20
+            UIView.animate(withDuration: 0.5, animations: {
+//                if !ViewController.isBlue{
+//                    ViewController.middleButton.transform = CGAffineTransform(rotationAngle: .pi / 2)
+//                }
+                ViewController.chatButton.frame.origin = CGPoint(x: xChatPosition, y: yChatPosition - minYIpX)
+                ViewController.callButton.frame.origin = CGPoint(x: xCallPosition, y: yCallPosition - minYIpX)
+                ViewController.ccButton.frame.origin = CGPoint(x: xCCPosition, y: yCCPosition - minYIpX)
+                ViewController.streamingButton.frame.origin = CGPoint(x: xStreamingPosition, y: yStreamingPosition - minYIpX)
+                ViewController.postButton.frame.origin = CGPoint(x: xPostPosition, y: yPostPosition - minYIpX)
+            })
+        }
+    }
+    
+    public static func removeMiddleButton() {
+//        ViewController.chatButton.removeFromSuperview()
+//        ViewController.callButton.removeFromSuperview()
+//        ViewController.ccButton.removeFromSuperview()
+//        ViewController.streamingButton.removeFromSuperview()
+//        ViewController.postButton.removeFromSuperview()
+        ViewController.middleButton.isHidden = true
+    }
+    
+    public static func getDataImageFromUrl(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
+        let urlConfig = URLSessionConfiguration.default
+        let sessionDelegate = SelfSignedURLSessionDelegate()
+        let session = URLSession(configuration: urlConfig, delegate: sessionDelegate, delegateQueue: nil)
+        session.dataTask(with: url, completionHandler: completion).resume()
+    }
+
+}
+
+class EmptyTabViewController: UIViewController {
+    override func viewDidLoad() {
+        
+    }
+}
+                
+extension Bundle {
+    // Name of the app - title under the icon.
+    var displayName: String? {
+            return object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ??
+                object(forInfoDictionaryKey: "CFBundleName") as? String
+    }
+}
+
+extension BinaryInteger {
+    var degreesToRadians: CGFloat { CGFloat(self) * .pi / 180 }
+}
+
+extension FloatingPoint {
+    var degreesToRadians: Self { self * .pi / 180 }
+    var radiansToDegrees: Self { self * 180 / .pi }
+}
+
+extension UIImage {
+    class func imageWithColor(color: UIColor, size: CGSize) -> UIImage {
+        let rect: CGRect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
+        UIGraphicsBeginImageContextWithOptions(size, false, 0)
+        color.setFill()
+        UIRectFill(rect)
+        let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
+        UIGraphicsEndImageContext()
+        return image
+    }
+}
+
+extension String {
+    static func format(strings: [String],
+                    italicFont: UIFont = UIFont.italicSystemFont(ofSize: 12),
+                    italicColor: UIColor = UIColor.systemGreen,
+                    inString string: String,
+                    font: UIFont = UIFont.systemFont(ofSize: 12),
+                    color: UIColor = UIColor.black) -> NSAttributedString {
+        let attributedString =
+            NSMutableAttributedString(string: string,
+                                    attributes: [
+                                        NSAttributedString.Key.font: font,
+                                        NSAttributedString.Key.foregroundColor: color])
+        let italicFontAttribute = [NSAttributedString.Key.font: italicFont, NSAttributedString.Key.foregroundColor: italicColor]
+        for italic in strings {
+            attributedString.addAttributes(italicFontAttribute, range: (string as NSString).range(of: italic))
+        }
+        return attributedString
+    }
+}
+
+extension UILabel {
+    func indexOfAttributedTextCharacterAtPoint(point: CGPoint) -> Int {
+        assert(self.attributedText != nil, "This method is developed for attributed string")
+        let textStorage = NSTextStorage(attributedString: self.attributedText!)
+        let layoutManager = NSLayoutManager()
+        textStorage.addLayoutManager(layoutManager)
+        let textContainer = NSTextContainer(size: self.frame.size)
+        textContainer.lineFragmentPadding = 0
+        textContainer.maximumNumberOfLines = self.numberOfLines
+        textContainer.lineBreakMode = self.lineBreakMode
+        layoutManager.addTextContainer(textContainer)
+
+        let index = layoutManager.characterIndex(for: point, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
+        return index
+    }
+}

BIN
AppBuilder/AppBuilder/bi_icon.png


BIN
AppBuilder/AppBuilder/bpkh_icon.png


BIN
AppBuilder/AppBuilder/diginets_icon.png


BIN
AppBuilder/AppBuilder/digisales_icon.png


BIN
AppBuilder/AppBuilder/disini_icon.png


BIN
AppBuilder/AppBuilder/gudeg_icon.png


BIN
AppBuilder/AppBuilder/ikn_icon.png


BIN
AppBuilder/AppBuilder/kmi_icon.png


BIN
AppBuilder/AppBuilder/nu_icon.png


BIN
AppBuilder/AppBuilder/nxcook_icon.png


BIN
AppBuilder/AppBuilder/nxsport_icon.png


+ 21 - 0
AppBuilder/NotificationService/Info.plist

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>NSExtension</key>
+	<dict>
+		<key>NSExtensionAttributes</key>
+		<dict>
+			<key>IntentsSupported</key>
+			<array>
+				<string>INSendMessageIntent</string>
+				<string></string>
+			</array>
+		</dict>
+		<key>NSExtensionPointIdentifier</key>
+		<string>com.apple.usernotifications.service</string>
+		<key>NSExtensionPrincipalClass</key>
+		<string>$(PRODUCT_MODULE_NAME).NotificationService</string>
+	</dict>
+</dict>
+</plist>

+ 81 - 0
AppBuilder/NotificationService/NotificationService.swift

@@ -0,0 +1,81 @@
+//
+//  NotificationService.swift
+//  BeautifulIndonesiaNotificationService
+//
+//  Created by Akhmad Al Qindi Irsyam on 01/03/23.
+//
+
+import UserNotifications
+import Intents
+import UIKit
+
+class NotificationService: UNNotificationServiceExtension {
+
+    var contentHandler: ((UNNotificationContent) -> Void)?
+    var bestAttemptContent: UNMutableNotificationContent?
+
+    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
+        self.contentHandler = contentHandler
+        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
+        
+        guard let bestAttemptContent = bestAttemptContent else {
+            return
+        }
+        
+        // Check if the notification is a communication notification
+        let categoryIdentifier = bestAttemptContent.categoryIdentifier
+        if categoryIdentifier != "chat" {
+            contentHandler(bestAttemptContent)
+            return
+        }
+        
+        let avatarDefault = INImage(imageData: UIImage(systemName: "person.circle.fill")!.withTintColor(.gray).pngData()!)
+        var sender = INPerson(personHandle: INPersonHandle(value: "02cdfdfdac", type: .unknown), nameComponents: nil, displayName: "Meme", image: avatarDefault, contactIdentifier: "02cdfdfdac", customIdentifier: "02cdfdfdac")
+        
+//        sender = INPerson(personHandle: INPersonHandle(value: "02cdfdfdac", type: .unknown), nameComponents: nil, displayName: "Meme", image: INImage(url: URL(string: "https://i.pinimg.com/474x/69/77/b7/6977b70a129ec184527433bbdf9fe457.jpg")!), contactIdentifier: "02cdfdfdac", customIdentifier: nil)
+        
+//        let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
+//        let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
+//        let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
+//        if let dirPath = paths.first {
+//            let fileURL = URL(fileURLWithPath: dirPath).appendingPathComponent("6977b70a129ec184527433bbdf9fe457.jpg")
+//            if FileManager.default.fileExists(atPath: fileURL.path) {
+//                sender = INPerson(personHandle: INPersonHandle(value: "02cdfdfdac", type: .unknown), nameComponents: nil, displayName: "Hansen", image: INImage(url: ), contactIdentifier: "02cdfdfdac", customIdentifier: nil)
+//            }
+//        }
+
+        let incomingMessageIntent = INSendMessageIntent(recipients: [sender], outgoingMessageType: .outgoingMessageText, content: nil, speakableGroupName: INSpeakableString(spokenPhrase: "Test Group"), conversationIdentifier: "Test Group", serviceName: nil, sender: sender, attachments: nil)
+        incomingMessageIntent.setImage(avatarDefault, forParameterNamed: \.speakableGroupName)
+
+        let interaction = INInteraction(intent: incomingMessageIntent, response: nil)
+        interaction.direction = .incoming
+        interaction.donate { error in
+            if let error = error {
+                contentHandler(bestAttemptContent)
+                return
+            }
+            
+            let content = UNMutableNotificationContent()
+            content.subtitle = "testing subTitle"
+            content.body = "testing body"
+            content.sound = .default
+            let myRequest = UNNotificationRequest(identifier: "02cdfdfdac", content: content, trigger: nil)
+            let myContent = myRequest.content
+
+            do {
+                // Update notification content before displaying the
+                // communication notification.
+                if #available(iOSApplicationExtension 15.0, *) {
+                    let updatedContent = try myContent.updating(from: incomingMessageIntent)
+                    contentHandler(updatedContent)
+                } else {
+                    contentHandler(bestAttemptContent)
+                }
+
+            } catch {
+                contentHandler(bestAttemptContent)
+            }
+        }
+    }
+
+}

+ 35 - 0
AppBuilder/Podfile

@@ -0,0 +1,35 @@
+# Uncomment the next line to define a global platform for your project
+# platform :ios, '9.0'
+
+target 'AppBuilder' do
+  # Comment the next line if you don't want to use dynamic frameworks
+  use_frameworks!
+
+  pod 'NexilisLite', :path => '../NexilisLite'
+#  pod 'nuSDKService', '~> 0.0.8'
+#  pod 'FMDB', '~> 2.7.5'
+#  pod 'NotificationBannerSwift', '~> 3.2.1'
+#  pod 'Alamofire', '~> 5.7.0'
+#  pod 'SDWebImage', '~> 5.15.7'
+#  pod 'Toast-Swift', '~> 5.0.1'
+
+  # Pods for AppBuilder
+
+  # target 'AppBuilderTests' do
+    #inherit! :search_paths
+    # Pods for testing
+  # end
+
+  #target 'AppBuilderUITests' do
+    # Pods for testing
+  #end
+  
+#  post_install do |installer|
+#    installer.pods_project.targets.each do |target|
+#      target.build_configurations.each do |config|
+#        config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
+#      end
+#    end
+#  end
+
+end

BIN
NexilisLite/.DS_Store


+ 8 - 0
NexilisLite/LICENSE

@@ -0,0 +1,8 @@
+MIT License
+Copyright (c) <year> <copyright holders>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 42 - 0
NexilisLite/NexilisLite.podspec

@@ -0,0 +1,42 @@
+#
+#  Be sure to run `pod spec lint PalioLite.podspec' to ensure this is a
+#  valid spec and to remove all comments including this before submitting the spec.
+#
+#  To learn more about Podspec attributes see https://guides.cocoapods.org/syntax/podspec.html
+#  To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
+#
+
+Pod::Spec.new do |spec|
+  spec.name         = "NexilisLite"
+  spec.version      = "3.3.1"
+  spec.summary      = "NexilisLite Framework"
+  spec.description  = <<-DESC
+  NexilisLite Framework, embed Contact Center, Live Streaming, Push Notifications, Instant Messaging, Video and VoIP Calling features into your mobile apps within minutes...
+                   DESC
+
+  spec.homepage     = "https://nexilis.io/"
+  spec.license      = "MIT"
+  spec.author       = { "Yayan D Wicaksono" => "ya2n.wicaksono@gmail.com" }
+  spec.ios.deployment_target = "14.0"
+#  spec.source       = { :http => 'https://nexilis.io/UCPaaSiOS/releases/download/NexilisLite/v2.2.2/NexilisLite.zip' }
+  spec.source       = { :path => '.' }
+  spec.source_files = 'NexilisLite/Source/**/*'
+  spec.resource_bundles = { 'NexilisLite' => ['NexilisLite/Resource/**/*']}
+  spec.swift_version = '5.5.1'
+  spec.dependency 'FMDB', '~> 2.7.12'
+  spec.dependency 'nuSDKService', '~> 3.0.1'
+  spec.dependency 'NotificationBannerSwift', '~> 3.1.0'
+  spec.dependency 'Alamofire', '~> 5.10.1'
+  spec.dependency 'SDWebImage', '~> 5.20.0'
+  spec.dependency 'Toast-Swift', '~> 5.1.1'
+  spec.dependency 'ZIPFoundation', '~> 0.9.19'
+  spec.dependency 'SwiftLinkPreview', '~> 3.4.0'
+  spec.dependency 'KeychainAccess'
+  spec.dependency 'Popover'
+#  spec.static_framework = true
+# spec.dependency 'iOS-WebP'
+#  spec.vendored_frameworks = 'nuSDKService.framework'
+  spec.ios.vendored_frameworks = "NexilisLite.framework"
+  spec.pod_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64', 'ENABLE_BITCODE' => 'NO' }
+  spec.user_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64', 'ENABLE_BITCODE' => 'NO' }
+end

BIN
NexilisLite/NexilisLite/.DS_Store


+ 84 - 0
NexilisLite/NexilisLite/Info.plist

@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
+	<key>CFBundleShortVersionString</key>
+	<string>$(MARKETING_VERSION)</string>
+	<key>CFBundleVersion</key>
+	<string>$(CURRENT_PROJECT_VERSION)</string>
+    <key>NSCameraUsageDescription</key>
+    <string>Video Call, Conference Room, Content Creation and Live Streaming.</string>
+    <key>NSLocationWhenInUseUsageDescription</key>
+    <string>Access Location For Multiple Login.</string>
+    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
+    <string>Access Location For Multiple Login.</string>
+    <key>NSContactsUsageDescription</key>
+    <string>Get File Contact from Local Dictionary for Send Message.</string>
+    <key>NSDocumentsFolderUsageDescription</key>
+    <string>Get File from Local Dictionary for Send Message.</string>
+    <key>NSMicrophoneUsageDescription</key>
+    <string>VoIP Call, Video Call, Conference Room, and Live Streaming.</string>
+    <key>NSMotionUsageDescription</key>
+    <string>Service nuSDK.</string>
+    <key>NSPhotoLibraryAddUsageDescription</key>
+    <string>Get File Photos from Local Dictionary for Send Message and Content Creation.</string>
+    <key>NSPhotoLibraryUsageDescription</key>
+    <string>Get File Photos from Local Dictionary for Send Message and Content Creation.</string>
+    <key>NSSpeechRecognitionUsageDescription</key>
+    <string>Used for speech recognition features.</string>
+    <key>NSAppTransportSecurity</key>
+        <dict>
+            <key>NSAllowsArbitraryLoads</key>
+            <true/>
+        </dict>
+    <key>NSUserActivityTypes</key>
+    <array>
+        <string>INSendMessageIntent</string>
+    </array>
+    <key>LSApplicationQueriesSchemes</key>
+    <array>
+        <string>whatsapp</string>
+        <string>googlegmail</string>
+        <string>ms-outlook</string>
+        <string>readdle-spark</string>
+        <string>ymail</string>
+    </array>
+    <key>UIViewControllerBasedStatusBarAppearance</key>
+    <true/>
+    <key>UIUserInterfaceStyle</key>
+    <string>Automatic</string>
+    <key>UIBackgroundModes</key>
+    <array>
+        <string>audio</string>
+        <string>bluetooth-central</string>
+        <string>bluetooth-peripheral</string>
+        <string>external-accessory</string>
+        <string>fetch</string>
+        <string>processing</string>
+        <string>remote-notification</string>
+        <string>voip</string>
+    </array>
+	<key>UIAppFonts</key>
+	<array>
+		<string>fonts/Poppins-Light.ttf</string>
+		<string>fonts/Poppins-LightItalic.ttf</string>
+		<string>fonts/Poppins-Medium.ttf</string>
+		<string>fonts/Poppins-MediumItalic.ttf</string>
+		<string>fonts/Poppins-Regular.ttf</string>
+		<string>fonts/Poppins-SemiBold.ttf</string>
+		<string>fonts/Poppins-SemiBoldItalic.ttf</string>
+	</array>
+</dict>
+</plist>

+ 13 - 0
NexilisLite/NexilisLite/NexilisLite.docc/NexilisLite.md

@@ -0,0 +1,13 @@
+# ``NexilisLite``
+
+<!--@START_MENU_TOKEN@-->Summary<!--@END_MENU_TOKEN@-->
+
+## Overview
+
+<!--@START_MENU_TOKEN@-->Text<!--@END_MENU_TOKEN@-->
+
+## Topics
+
+### <!--@START_MENU_TOKEN@-->Group<!--@END_MENU_TOKEN@-->
+
+- <!--@START_MENU_TOKEN@-->``Symbol``<!--@END_MENU_TOKEN@-->

+ 18 - 0
NexilisLite/NexilisLite/NexilisLite.h

@@ -0,0 +1,18 @@
+//
+//  NexilisLite.h
+//  NexilisLite
+//
+//  Created by Akhmad Al Qindi Irsyam on 10/05/23.
+//
+
+#import <Foundation/Foundation.h>
+
+//! Project version number for NexilisLite.
+FOUNDATION_EXPORT double NexilisLiteVersionNumber;
+
+//! Project version string for NexilisLite.
+FOUNDATION_EXPORT const unsigned char NexilisLiteVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import <NexilisLite/PublicHeader.h>
+
+

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/Attachment.imageset/Attachment.png


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/Attachment.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "Attachment.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/Camera.imageset/Camera.png


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/Camera.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "Camera.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 6 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/Conversation---Black.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "Conversation---Black.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/Conversation---Black.imageset/Conversation---Black.png


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/Conversation---Purple.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "Conversation---Purple.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/Conversation---Purple.imageset/Conversation---Purple.png


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/File---Documents.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "File---Documents.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/File---Documents.imageset/File---Documents.png


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/Profile---Black.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "Profile---Black.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/Profile---Black.imageset/Profile---Black.png


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/Profile---Purple.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "Profile---Purple.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/Profile---Purple.imageset/Profile---Purple.png


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/Q-Button-PNG.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "Q-Button-PNG.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/Q-Button-PNG.imageset/Q-Button-PNG.png


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/Send-(White).imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "Send-(White).png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/Send-(White).imageset/Send-(White).png


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/Send---Purple.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "Send---Purple.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/Send---Purple.imageset/Send---Purple.png


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/Send-Image.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "Send-Image.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/Send-Image.imageset/Send-Image.png


BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/Sofa.imageset/1-Furniture-Single-Sofa-196.jpg


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/Sofa.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "1-Furniture-Single-Sofa-196.jpg",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/Sticker---Emoji.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "Sticker---Emoji.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/Sticker---Emoji.imageset/Sticker---Emoji.png


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/Voice-Command.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "Voice-Command.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/Voice-Command.imageset/Voice-Command.png


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/Voice-Record.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "Voice-Record.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/Voice-Record.imageset/Voice-Record.png


Some files were not shown because too many files changed in this diff