FloatingButton.swift 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. //
  2. // FloatingButton.swift
  3. // Qmera
  4. //
  5. // Created by Yayan Dwi on 03/09/21.
  6. //
  7. import UIKit
  8. import nuSDKService
  9. import NotificationBannerSwift
  10. public class FloatingButton: UIView {
  11. var groupView: UIStackView!
  12. var scrollView: UIScrollView!
  13. var button_fb1: UIButton!
  14. var button_fb2: UIButton!
  15. var button_fb3: UIButton!
  16. var button_fb4: UIButton!
  17. var nexilis_button: UIImageView!
  18. var nexilis_pin: UIImageView!
  19. var leadingConstraintPin: NSLayoutConstraint!
  20. var bottomConstraintPin: NSLayoutConstraint!
  21. var trailingConstraintPin: NSLayoutConstraint!
  22. var topConstraintPin: NSLayoutConstraint!
  23. var lastPosY: CGFloat?
  24. var lastImageButton = ""
  25. var iconCC = ""
  26. let indicatorCounterFB = UIView()
  27. let labelCounterFB = UILabel()
  28. let indicatorCounterFBBig = UIImageView()
  29. var datePull: Date?
  30. var animationTimer = Timer()
  31. var configAnim: Int = Int(Utils.getFloatingAnim().components(separatedBy: "~")[0]) ?? 1
  32. var isLoopingAnim = (Int(Utils.getFloatingAnim().components(separatedBy: "~")[1]) ?? 1) == 1 ? true : false
  33. var lastRunAnimationHrz = -1
  34. var lastRunAnimationVrt = -1
  35. var panGesture: UIPanGestureRecognizer?
  36. var defaultWidthFB = (UIScreen.main.bounds.height * 0.5) / 7.5
  37. var defaultHeightFB = (UIScreen.main.bounds.height * 0.5) / 7.5
  38. let defaultWidthHeightMenuFB = (UIScreen.main.bounds.height * 0.45) / 7.5
  39. let widthFBAnim = (UIScreen.main.bounds.height * 0.8) / 7.5
  40. let heightFBAnim = (UIScreen.main.bounds.height * 1) / 7.5
  41. let heightFBSideTab = (UIScreen.main.bounds.height * 1.05) / 7.5
  42. let widthFBSideTab: CGFloat = 18
  43. final let MODE_VERTICAL_FLOATING_BUTTON = "1"
  44. final let MODE_VERTICAL_ANIMATION = "2"
  45. final let MODE_HORIZONTAL_ANIMATION = "3"
  46. final let MODE_HORIZONTAL_SIDE_TAB = "4"
  47. var countMenuFB: CGFloat = 5 {
  48. didSet {
  49. if isShow {
  50. show(isShow: isShow)
  51. }
  52. }
  53. }
  54. public weak var mySettingDelegate: SettingMABDelegate?
  55. public var isShow: Bool = false
  56. override init(frame: CGRect) {
  57. super.init(frame: frame)
  58. commonInit()
  59. }
  60. required init?(coder: NSCoder) {
  61. super.init(coder: coder)
  62. commonInit()
  63. }
  64. private func commonInit() {
  65. panGesture = UIPanGestureRecognizer(target: self, action: #selector(draggedView(_:)))
  66. addGestureRecognizer(panGesture!)
  67. nexilis_button = UIImageView()
  68. nexilis_button.translatesAutoresizingMaskIntoConstraints = false
  69. nexilis_button.isUserInteractionEnabled = true
  70. var dataImage: Data?
  71. if Utils.getConfigModeFB() == MODE_VERTICAL_ANIMATION || Utils.getConfigModeFB() == MODE_HORIZONTAL_ANIMATION {
  72. defaultWidthFB = widthFBAnim
  73. defaultHeightFB = heightFBAnim
  74. nexilis_button.sd_setImage(with: URL(string: Utils.getConfigModeFB() == MODE_VERTICAL_ANIMATION ? Utils.getIconCenterAnim2()! : Utils.getIconCenterAnim4()!)) { [self] (image, error, cacheType, imageURL) in
  75. if error != nil {
  76. //print("Error loading GIF: \(error.localizedDescription)")
  77. } else {
  78. // Configure the animation
  79. nexilis_button.animationImages = image?.images
  80. nexilis_button.animationDuration = image?.duration ?? 0.0
  81. nexilis_button.animationRepeatCount = 0
  82. nexilis_button.startAnimating()
  83. }
  84. }
  85. } else {
  86. if !Utils.getIconDock().isEmpty && Utils.getConfigModeFB() == MODE_VERTICAL_FLOATING_BUTTON {
  87. dataImage = try? Data(contentsOf: URL(string: Utils.getUrlDock()!)!)
  88. if dataImage != nil {
  89. if let image = UIImage(data: dataImage!) {
  90. nexilis_button.image = image
  91. } else {
  92. nexilis_button.image = UIImage(named: Utils.getFBIconBg() == "1" ? "pb_button" : "pb_ball", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
  93. }
  94. } else {
  95. nexilis_button.image = UIImage(named: Utils.getFBIconBg() == "1" ? "pb_button" : "pb_ball", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
  96. }
  97. } else {
  98. if Utils.getConfigModeFB() == MODE_HORIZONTAL_SIDE_TAB {
  99. defaultWidthFB = widthFBSideTab
  100. defaultHeightFB = heightFBSideTab
  101. }
  102. nexilis_button.image = UIImage(named: Utils.getConfigModeFB() != MODE_HORIZONTAL_SIDE_TAB ? "pb_button" : "pb_side_tab", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
  103. }
  104. }
  105. backgroundColor = .clear
  106. frame = CGRect(x: UIScreen.main.bounds.width - defaultWidthFB, y: (UIScreen.main.bounds.height / 2) - defaultHeightFB, width: Utils.getConfigModeFB() == MODE_HORIZONTAL_SIDE_TAB ? UIScreen.main.bounds.width - defaultWidthFB : defaultWidthFB, height: defaultHeightFB)
  107. if Utils.getConfigModeFB() == MODE_VERTICAL_ANIMATION || Utils.getConfigModeFB() == MODE_HORIZONTAL_ANIMATION {
  108. if configAnim == 0 { //left to right
  109. lastRunAnimationHrz = 1
  110. } else if configAnim == 1 { //right to left
  111. lastRunAnimationHrz = -1
  112. } else if configAnim == 2 { //top to bottom
  113. lastRunAnimationVrt = 1
  114. } else if configAnim == 3 { //top to bottom
  115. lastRunAnimationVrt = -1
  116. }
  117. if configAnim >= 0 && configAnim <= 3 {
  118. checkDelayAnimation()
  119. }
  120. }
  121. let qmeraTap = UITapGestureRecognizer(target: self, action: #selector(qmeraTap))
  122. qmeraTap.numberOfTouchesRequired = 1
  123. nexilis_button.addGestureRecognizer(qmeraTap)
  124. let qmeraLongPress = UILongPressGestureRecognizer(target: self, action: #selector(qmeraLongPress(gestureRecognizer:)))
  125. nexilis_button.addGestureRecognizer(qmeraLongPress)
  126. addSubview(nexilis_button)
  127. nexilis_button.widthAnchor.constraint(equalToConstant: defaultWidthFB).isActive = true
  128. nexilis_button.heightAnchor.constraint(equalToConstant: defaultHeightFB).isActive = true
  129. nexilis_button.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
  130. nexilis_button.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
  131. scrollView = UIScrollView()
  132. scrollView.translatesAutoresizingMaskIntoConstraints = false
  133. if Utils.getFBItemBg() == "1" && Utils.getConfigModeFB() == MODE_VERTICAL_FLOATING_BUTTON {
  134. scrollView.layer.borderWidth = 1.0
  135. scrollView.layer.borderColor = UIColor.white.cgColor
  136. scrollView.layer.cornerRadius = 8.0
  137. scrollView.layer.masksToBounds = true
  138. scrollView.backgroundColor = .black.withAlphaComponent(0.25)
  139. }
  140. addSubview(scrollView)
  141. if Utils.getConfigModeFB() != MODE_HORIZONTAL_SIDE_TAB {
  142. scrollView.topAnchor.constraint(equalTo: topAnchor).isActive = true
  143. if Utils.getConfigModeFB() == MODE_VERTICAL_ANIMATION {
  144. scrollView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
  145. scrollView.leftAnchor.constraint(equalTo: nexilis_button.rightAnchor, constant: -20).isActive = true
  146. scrollView.widthAnchor.constraint(equalToConstant: defaultWidthHeightMenuFB + 10).isActive = true
  147. scrollView.isHidden = true
  148. } else if Utils.getConfigModeFB() == MODE_HORIZONTAL_ANIMATION {
  149. scrollView.bottomAnchor.constraint(equalTo: nexilis_button.topAnchor).isActive = true
  150. scrollView.leftAnchor.constraint(equalTo: nexilis_button.leftAnchor).isActive = true
  151. scrollView.widthAnchor.constraint(equalToConstant: defaultWidthHeightMenuFB * (countMenuFB - 1)).isActive = true
  152. } else {
  153. scrollView.widthAnchor.constraint(equalToConstant: defaultWidthHeightMenuFB + 10).isActive = true
  154. scrollView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
  155. scrollView.bottomAnchor.constraint(equalTo: nexilis_button.topAnchor).isActive = true
  156. }
  157. } else {
  158. scrollView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width - defaultWidthFB).isActive = true
  159. scrollView.heightAnchor.constraint(equalToConstant: defaultHeightFB).isActive = true
  160. scrollView.leftAnchor.constraint(equalTo: nexilis_button.rightAnchor).isActive = true
  161. scrollView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
  162. scrollView.backgroundColor = .black.withAlphaComponent(0.25)
  163. }
  164. groupView = UIStackView()
  165. groupView.translatesAutoresizingMaskIntoConstraints = false
  166. groupView.axis = (Utils.getConfigModeFB() == MODE_HORIZONTAL_SIDE_TAB || Utils.getConfigModeFB() == MODE_HORIZONTAL_ANIMATION) ? .horizontal : .vertical
  167. if Utils.getConfigModeFB() != MODE_HORIZONTAL_SIDE_TAB && Utils.getConfigModeFB() != MODE_HORIZONTAL_ANIMATION {
  168. groupView.distribution = .fillEqually
  169. }
  170. scrollView.addSubview(groupView)
  171. if Utils.getConfigModeFB() == MODE_HORIZONTAL_SIDE_TAB {
  172. groupView.leftAnchor.constraint(equalTo: scrollView.leftAnchor).isActive = true
  173. groupView.rightAnchor.constraint(equalTo: scrollView.rightAnchor).isActive = true
  174. groupView.centerYAnchor.constraint(equalTo: scrollView.centerYAnchor).isActive = true
  175. groupView.heightAnchor.constraint(equalToConstant: defaultHeightFB - 10).isActive = true
  176. } else {
  177. groupView.widthAnchor.constraint(equalToConstant: Utils.getConfigModeFB() == MODE_HORIZONTAL_ANIMATION ? defaultWidthHeightMenuFB * (countMenuFB - 1) : defaultWidthHeightMenuFB).isActive = true
  178. groupView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: Utils.getConfigModeFB() == MODE_HORIZONTAL_ANIMATION ? 0 : 5).isActive = true
  179. groupView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: Utils.getConfigModeFB() == MODE_HORIZONTAL_ANIMATION ? 0 : -5).isActive = true
  180. groupView.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: Utils.getConfigModeFB() == MODE_HORIZONTAL_ANIMATION ? 0 : 6).isActive = true
  181. }
  182. pullButton()
  183. let center: NotificationCenter = NotificationCenter.default
  184. center.addObserver(self, selector: #selector(imageFBUpdate(notification:)), name: NSNotification.Name(rawValue: "imageFBUpdate"), object: nil)
  185. center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil)
  186. center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil)
  187. let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hideButton))
  188. tapGesture.cancelsTouchesInView = false
  189. UIApplication.shared.windows.first?.rootViewController?.view.addGestureRecognizer(tapGesture)
  190. }
  191. private func checkDelayAnimation() {
  192. DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: { [self] in
  193. if !isShow {
  194. animationTimer = Timer.scheduledTimer(timeInterval: 0.001, target: self, selector: #selector(runAnimation), userInfo: nil, repeats: true)
  195. }
  196. })
  197. }
  198. @objc func runAnimation(){
  199. DispatchQueue.main.async { [self] in
  200. if configAnim == 0 || configAnim == 1 {
  201. if (lastRunAnimationHrz == -1 && frame.origin.x >= 0) || lastRunAnimationHrz == 1 && frame.origin.x <= UIScreen.main.bounds.width - defaultWidthFB {
  202. if lastRunAnimationHrz == -1 {
  203. frame.origin.x-=0.1
  204. } else {
  205. frame.origin.x+=0.1
  206. }
  207. } else {
  208. lastRunAnimationHrz = lastRunAnimationHrz == 1 ? -1 : 1
  209. if (lastRunAnimationHrz == -1 && configAnim == 1) || (lastRunAnimationHrz == 1 && configAnim == 0) {
  210. animationTimer.invalidate()
  211. if isLoopingAnim {
  212. checkDelayAnimation()
  213. }
  214. }
  215. }
  216. } else {
  217. if (lastRunAnimationVrt == -1 && frame.origin.y >= 0) || lastRunAnimationVrt == 1 && frame.origin.y <= UIScreen.main.bounds.height - defaultHeightFB {
  218. if lastRunAnimationVrt == -1 {
  219. frame.origin.y-=0.1
  220. } else {
  221. frame.origin.y+=0.1
  222. }
  223. } else {
  224. lastRunAnimationVrt = lastRunAnimationVrt == 1 ? -1 : 1
  225. if (lastRunAnimationVrt == -1 && configAnim == 3) || (lastRunAnimationVrt == 1 && configAnim == 2) {
  226. animationTimer.invalidate()
  227. if isLoopingAnim {
  228. checkDelayAnimation()
  229. }
  230. }
  231. }
  232. }
  233. }
  234. }
  235. private func pullButton() {
  236. if datePull == nil || Int(Date().timeIntervalSince(datePull!)) >= 60 {
  237. datePull = Date()
  238. } else if Int(Date().timeIntervalSince(datePull!)) < 60 {
  239. return
  240. }
  241. if !CheckConnection.isConnectedToNetwork() || API.nGetCLXConnState() == 0 {
  242. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  243. imageView.tintColor = .white
  244. 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)
  245. banner.show()
  246. return
  247. }
  248. if groupView.subviews.count == 0 {
  249. getDefaultButton()
  250. }
  251. DispatchQueue.global().async { [self] in
  252. if !Utils.getCustomButtons().isEmpty && Utils.getConfigModeFB() != MODE_HORIZONTAL_SIDE_TAB && Utils.getConfigModeFB() != MODE_HORIZONTAL_ANIMATION {
  253. DispatchQueue.main.async { [self] in
  254. groupView.subviews.forEach({ $0.removeFromSuperview() })
  255. let customButtons = Utils.getCustomButtons().components(separatedBy: ",")
  256. let customIcons = Utils.getCustomFBIcon().components(separatedBy: ",")
  257. countMenuFB = CGFloat(customButtons.count > 5 ? 5 : customButtons.count)
  258. for i in 0..<customButtons.count {
  259. let package_id = customButtons[i]
  260. let app_id = ""
  261. let icon = customIcons[i]
  262. let newButton = UIButton()
  263. newButton.heightAnchor.constraint(equalToConstant: defaultWidthHeightMenuFB).isActive = true
  264. newButton.translatesAutoresizingMaskIntoConstraints = false
  265. DispatchQueue.global().async {
  266. let data = try? Data(contentsOf: URL(string: "https://nexilis.io/dashboardv2/uploads/fb_icon/\(icon)")!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
  267. DispatchQueue.main.async {
  268. if data != nil {
  269. newButton.setImage(UIImage(data: data!), for: .normal)
  270. }
  271. }
  272. }
  273. groupView.addArrangedSubview(newButton)
  274. newButton.restorationIdentifier = package_id
  275. newButton.accessibilityIdentifier = app_id
  276. newButton.addTarget(self, action: #selector(fbTap), for: .touchUpOutside)
  277. }
  278. }
  279. return
  280. }
  281. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.pullFloatingButton(), timeout: 30 * 1000){
  282. if response.isOk() {
  283. let data = response.getBody(key: CoreMessage_TMessageKey.DATA, default_value: "")
  284. if !data.isEmpty {
  285. if let jsonArray = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [AnyObject] {
  286. DispatchQueue.main.async { [self] in
  287. groupView.subviews.forEach({ $0.removeFromSuperview() })
  288. if jsonArray.count == 0 {
  289. countMenuFB = CGFloat(4)
  290. getDefaultButton()
  291. } else {
  292. if Utils.getConfigModeFB() != MODE_HORIZONTAL_ANIMATION {
  293. countMenuFB = CGFloat(jsonArray.count > 5 ? 5 : jsonArray.count)
  294. } else {
  295. countMenuFB = CGFloat(jsonArray.filter({ $0["mode"] as? Int == Int(MODE_HORIZONTAL_ANIMATION) }).count)
  296. }
  297. for json in jsonArray {
  298. let package_id = json["package_id"] as! String
  299. let app_id = (json["app_id"] as? String) ?? ""
  300. let icon = (json["icon"] as? String) ?? ""
  301. let mode = "\((json["mode"] as? Int) ?? 1)"
  302. let newButton = UIButton()
  303. if mode != Utils.getConfigModeFB() {
  304. continue
  305. }
  306. if mode == MODE_HORIZONTAL_SIDE_TAB {
  307. newButton.widthAnchor.constraint(equalToConstant: defaultHeightFB - 10).isActive = true
  308. newButton.heightAnchor.constraint(equalToConstant: defaultHeightFB - 10).isActive = true
  309. } else if mode == MODE_HORIZONTAL_ANIMATION {
  310. newButton.widthAnchor.constraint(equalToConstant: defaultWidthHeightMenuFB).isActive = true
  311. newButton.heightAnchor.constraint(equalToConstant: defaultWidthHeightMenuFB).isActive = true
  312. } else {
  313. newButton.heightAnchor.constraint(equalToConstant: defaultWidthHeightMenuFB).isActive = true
  314. }
  315. newButton.translatesAutoresizingMaskIntoConstraints = false
  316. var indexTap = 0
  317. if package_id.contains("_fb"){
  318. let numIdx = package_id.split(separator: "_")[1]
  319. indexTap = Int(String(numIdx).substring(from: 2, to: numIdx.count))!
  320. }
  321. if indexTap == Nexilis.IDX_CHAT {
  322. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_chat" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_chat" : "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  323. } else if indexTap == Nexilis.IDX_CONVERSATION {
  324. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_conversation" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_conversation" : "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  325. } else if indexTap == Nexilis.IDX_CALL {
  326. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_call" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_call" : "pb_button_call", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  327. } else if indexTap == Nexilis.IDX_CC {
  328. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_cc" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_cc" : "pb_button_cc", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  329. } else if indexTap == Nexilis.IDX_STREAM {
  330. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_stream" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_stream" : "pb_button_stream", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  331. } else if indexTap == Nexilis.IDX_SOCIAL_COMMERCE {
  332. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_social_commerce" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_commerce" : "pb_button_commerce", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  333. } else if indexTap == Nexilis.IDX_NEWS {
  334. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_news" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_news" : "pb_button_news", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  335. } else if indexTap == Nexilis.IDX_POST {
  336. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_post" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_post" : "pb_button_post", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  337. } else if indexTap == Nexilis.IDX_NOTIF_CENTER {
  338. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_notif_center" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_notif_center" : "pb_button_notification", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  339. } else {
  340. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_more" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_more" : "pb_button_others", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  341. }
  342. if !icon.isEmpty {
  343. DispatchQueue.global().async {
  344. let data = try? Data(contentsOf: URL(string: "https://newuniverse.io/get_file?account=\(Nexilis.sAPIKey)&image=\(icon)")!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
  345. DispatchQueue.main.async {
  346. if data != nil {
  347. newButton.setImage(UIImage(data: data!), for: .normal)
  348. }
  349. }
  350. }
  351. }
  352. groupView.addArrangedSubview(newButton)
  353. newButton.restorationIdentifier = package_id
  354. newButton.accessibilityIdentifier = app_id
  355. newButton.addTarget(self, action: #selector(fbTap), for: .touchUpOutside)
  356. }
  357. }
  358. }
  359. }
  360. } else {
  361. groupView.subviews.forEach({ $0.removeFromSuperview() })
  362. getDefaultButton()
  363. }
  364. } else {
  365. groupView.subviews.forEach({ $0.removeFromSuperview() })
  366. getDefaultButton()
  367. }
  368. }
  369. }
  370. }
  371. func getDefaultButton() {
  372. let data = [Nexilis.IDX_NOTIF_CENTER, Nexilis.IDX_CC, Nexilis.IDX_CONVERSATION, Nexilis.IDX_CALL, Nexilis.IDX_STREAM]
  373. for i in 0..<data.count {
  374. let newButton = UIButton()
  375. let mode = Utils.getConfigModeFB()
  376. if mode == MODE_HORIZONTAL_SIDE_TAB {
  377. newButton.widthAnchor.constraint(equalToConstant: defaultHeightFB - 10).isActive = true
  378. newButton.heightAnchor.constraint(equalToConstant: defaultHeightFB - 10).isActive = true
  379. } else if mode == MODE_HORIZONTAL_ANIMATION {
  380. newButton.widthAnchor.constraint(equalToConstant: defaultWidthHeightMenuFB).isActive = true
  381. newButton.heightAnchor.constraint(equalToConstant: defaultWidthHeightMenuFB).isActive = true
  382. } else {
  383. newButton.heightAnchor.constraint(equalToConstant: defaultWidthHeightMenuFB).isActive = true
  384. }
  385. newButton.translatesAutoresizingMaskIntoConstraints = false
  386. let indexTap = data[i]
  387. if indexTap == Nexilis.IDX_CHAT {
  388. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_chat" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_chat" : "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  389. } else if indexTap == Nexilis.IDX_CONVERSATION {
  390. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_conversation" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_conversation" : "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  391. } else if indexTap == Nexilis.IDX_CALL {
  392. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_call" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_call" : "pb_button_call", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  393. } else if indexTap == Nexilis.IDX_CC {
  394. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_cc" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_cc" : "pb_button_cc", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  395. } else if indexTap == Nexilis.IDX_STREAM {
  396. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_stream" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_stream" : "pb_button_stream", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  397. } else if indexTap == Nexilis.IDX_SOCIAL_COMMERCE {
  398. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_social_commerce" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_commerce" : "pb_button_commerce", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  399. } else if indexTap == Nexilis.IDX_NEWS {
  400. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_news" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_news" : "pb_button_news", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  401. } else if indexTap == Nexilis.IDX_POST {
  402. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_post" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_post" : "pb_button_post", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  403. } else if indexTap == Nexilis.IDX_NOTIF_CENTER {
  404. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_notif_center" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_notif_center" : "pb_button_notification", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  405. } else {
  406. newButton.setImage(UIImage(named: mode == MODE_HORIZONTAL_SIDE_TAB ? "pb_button_hrz_more" : mode == MODE_HORIZONTAL_ANIMATION ? "pb_button_hrz_anim_more" : "pb_button_others", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  407. }
  408. groupView.addArrangedSubview(newButton)
  409. newButton.restorationIdentifier = "default_fb\(data[i])"
  410. newButton.accessibilityIdentifier = ""
  411. newButton.addTarget(self, action: #selector(fbTap), for: .touchUpOutside)
  412. }
  413. }
  414. @objc func draggedView(_ sender:UIPanGestureRecognizer){
  415. let size = UIScreen.main.bounds
  416. let widthScreen = size.width
  417. let heightScreen = size.height
  418. let minimumx: CGFloat = Utils.getConfigModeFB() == MODE_HORIZONTAL_ANIMATION && isShow ? 80 : Utils.getConfigModeFB() == MODE_VERTICAL_ANIMATION && isShow ? 60 : 40
  419. let maximumx = Utils.getConfigModeFB() == MODE_HORIZONTAL_ANIMATION && isShow ? widthScreen - frame.width + 20 : Utils.getConfigModeFB() == MODE_VERTICAL_ANIMATION && isShow ? widthScreen - 10 - defaultWidthHeightMenuFB : widthScreen - 40
  420. let maxMinXSideTab = isShow ? center.x : widthScreen + (center.x - widthScreen)
  421. let translation = sender.translation(in: self)
  422. var xPos = center.x + translation.x
  423. var yPos = center.y + translation.y
  424. bringSubviewToFront(self)
  425. if Utils.getConfigModeFB() == MODE_HORIZONTAL_SIDE_TAB {
  426. xPos = maxMinXSideTab
  427. } else {
  428. if (xPos < minimumx) {
  429. xPos = minimumx
  430. }
  431. if (xPos > maximumx) {
  432. xPos = maximumx
  433. }
  434. }
  435. if(isShow) {
  436. let minimumy = Utils.getConfigModeFB() == MODE_HORIZONTAL_SIDE_TAB ? 50 : (defaultWidthHeightMenuFB * countMenuFB) - defaultHeightFB - 10
  437. let maximumy = Utils.getConfigModeFB() == MODE_HORIZONTAL_SIDE_TAB ? heightScreen - 50 : heightScreen - defaultHeightFB - 10
  438. if(yPos < minimumy) {
  439. yPos = minimumy
  440. }
  441. if(yPos > maximumy) {
  442. yPos = maximumy
  443. }
  444. } else {
  445. let minimumy: CGFloat = 50
  446. let maximumy = heightScreen - 50
  447. if(yPos < minimumy) {
  448. yPos = minimumy
  449. }
  450. if(yPos > maximumy) {
  451. yPos = maximumy
  452. }
  453. }
  454. center = CGPoint(x: xPos, y: yPos)
  455. sender.setTranslation(CGPoint.zero, in: self)
  456. if lastPosY != nil {
  457. lastPosY = nil
  458. }
  459. UserDefaults.standard.set(center.x, forKey: "xlastPosFB")
  460. UserDefaults.standard.set(center.y, forKey: "ylastPosFB")
  461. }
  462. @objc func imageFBUpdate(notification: NSNotification) {
  463. }
  464. @objc func checkCounter() {
  465. let counter = queryCountCounter()
  466. if counter > 0 {
  467. DispatchQueue.main.async { [self] in
  468. if button_fb2 != nil && !indicatorCounterFB.isDescendant(of: button_fb2) {
  469. button_fb2.addSubview(indicatorCounterFB)
  470. indicatorCounterFB.layer.cornerRadius = 7.5
  471. indicatorCounterFB.layer.masksToBounds = true
  472. indicatorCounterFB.backgroundColor = .systemRed
  473. indicatorCounterFB.anchor(top: button_fb2.topAnchor, left: button_fb2.leftAnchor, height: 15, minWidth: 15, maxWidth: 20)
  474. indicatorCounterFB.addSubview(labelCounterFB)
  475. labelCounterFB.anchor(left: indicatorCounterFB.leftAnchor, right: indicatorCounterFB.rightAnchor, paddingLeft: 5, paddingRight: 5, centerX: indicatorCounterFB.centerXAnchor, centerY: indicatorCounterFB.centerYAnchor)
  476. labelCounterFB.font = .systemFont(ofSize: 10)
  477. labelCounterFB.textColor = .white
  478. }
  479. if !indicatorCounterFBBig.isDescendant(of: nexilis_button){
  480. nexilis_button.addSubview(indicatorCounterFBBig)
  481. indicatorCounterFBBig.tintColor = .systemRed
  482. indicatorCounterFBBig.image = UIImage(systemName: "staroflife.circle.fill")
  483. indicatorCounterFBBig.anchor(top: nexilis_button.topAnchor, left: nexilis_button.leftAnchor, paddingTop: 5, paddingLeft: 5, width: 15, height: 15)
  484. }
  485. labelCounterFB.text = "\(counter)"
  486. }
  487. } else {
  488. DispatchQueue.main.async { [self] in
  489. if button_fb2 != nil && indicatorCounterFB.isDescendant(of: button_fb2) {
  490. indicatorCounterFB.removeFromSuperview()
  491. }
  492. if indicatorCounterFBBig.isDescendant(of: nexilis_button) {
  493. indicatorCounterFBBig.removeFromSuperview()
  494. }
  495. }
  496. }
  497. }
  498. private func queryCountCounter() -> Int32 {
  499. var counter: Int32?
  500. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  501. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "SELECT SUM(counter) FROM MESSAGE_SUMMARY"), cursor.next() {
  502. counter = cursor.int(forColumnIndex: 0)
  503. cursor.close()
  504. }
  505. })
  506. return counter ?? 0
  507. }
  508. @objc func qmeraTap() {
  509. show(isShow: !isShow)
  510. }
  511. @objc func fbTap(_ sender: UIButton) {
  512. let package_id = sender.restorationIdentifier!
  513. var app_id = sender.accessibilityIdentifier!
  514. var indexTap = 0
  515. if package_id.contains("_fb"){
  516. let numIdx = package_id.split(separator: "_")[1]
  517. indexTap = Int(String(numIdx).substring(from: 2, to: numIdx.count))!
  518. }
  519. if indexTap == 2 {
  520. app_id = package_id.components(separatedBy: "_")[2]
  521. }
  522. Nexilis.buttonClicked(index: indexTap, id: app_id)
  523. hideButton()
  524. }
  525. @objc func fb1Tap() {
  526. APIS.openContactCenter()
  527. hideButton()
  528. }
  529. @objc func fb2Tap() {
  530. APIS.startConversation()
  531. hideButton()
  532. }
  533. @objc func fb3Tap() {
  534. APIS.openCall()
  535. hideButton()
  536. }
  537. @objc func fb4Tap() {
  538. APIS.openStreaming()
  539. hideButton()
  540. }
  541. @objc func qmeraLongPress(gestureRecognizer: UILongPressGestureRecognizer) {
  542. if gestureRecognizer.state == .began {
  543. if mySettingDelegate != nil {
  544. mySettingDelegate?.settingDelegate()
  545. } else {
  546. let navigationController = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "settingNav") as! UINavigationController
  547. navigationController.modalPresentationStyle = .fullScreen
  548. navigationController.navigationBar.tintColor = .white
  549. navigationController.navigationBar.barTintColor = .mainColor
  550. navigationController.navigationBar.isTranslucent = false
  551. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  552. navigationController.navigationBar.barStyle = .black
  553. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
  554. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  555. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  556. navigationController.navigationBar.titleTextAttributes = textAttributes
  557. navigationController.view.backgroundColor = .mainColor
  558. UIApplication.shared.rootViewController?.present(navigationController, animated: true, completion: nil)
  559. }
  560. hideButton()
  561. }
  562. }
  563. @objc public func hideButton() {
  564. animationTimer.invalidate()
  565. if isShow {
  566. show(isShow: false)
  567. }
  568. if self.frame.origin.x < UIScreen.main.bounds.width / 2 - 30 {
  569. self.frame.origin.x = 0
  570. } else {
  571. self.frame.origin.x = UIScreen.main.bounds.width - defaultWidthFB
  572. }
  573. }
  574. public func show(isShow: Bool) {
  575. self.isShow = isShow
  576. if isShow {
  577. animationTimer.invalidate()
  578. pullButton()
  579. if indicatorCounterFBBig.isDescendant(of: nexilis_button) {
  580. indicatorCounterFBBig.isHidden = true
  581. }
  582. var height = CGFloat((defaultWidthHeightMenuFB * countMenuFB) + defaultHeightFB + 5) //defaultWidthHeightMenuFB
  583. var width = frame.width
  584. var xPosition = frame.origin.x
  585. if Utils.getConfigModeFB() == MODE_VERTICAL_ANIMATION {
  586. height = CGFloat((defaultWidthHeightMenuFB * (countMenuFB - 2)) + defaultHeightFB - 5)
  587. width = frame.width + defaultWidthHeightMenuFB
  588. if xPosition > UIScreen.main.bounds.width - defaultWidthFB - defaultWidthHeightMenuFB {
  589. xPosition = UIScreen.main.bounds.width - defaultWidthFB - defaultWidthHeightMenuFB
  590. }
  591. scrollView.isHidden = false
  592. } else if Utils.getConfigModeFB() == MODE_HORIZONTAL_ANIMATION {
  593. height = defaultHeightFB + defaultWidthHeightMenuFB
  594. width = defaultWidthHeightMenuFB * (countMenuFB - 1)
  595. if xPosition > UIScreen.main.bounds.width - defaultWidthHeightMenuFB * (countMenuFB) {
  596. xPosition = UIScreen.main.bounds.width - defaultWidthHeightMenuFB * (countMenuFB)
  597. }
  598. }
  599. var yPosition = frame.origin.y - height + defaultHeightFB
  600. if yPosition <= 25 {
  601. lastPosY = frame.origin.y
  602. yPosition = 25
  603. }
  604. if Utils.getConfigModeFB() != MODE_HORIZONTAL_SIDE_TAB {
  605. frame = CGRect(x: xPosition, y: yPosition, width: width, height: height)
  606. } else {
  607. UIView.animate(withDuration: 0.5, animations: {
  608. self.frame.origin.x = 0
  609. })
  610. }
  611. DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: { [self] in
  612. if isShow {
  613. let countSubviewsAfter = groupView.subviews.count
  614. if countSubviewsAfter > 5 {
  615. scrollView.flashScrollIndicators()
  616. }
  617. }
  618. })
  619. } else {
  620. if indicatorCounterFBBig.isDescendant(of: nexilis_button) {
  621. indicatorCounterFBBig.isHidden = false
  622. }
  623. var height = CGFloat((defaultWidthHeightMenuFB * countMenuFB) + defaultHeightFB + 5) //defaultWidthHeightMenuFB
  624. var width = defaultWidthFB
  625. if Utils.getConfigModeFB() == MODE_VERTICAL_ANIMATION {
  626. height = CGFloat((defaultWidthHeightMenuFB * 3) + defaultHeightFB - 5)
  627. scrollView.isHidden = true
  628. } else if Utils.getConfigModeFB() == MODE_HORIZONTAL_ANIMATION {
  629. height = defaultHeightFB + defaultWidthHeightMenuFB
  630. width = defaultWidthFB
  631. }
  632. var yPosition = frame.origin.y + height - defaultHeightFB
  633. if lastPosY != nil {
  634. yPosition = lastPosY!
  635. }
  636. if Utils.getConfigModeFB() != MODE_HORIZONTAL_SIDE_TAB {
  637. frame = CGRect(x: frame.origin.x, y: yPosition, width: width, height: defaultHeightFB)
  638. } else {
  639. UIView.animate(withDuration: 0.5, animations: { [self] in
  640. frame.origin.x = UIScreen.main.bounds.width - defaultWidthFB
  641. })
  642. }
  643. if Utils.getConfigModeFB() == MODE_VERTICAL_ANIMATION || Utils.getConfigModeFB() == MODE_HORIZONTAL_ANIMATION {
  644. checkDelayAnimation()
  645. }
  646. }
  647. }
  648. }
  649. public protocol SettingMABDelegate: AnyObject {
  650. func settingDelegate()
  651. }