MOGiftBottomMenuView.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. //
  2. // MOGiftBottomMenuView.swift
  3. // MiMoLive
  4. //
  5. // Created by OneeChan on 2025/9/5.
  6. //
  7. import Foundation
  8. import UIKit
  9. import SnapKit
  10. @objc protocol MOGiftBottomMenuViewDelegate {
  11. // Recharge
  12. func giftBottomMenuViewClickRecharge(view: MOGiftBottomMenuView)
  13. // Gift
  14. func giftBottomMenuViewDidSelectNum(view: MOGiftBottomMenuView, num: Int, isCustom: Bool)
  15. func giftBottomMenuViewClickSendGift(view: MOGiftBottomMenuView)
  16. func giftBottomMenuViewClickCustom(view: MOGiftBottomMenuView)
  17. // Bag
  18. func giftBottomMenuViewClickSendBag(view: MOGiftBottomMenuView)
  19. // Props
  20. func giftBottomMenuViewClickUse(view: MOGiftBottomMenuView)
  21. }
  22. @objcMembers
  23. class MOGiftBottomMenuView: UIView {
  24. weak var delegate: MOGiftBottomMenuViewDelegate?
  25. @objc enum GiftBottomMenuType: Int {
  26. case none
  27. case gift
  28. case bag
  29. case props
  30. }
  31. private var curType: GiftBottomMenuType = .gift
  32. private var giftView: UIView?
  33. private var diamondLabel: UILabel?
  34. private var sendGiftView: MOSendGiftView?
  35. private var bagView: UIView?
  36. private var propView: UIView?
  37. private var usePropButon: MOGiftGradientButton?
  38. override init(frame: CGRect) {
  39. super.init(frame: frame)
  40. setupViews()
  41. updateViewType(curType)
  42. }
  43. required init?(coder: NSCoder) {
  44. fatalError("init(coder:) has not been implemented")
  45. }
  46. func updateSelectItem(_ item: Any?) {
  47. guard let item else {
  48. updateViewType(.none)
  49. return
  50. }
  51. if let item = item as? MOGiftlist {
  52. if item.isBag {
  53. updateViewType(.bag)
  54. } else {
  55. enableGiftSendView(true)
  56. updateViewType(.gift)
  57. }
  58. } else if let item = item as? MOShopList {
  59. updateViewType(.props)
  60. if item.used {
  61. usePropButon?.title = NSLocalizedString("mimo_2_gift_list_prpps_a_use", comment: "")
  62. } else {
  63. usePropButon?.title = NSLocalizedString("mimo_2_gift_list_prpps_use", comment: "")
  64. }
  65. } else {
  66. updateViewType(.none)
  67. }
  68. }
  69. func updateViewType(_ type: GiftBottomMenuType) {
  70. curType = type
  71. let showView: UIView? = switch type {
  72. case .none:
  73. nil
  74. case .gift:
  75. self.giftView
  76. case .bag:
  77. self.bagView
  78. case .props:
  79. self.propView
  80. }
  81. let showings = [self.giftView, self.bagView, self.propView]
  82. .filter { $0?.isHidden == false && $0 != showView }
  83. showings.forEach { $0?.isHidden = true }
  84. // 已经在展示,不需要调整
  85. if showView?.isHidden == false { return }
  86. showView?.isHidden = false
  87. }
  88. func updateUserDiamond(_ count: Double) {
  89. var zuanNumStr = ""
  90. if count < 10_000_000 { // 1千万以下
  91. zuanNumStr = String(format: "%.f", count)
  92. } else if count < 1_000_000_000 { // 1千万到10亿
  93. let firstTwoDigits = Int(count / 10_000)
  94. zuanNumStr = String(
  95. format: "%ld.%02ldM",
  96. firstTwoDigits / 100,
  97. firstTwoDigits % 100
  98. )
  99. } else { // 10亿以上
  100. let firstTwoDigits = Int(count / 10_000_000)
  101. zuanNumStr = String(
  102. format: "%ld.%02ldB",
  103. firstTwoDigits / 100,
  104. firstTwoDigits % 100
  105. )
  106. }
  107. diamondLabel?.text = "\(zuanNumStr)"
  108. }
  109. func selectGiftNum(_ num: Int) {
  110. sendGiftView?.updateGiftNum(num)
  111. }
  112. func curGiftNum() -> Int {
  113. sendGiftView?.curGiftNum() ?? 1
  114. }
  115. func enableGiftSendView(_ enable: Bool) {
  116. sendGiftView?.isHidden = !enable
  117. }
  118. func enableGiftNum(_ enable: Bool) {
  119. sendGiftView?.enableGiftNum(enable)
  120. }
  121. func updateCustomNum(_ num: Int) {
  122. sendGiftView?.updateCustomNum(num)
  123. }
  124. }
  125. // MARK: Private
  126. extension MOGiftBottomMenuView {
  127. }
  128. // MARK: UI 事件
  129. extension MOGiftBottomMenuView {
  130. @objc func handleRechargeButtonClick() {
  131. delegate?.giftBottomMenuViewClickRecharge(view: self)
  132. }
  133. @objc func handleSendBagButtonClick() {
  134. delegate?.giftBottomMenuViewClickSendBag(view: self)
  135. }
  136. @objc func handleUsePropsButtonClick() {
  137. delegate?.giftBottomMenuViewClickUse(view: self)
  138. }
  139. }
  140. // MARK: MOSendGiftDelegate
  141. extension MOGiftBottomMenuView: MOSendGiftViewDelegate {
  142. func sendGiftViewDidSelectNum(
  143. view: MOSendGiftView,
  144. num: Int,
  145. isCustom: Bool
  146. ) {
  147. delegate?
  148. .giftBottomMenuViewDidSelectNum(
  149. view: self,
  150. num: num,
  151. isCustom: isCustom
  152. )
  153. }
  154. func sendGiftViewClickSend(view: MOSendGiftView) {
  155. delegate?.giftBottomMenuViewClickSendGift(view: self)
  156. }
  157. func sendGiftViewClickCustom(view: MOSendGiftView) {
  158. delegate?.giftBottomMenuViewClickCustom(view: self)
  159. }
  160. }
  161. // MARK: UI 视图构建
  162. extension MOGiftBottomMenuView {
  163. // UI 组装
  164. private func setupViews() {
  165. let giftView = buildGiftMenuView()
  166. giftView.isHidden = true
  167. addSubview(giftView)
  168. giftView.snp.makeConstraints { make in
  169. make.leading.trailing.bottom.equalToSuperview()
  170. make.top.bottom.equalToSuperview()
  171. }
  172. self.giftView = giftView
  173. let bagView = buildBagMenuView()
  174. bagView.isHidden = true
  175. addSubview(bagView)
  176. bagView.snp.makeConstraints { make in
  177. make.edges.equalToSuperview()
  178. }
  179. self.bagView = bagView
  180. let propsView = buildPropsMenuView()
  181. propsView.isHidden = true
  182. addSubview(propsView)
  183. propsView.snp.makeConstraints { make in
  184. make.edges.equalToSuperview()
  185. }
  186. self.propView = propsView
  187. }
  188. // Gift Menu
  189. private func buildGiftMenuView() -> UIView {
  190. let container = UIView()
  191. let diamondView = buildDiamondView()
  192. container.addSubview(diamondView)
  193. diamondView.snp.makeConstraints { make in
  194. make.top.bottom.equalToSuperview()
  195. make.leading.equalToSuperview().offset(12)
  196. }
  197. let sendView = MOSendGiftView()
  198. sendView.delegate = self
  199. container.addSubview(sendView)
  200. sendView.snp.makeConstraints { make in
  201. make.top.bottom.equalToSuperview()
  202. make.trailing.equalToSuperview().offset(-12)
  203. make.leading.equalTo(diamondView.snp.trailing).offset(8)
  204. }
  205. self.sendGiftView = sendView
  206. return container
  207. }
  208. // 钻石界面
  209. private func buildDiamondView() -> UIView {
  210. let container = UIView()
  211. container.layer.cornerRadius = 10
  212. container.backgroundColor = .white.withAlphaComponent(0.15)
  213. let diamond = UIImageView()
  214. diamond.image = UIImage(named: "icon_gift_zuan")
  215. container.addSubview(diamond)
  216. diamond.snp.makeConstraints { make in
  217. make.top.equalToSuperview().offset(7)
  218. make.bottom.equalToSuperview().offset(-7)
  219. make.leading.equalToSuperview().offset(10)
  220. make.width.height.equalTo(14)
  221. }
  222. let label = UILabel()
  223. label.textColor = .white
  224. label.font = MOTextTools.mediumFont(12.0)
  225. container.addSubview(label)
  226. label.snp.makeConstraints { make in
  227. make.centerY.equalToSuperview()
  228. make.leading.equalTo(diamond.snp.trailing).offset(3)
  229. }
  230. self.diamondLabel = label
  231. let arrow = UIImageView()
  232. arrow.image = UIImage(named: "icon_arrow_right_gray")
  233. container.addSubview(arrow)
  234. arrow.snp.makeConstraints { make in
  235. make.centerY.equalToSuperview()
  236. make.leading.equalTo(label.snp.trailing).offset(5)
  237. make.trailing.equalToSuperview().offset(-10)
  238. }
  239. let button = UIButton()
  240. button
  241. .addTarget(
  242. self,
  243. action: #selector(handleRechargeButtonClick),
  244. for: .touchUpInside
  245. )
  246. container.addSubview(button)
  247. button.snp.makeConstraints { make in
  248. make.edges.equalToSuperview()
  249. }
  250. return container
  251. }
  252. // Bag View
  253. private func buildBagMenuView() -> UIView {
  254. let container = UIView()
  255. let send = MOGiftGradientButton()
  256. send
  257. .addTarget(
  258. self,
  259. action: #selector(handleSendBagButtonClick),
  260. for: .touchUpInside
  261. )
  262. send.title = "Send"
  263. container.addSubview(send)
  264. send.snp.makeConstraints { make in
  265. make.top.bottom.equalToSuperview()
  266. make.trailing.equalToSuperview().offset(-12)
  267. }
  268. return container
  269. }
  270. // Props View
  271. private func buildPropsMenuView() -> UIView {
  272. let container = UIView()
  273. let use = MOGiftGradientButton()
  274. use.addTarget(
  275. self,
  276. action: #selector(handleUsePropsButtonClick),
  277. for: .touchUpInside
  278. )
  279. use.title = "Use"
  280. container.addSubview(use)
  281. use.snp.makeConstraints { make in
  282. make.top.bottom.equalToSuperview()
  283. make.trailing.equalToSuperview().offset(-12)
  284. }
  285. self.usePropButon = use
  286. return container
  287. }
  288. }
  289. private class MOGiftGradientButton: UIButton {
  290. var title = "" {
  291. didSet {
  292. textLabel.text = title
  293. }
  294. }
  295. private let gradientLayer = CAGradientLayer()
  296. private let textLabel = UILabel()
  297. override init(frame: CGRect) {
  298. super.init(frame: frame)
  299. setupViews()
  300. }
  301. required init?(coder: NSCoder) {
  302. fatalError("init(coder:) has not been implemented")
  303. }
  304. override func layoutSubviews() {
  305. super.layoutSubviews()
  306. CATransaction.begin()
  307. CATransaction.setDisableActions(true)
  308. layer.sublayers?.forEach({ layer in
  309. if layer is CAGradientLayer {
  310. layer.frame = bounds
  311. }
  312. })
  313. CATransaction.commit()
  314. }
  315. private func setupViews() {
  316. let graLayer = CAGradientLayer()
  317. graLayer.startPoint = CGPoint(x: 0, y: 0.5)
  318. graLayer.endPoint = CGPoint(x: 1, y: 0.5)
  319. graLayer.colors = [
  320. UIColor(
  321. red: 255/255.0,
  322. green: 77/255.0,
  323. blue: 166/255.0,
  324. alpha: 1
  325. ).cgColor,
  326. UIColor(
  327. red: 67/255.0,
  328. green: 99/255.0,
  329. blue: 255/255.0,
  330. alpha: 1
  331. ).cgColor
  332. ];
  333. graLayer.locations = [0, 1.0]
  334. layer.insertSublayer(graLayer, at: 0)
  335. layer.cornerRadius = 10
  336. layer.masksToBounds = true
  337. textLabel.text = "Use"
  338. textLabel.font = MOTextTools.mediumFont(12.0)
  339. textLabel.textColor = .white
  340. addSubview(textLabel)
  341. textLabel.snp.makeConstraints { make in
  342. make.edges
  343. .equalToSuperview()
  344. .inset(UIEdgeInsets(top: 6, left: 16, bottom: 6, right: 16))
  345. }
  346. }
  347. }
  348. //#if DEBUG
  349. //import SwiftUI
  350. //
  351. //struct MOGiftBottomMenuViewPreview: UIViewRepresentable {
  352. // func makeUIView(context: Context) -> some UIView {
  353. // let container = UIView()
  354. // container.backgroundColor = .black
  355. //
  356. // let view = MOGiftBottomMenuView()
  357. // container.addSubview(view)
  358. // view.snp.makeConstraints { make in
  359. // make.centerY.equalToSuperview()
  360. // make.leading.trailing.equalToSuperview()
  361. // }
  362. //
  363. // return container
  364. // }
  365. //
  366. // func updateUIView(_ uiView: UIViewType, context: Context) {
  367. //
  368. // }
  369. //}
  370. //
  371. //#Preview(body: {
  372. // VStack {
  373. // MOGiftBottomMenuViewPreview()
  374. // }
  375. //})
  376. //
  377. //#endif