FloatingButton.swift 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  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 panGesture: UIPanGestureRecognizer?
  31. public weak var mySettingDelegate: SettingMABDelegate?
  32. public var isShow: Bool = false
  33. override init(frame: CGRect) {
  34. super.init(frame: frame)
  35. commonInit()
  36. }
  37. required init?(coder: NSCoder) {
  38. super.init(coder: coder)
  39. commonInit()
  40. }
  41. private func commonInit() {
  42. backgroundColor = .clear
  43. frame = CGRect(x: UIScreen.main.bounds.width - 50, y: (UIScreen.main.bounds.height / 2) - 50, width: 50.0, height: 50.0)
  44. panGesture = UIPanGestureRecognizer(target: self, action: #selector(draggedView(_:)))
  45. addGestureRecognizer(panGesture!)
  46. nexilis_button = UIImageView()
  47. nexilis_button.translatesAutoresizingMaskIntoConstraints = false
  48. nexilis_button.isUserInteractionEnabled = true
  49. if Utils.getIconDock() != nil {
  50. let dataImage = try? Data(contentsOf: URL(string: Utils.getUrlDock()!)!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
  51. if dataImage != nil {
  52. nexilis_button.image = UIImage(data: dataImage!)
  53. }
  54. } else {
  55. nexilis_button.image = UIImage(named: "pb_button", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
  56. }
  57. let qmeraTap = UITapGestureRecognizer(target: self, action: #selector(qmeraTap))
  58. qmeraTap.numberOfTouchesRequired = 1
  59. nexilis_button.addGestureRecognizer(qmeraTap)
  60. let qmeraLongPress = UILongPressGestureRecognizer(target: self, action: #selector(qmeraLongPress(gestureRecognizer:)))
  61. nexilis_button.addGestureRecognizer(qmeraLongPress)
  62. addSubview(nexilis_button)
  63. nexilis_button.widthAnchor.constraint(equalToConstant: 50.0).isActive = true
  64. nexilis_button.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
  65. nexilis_button.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
  66. nexilis_button.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
  67. scrollView = UIScrollView()
  68. scrollView.translatesAutoresizingMaskIntoConstraints = false
  69. scrollView.layer.borderWidth = 1.0
  70. scrollView.layer.borderColor = UIColor.white.cgColor
  71. scrollView.layer.cornerRadius = 8.0
  72. scrollView.layer.masksToBounds = true
  73. scrollView.backgroundColor = .black.withAlphaComponent(0.25)
  74. addSubview(scrollView)
  75. scrollView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true
  76. scrollView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
  77. scrollView.topAnchor.constraint(equalTo: topAnchor).isActive = true
  78. scrollView.bottomAnchor.constraint(equalTo: nexilis_button.topAnchor).isActive = true
  79. groupView = UIStackView()
  80. groupView.translatesAutoresizingMaskIntoConstraints = false
  81. groupView.axis = .vertical
  82. groupView.distribution = .fillEqually
  83. scrollView.addSubview(groupView)
  84. groupView.widthAnchor.constraint(equalToConstant: 40).isActive = true
  85. groupView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 5).isActive = true
  86. groupView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -5).isActive = true
  87. groupView.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 6).isActive = true
  88. pullButton()
  89. let center: NotificationCenter = NotificationCenter.default
  90. center.addObserver(self, selector: #selector(imageFBUpdate(notification:)), name: NSNotification.Name(rawValue: "imageFBUpdate"), object: nil)
  91. center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
  92. center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil)
  93. let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hideButton))
  94. tapGesture.cancelsTouchesInView = false
  95. UIApplication.shared.windows.first?.rootViewController?.view.addGestureRecognizer(tapGesture)
  96. }
  97. private func pullButton() {
  98. if datePull == nil || Int(Date().timeIntervalSince(datePull!)) >= 60 {
  99. datePull = Date()
  100. } else if Int(Date().timeIntervalSince(datePull!)) < 60 {
  101. return
  102. }
  103. if !CheckConnection.isConnectedToNetwork() || API.nGetCLXConnState() == 0 {
  104. let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
  105. imageView.tintColor = .white
  106. 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)
  107. banner.show()
  108. return
  109. }
  110. DispatchQueue.global().async { [self] in
  111. if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.pullFloatingButton(), timeout: 30 * 1000){
  112. if response.isOk() {
  113. let data = response.getBody(key: CoreMessage_TMessageKey.DATA, default_value: "")
  114. if !data.isEmpty {
  115. if let jsonArray = try! JSONSerialization.jsonObject(with: data.data(using: String.Encoding.utf8)!, options: JSONSerialization.ReadingOptions()) as? [AnyObject] {
  116. DispatchQueue.main.async { [self] in
  117. groupView.subviews.forEach({ $0.removeFromSuperview() })
  118. if jsonArray.count == 0 {
  119. getDefaultButton()
  120. } else {
  121. for json in jsonArray {
  122. let package_id = json["package_id"] as! String
  123. let app_id = (json["app_id"] as? String) ?? ""
  124. let icon = (json["icon"] as? String) ?? ""
  125. let newButton = UIButton()
  126. newButton.heightAnchor.constraint(equalToConstant: 40).isActive = true
  127. newButton.translatesAutoresizingMaskIntoConstraints = false
  128. DispatchQueue.global().async {
  129. 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
  130. DispatchQueue.main.async {
  131. if data != nil {
  132. newButton.setImage(UIImage(data: data!), for: .normal)
  133. }
  134. }
  135. }
  136. groupView.addArrangedSubview(newButton)
  137. newButton.restorationIdentifier = package_id
  138. newButton.accessibilityIdentifier = app_id
  139. newButton.addTarget(self, action: #selector(fbTap), for: .touchUpOutside)
  140. }
  141. }
  142. let countSubviewsAfter = groupView.subviews.count
  143. if countSubviewsAfter <= 4 {
  144. scrollView.isScrollEnabled = false
  145. }
  146. }
  147. }
  148. } else {
  149. groupView.subviews.forEach({ $0.removeFromSuperview() })
  150. getDefaultButton()
  151. }
  152. } else {
  153. groupView.subviews.forEach({ $0.removeFromSuperview() })
  154. getDefaultButton()
  155. }
  156. }
  157. }
  158. }
  159. func getDefaultButton() {
  160. button_fb1 = UIButton()
  161. button_fb1.heightAnchor.constraint(equalToConstant: 40).isActive = true
  162. button_fb1.translatesAutoresizingMaskIntoConstraints = false
  163. button_fb1.setImage(UIImage(named: "pb_button_cc", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  164. groupView.addArrangedSubview(button_fb1)
  165. button_fb1.addTarget(self, action: #selector(fb1Tap), for: .touchUpOutside)
  166. button_fb2 = UIButton()
  167. button_fb2.heightAnchor.constraint(equalToConstant: 40).isActive = true
  168. button_fb2.translatesAutoresizingMaskIntoConstraints = false
  169. button_fb2.setImage(UIImage(named: "pb_button_chat", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  170. groupView.addArrangedSubview(button_fb2)
  171. button_fb2.addTarget(self, action: #selector(fb2Tap), for: .touchUpOutside)
  172. checkCounter()
  173. button_fb3 = UIButton()
  174. button_fb3.heightAnchor.constraint(equalToConstant: 40).isActive = true
  175. button_fb3.translatesAutoresizingMaskIntoConstraints = false
  176. button_fb3.setImage(UIImage(named: "pb_button_call", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  177. groupView.addArrangedSubview(button_fb3)
  178. button_fb3.addTarget(self, action: #selector(fb3Tap), for: .touchUpOutside)
  179. button_fb4 = UIButton()
  180. button_fb4.heightAnchor.constraint(equalToConstant: 40).isActive = true
  181. button_fb4.translatesAutoresizingMaskIntoConstraints = false
  182. button_fb4.setImage(UIImage(named: "pb_button_stream", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
  183. groupView.addArrangedSubview(button_fb4)
  184. button_fb4.addTarget(self, action: #selector(fb4Tap), for: .touchUpOutside)
  185. }
  186. @objc func draggedView(_ sender:UIPanGestureRecognizer){
  187. let size = UIScreen.main.bounds
  188. let widthScreen = size.width
  189. let heightScreen = size.height
  190. let minimumx = (widthScreen + 30) - widthScreen
  191. let maximumx = widthScreen - 30
  192. let translation = sender.translation(in: self)
  193. var xPos = center.x + translation.x
  194. var yPos = center.y + translation.y
  195. bringSubviewToFront(self)
  196. if (xPos < minimumx) {
  197. xPos = minimumx
  198. }
  199. if (xPos > maximumx) {
  200. xPos = maximumx
  201. }
  202. if(isShow) {
  203. let minimumy = CGFloat(120.5) //30
  204. let maximumy = heightScreen - 100
  205. if(yPos < minimumy) {
  206. yPos = minimumy
  207. }
  208. if(yPos > maximumy) {
  209. yPos = maximumy
  210. }
  211. } else {
  212. let minimumy = (heightScreen + 50) - heightScreen
  213. let maximumy = heightScreen - 20
  214. if(yPos < minimumy) {
  215. yPos = minimumy
  216. }
  217. if(yPos > maximumy) {
  218. yPos = maximumy
  219. }
  220. }
  221. center = CGPoint(x: xPos, y: yPos)
  222. sender.setTranslation(CGPoint.zero, in: self)
  223. if lastPosY != nil {
  224. lastPosY = nil
  225. }
  226. UserDefaults.standard.set(center.x, forKey: "xlastPosFB")
  227. UserDefaults.standard.set(center.y, forKey: "ylastPosFB")
  228. }
  229. @objc func imageFBUpdate(notification: NSNotification) {
  230. }
  231. @objc func checkCounter() {
  232. let counter = queryCountCounter()
  233. if counter > 0 {
  234. DispatchQueue.main.async { [self] in
  235. if !indicatorCounterFB.isDescendant(of: button_fb2) {
  236. button_fb2.addSubview(indicatorCounterFB)
  237. indicatorCounterFB.layer.cornerRadius = 7.5
  238. indicatorCounterFB.layer.masksToBounds = true
  239. indicatorCounterFB.backgroundColor = .systemRed
  240. indicatorCounterFB.anchor(top: button_fb2.topAnchor, left: button_fb2.leftAnchor, height: 15, minWidth: 15, maxWidth: 20)
  241. indicatorCounterFB.addSubview(labelCounterFB)
  242. labelCounterFB.anchor(left: indicatorCounterFB.leftAnchor, right: indicatorCounterFB.rightAnchor, paddingLeft: 5, paddingRight: 5, centerX: indicatorCounterFB.centerXAnchor, centerY: indicatorCounterFB.centerYAnchor)
  243. labelCounterFB.font = .systemFont(ofSize: 10)
  244. labelCounterFB.textColor = .white
  245. }
  246. if !indicatorCounterFBBig.isDescendant(of: nexilis_button){
  247. nexilis_button.addSubview(indicatorCounterFBBig)
  248. indicatorCounterFBBig.tintColor = .systemRed
  249. indicatorCounterFBBig.image = UIImage(systemName: "staroflife.circle.fill")
  250. indicatorCounterFBBig.anchor(top: nexilis_button.topAnchor, left: nexilis_button.leftAnchor, paddingTop: 5, paddingLeft: 5, width: 15, height: 15)
  251. }
  252. labelCounterFB.text = "\(counter)"
  253. }
  254. } else {
  255. DispatchQueue.main.async { [self] in
  256. if indicatorCounterFB.isDescendant(of: button_fb2) {
  257. indicatorCounterFB.removeFromSuperview()
  258. }
  259. if indicatorCounterFBBig.isDescendant(of: nexilis_button) {
  260. indicatorCounterFBBig.removeFromSuperview()
  261. }
  262. }
  263. }
  264. }
  265. private func queryCountCounter() -> Int32 {
  266. var counter: Int32?
  267. Database.shared.database?.inTransaction({ (fmdb, rollback) in
  268. if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "SELECT SUM(counter) FROM MESSAGE_SUMMARY"), cursor.next() {
  269. counter = cursor.int(forColumnIndex: 0)
  270. cursor.close()
  271. }
  272. })
  273. return counter ?? 0
  274. }
  275. @objc func qmeraTap() {
  276. show(isShow: !isShow)
  277. }
  278. @objc func fbTap(_ sender: UIButton) {
  279. let package_id = sender.restorationIdentifier!
  280. var app_id = sender.accessibilityIdentifier!
  281. var indexTap = 0
  282. if package_id.contains("_fb"){
  283. indexTap = Int(String(package_id.split(separator: "_")[1]).substring(from: 2, to: 2))!
  284. }
  285. if indexTap == 2 {
  286. app_id = package_id.components(separatedBy: "_")[2]
  287. }
  288. Nexilis.buttonClicked(index: indexTap, id: app_id)
  289. hideButton()
  290. }
  291. @objc func fb1Tap() {
  292. Nexilis.openContactCenter()
  293. hideButton()
  294. }
  295. @objc func fb2Tap() {
  296. Nexilis.openChat()
  297. hideButton()
  298. }
  299. @objc func fb3Tap() {
  300. Nexilis.openCall()
  301. hideButton()
  302. }
  303. @objc func fb4Tap() {
  304. Nexilis.openStreaming()
  305. hideButton()
  306. }
  307. @objc func qmeraLongPress(gestureRecognizer: UILongPressGestureRecognizer) {
  308. if gestureRecognizer.state == .began {
  309. if mySettingDelegate != nil {
  310. mySettingDelegate?.settingDelegate()
  311. } else {
  312. let navigationController = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "settingNav") as! UINavigationController
  313. navigationController.modalPresentationStyle = .fullScreen
  314. navigationController.navigationBar.tintColor = .white
  315. navigationController.navigationBar.barTintColor = .mainColor
  316. navigationController.navigationBar.isTranslucent = false
  317. navigationController.navigationBar.overrideUserInterfaceStyle = .dark
  318. navigationController.navigationBar.barStyle = .black
  319. let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: UIColor.white]
  320. UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
  321. let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
  322. navigationController.navigationBar.titleTextAttributes = textAttributes
  323. navigationController.view.backgroundColor = .mainColor
  324. UIApplication.shared.rootViewController?.present(navigationController, animated: true, completion: nil)
  325. }
  326. hideButton()
  327. }
  328. }
  329. @objc public func hideButton() {
  330. if isShow {
  331. show(isShow: false)
  332. }
  333. if self.frame.origin.x < UIScreen.main.bounds.width / 2 - 30 {
  334. self.frame.origin.x = 0
  335. } else {
  336. self.frame.origin.x = UIScreen.main.bounds.width - 50
  337. }
  338. }
  339. public func show(isShow: Bool) {
  340. self.isShow = isShow
  341. if isShow {
  342. pullButton()
  343. if indicatorCounterFBBig.isDescendant(of: nexilis_button) {
  344. indicatorCounterFBBig.isHidden = true
  345. }
  346. let height = CGFloat(217) //40
  347. var yPosition = frame.origin.y - height + 50
  348. if yPosition <= 25 {
  349. lastPosY = frame.origin.y
  350. yPosition = 25
  351. }
  352. frame = CGRect(x: frame.origin.x, y: yPosition, width: frame.width, height: height)
  353. DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: { [self] in
  354. if isShow {
  355. let countSubviewsAfter = groupView.subviews.count
  356. if countSubviewsAfter > 5 {
  357. scrollView.flashScrollIndicators()
  358. }
  359. }
  360. })
  361. } else {
  362. if indicatorCounterFBBig.isDescendant(of: nexilis_button) {
  363. indicatorCounterFBBig.isHidden = false
  364. }
  365. let height = CGFloat(217) //40
  366. var yPosition = frame.origin.y + height - 50
  367. if lastPosY != nil {
  368. yPosition = lastPosY!
  369. }
  370. frame = CGRect(x: frame.origin.x, y: yPosition, width: frame.width, height: frame.width)
  371. }
  372. }
  373. }
  374. public protocol SettingMABDelegate: AnyObject {
  375. func settingDelegate()
  376. }