LNSkillBottomMenuView.swift 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. //
  2. // LNSkillBottomMenuView.swift
  3. // Lanu
  4. //
  5. // Created by OneeChan on 2025/12/15.
  6. //
  7. import Foundation
  8. import UIKit
  9. import SnapKit
  10. import Combine
  11. class LNSkillBottomMenuView: UIView {
  12. private let priceLabel = UILabel()
  13. private let unitLabel = UILabel()
  14. private let discountView = UIView()
  15. private let newbieDiscountView = LNNewbieDiscountView()
  16. private var curDetail: LNGameMateSkillDetailVO?
  17. override init(frame: CGRect) {
  18. super.init(frame: frame)
  19. setupViews()
  20. LNEventDeliver.addObserver(self)
  21. }
  22. required init?(coder: NSCoder) {
  23. fatalError("init(coder:) has not been implemented")
  24. }
  25. func update(_ detail: LNGameMateSkillDetailVO) {
  26. isHidden = false
  27. priceLabel.text = detail.price.toDisplay
  28. unitLabel.text = "/\(detail.unit)"
  29. if curDetail == nil {
  30. if detail.userNo.isMyUid {
  31. let editView = buildEditView()
  32. addSubview(editView)
  33. editView.snp.makeConstraints { make in
  34. make.leading.equalToSuperview().inset(16)
  35. make.bottom.equalToSuperview().offset(commonBottomInset)
  36. make.top.equalToSuperview().offset(16)
  37. }
  38. let settingView = buildSettingsView()
  39. addSubview(settingView)
  40. settingView.snp.makeConstraints { make in
  41. make.leading.equalTo(editView.snp.trailing).offset(10)
  42. make.centerY.equalTo(editView)
  43. make.trailing.equalToSuperview().offset(-16)
  44. }
  45. } else {
  46. let orderView = buildOrderView()
  47. addSubview(orderView)
  48. orderView.snp.makeConstraints { make in
  49. make.leading.equalToSuperview().inset(16)
  50. make.bottom.equalToSuperview().offset(commonBottomInset)
  51. make.top.equalToSuperview().offset(16)
  52. }
  53. let discountView = buildDiscountView()
  54. addSubview(discountView)
  55. discountView.snp.makeConstraints { make in
  56. make.leading.equalTo(orderView)
  57. make.bottom.equalTo(orderView.snp.top).offset(10)
  58. }
  59. let chatView = buildChatView()
  60. addSubview(chatView)
  61. chatView.snp.makeConstraints { make in
  62. make.leading.equalTo(orderView.snp.trailing).offset(10)
  63. make.centerY.equalTo(orderView)
  64. make.trailing.equalToSuperview().offset(-16)
  65. }
  66. }
  67. }
  68. curDetail = detail
  69. updateDiscount()
  70. }
  71. }
  72. extension LNSkillBottomMenuView: LNOrderManagerNotify {
  73. func onMyDiscountInfoChanged(info: LNOrderDiscountVO?) {
  74. updateDiscount()
  75. }
  76. private func updateDiscount() {
  77. guard let curDetail else { return }
  78. if let discount = LNOrderManager.shared.discountFor(curDetail.price) {
  79. discountView.isHidden = false
  80. newbieDiscountView.update(1 - discount)
  81. priceLabel.text = (curDetail.price * discount).toDisplay
  82. } else {
  83. discountView.isHidden = true
  84. priceLabel.text = curDetail.price.toDisplay
  85. }
  86. }
  87. }
  88. extension LNSkillBottomMenuView {
  89. private func setupViews() {
  90. isHidden = true
  91. let bottomGradient = CAGradientLayer()
  92. bottomGradient.colors = [
  93. UIColor.white.withAlphaComponent(0).cgColor,
  94. UIColor.white.cgColor,
  95. UIColor.white.cgColor
  96. ]
  97. bottomGradient.locations = [0, 0.5, 1]
  98. bottomGradient.startPoint = .init(x: 0, y: 0)
  99. bottomGradient.endPoint = .init(x: 0, y: 1)
  100. layer.addSublayer(bottomGradient)
  101. publisher(for: \.bounds).removeDuplicates().sink { [weak bottomGradient] newValue in
  102. guard let bottomGradient else { return }
  103. bottomGradient.frame = newValue
  104. }.store(in: &cancellables)
  105. }
  106. private func buildOrderView() -> UIView {
  107. let container = UIView()
  108. container.backgroundColor = .init(hex: "#ECF6FF")
  109. container.layer.cornerRadius = 23.5
  110. container.snp.makeConstraints { make in
  111. make.height.equalTo(47)
  112. }
  113. let orderButton = UIButton()
  114. orderButton.setBackgroundImage(.icSkillOrder, for: .normal)
  115. orderButton.addAction(UIAction(handler: { [weak self] _ in
  116. guard let self else { return }
  117. guard let curDetail else { return }
  118. pushToCreateOrder(curDetail)
  119. }), for: .touchUpInside)
  120. container.addSubview(orderButton)
  121. orderButton.snp.makeConstraints { make in
  122. make.trailing.equalToSuperview()
  123. make.verticalEdges.equalToSuperview()
  124. }
  125. let titleLabel = UILabel()
  126. titleLabel.font = .heading_h3
  127. titleLabel.textColor = .text_1
  128. titleLabel.text = .init(key: "A00280")
  129. titleLabel.isUserInteractionEnabled = false
  130. orderButton.addSubview(titleLabel)
  131. titleLabel.snp.makeConstraints { make in
  132. make.centerY.equalToSuperview()
  133. make.centerX.equalToSuperview().offset(4)
  134. }
  135. let descView = UIView()
  136. container.addSubview(descView)
  137. descView.snp.makeConstraints { make in
  138. make.leading.verticalEdges.equalToSuperview()
  139. make.trailing.equalTo(orderButton.snp.leading)
  140. }
  141. let priceView = UIView()
  142. descView.addSubview(priceView)
  143. priceView.snp.makeConstraints { make in
  144. make.center.equalToSuperview()
  145. }
  146. let coin = UIImageView.coinImageView()
  147. priceView.addSubview(coin)
  148. coin.snp.makeConstraints { make in
  149. make.leading.centerY.equalToSuperview()
  150. make.width.height.equalTo(20)
  151. }
  152. priceLabel.font = .heading_h2
  153. priceLabel.textColor = .text_5
  154. priceView.addSubview(priceLabel)
  155. priceLabel.snp.makeConstraints { make in
  156. make.verticalEdges.equalToSuperview()
  157. make.leading.equalTo(coin.snp.trailing).offset(4)
  158. }
  159. unitLabel.font = .body_s
  160. unitLabel.textColor = .text_5
  161. priceView.addSubview(unitLabel)
  162. unitLabel.snp.makeConstraints { make in
  163. make.leading.equalTo(priceLabel.snp.trailing)
  164. make.centerY.equalToSuperview()
  165. make.trailing.equalToSuperview()
  166. }
  167. return container
  168. }
  169. private func buildChatView() -> UIView {
  170. let button = UIButton()
  171. button.setBackgroundImage(.primary_3, for: .normal)
  172. button.layer.cornerRadius = 23.5
  173. button.clipsToBounds = true
  174. button.addAction(UIAction(handler: { [weak self] _ in
  175. guard let self else { return }
  176. guard let curDetail else { return }
  177. pushToChat(uid: curDetail.userNo, action: .locateSkill(id: curDetail.id))
  178. LNStatisticManager.shared.reportClickChat(uid: curDetail.userNo)
  179. }), for: .touchUpInside)
  180. button.snp.makeConstraints { make in
  181. make.height.equalTo(47)
  182. }
  183. let container = UIView()
  184. container.isUserInteractionEnabled = false
  185. button.addSubview(container)
  186. container.snp.makeConstraints { make in
  187. make.center.equalToSuperview()
  188. make.leading.equalToSuperview().offset(28)
  189. }
  190. let faceIc = UIImageView()
  191. faceIc.image = .icSkillChatFace
  192. container.addSubview(faceIc)
  193. faceIc.snp.makeConstraints { make in
  194. make.verticalEdges.equalToSuperview()
  195. make.leading.equalToSuperview()
  196. make.width.height.equalTo(24)
  197. }
  198. let chatLabel = UILabel()
  199. chatLabel.text = .init(key: "A00042")
  200. chatLabel.font = .heading_h3
  201. chatLabel.textColor = .text_1
  202. container.addSubview(chatLabel)
  203. chatLabel.snp.makeConstraints { make in
  204. make.leading.equalTo(faceIc.snp.trailing).offset(4)
  205. make.centerY.equalToSuperview()
  206. make.trailing.equalToSuperview()
  207. }
  208. return button
  209. }
  210. private func buildEditView() -> UIView {
  211. let container = UIView()
  212. container.backgroundColor = .init(hex: "#ECF6FF")
  213. container.layer.cornerRadius = 23.5
  214. container.snp.makeConstraints { make in
  215. make.height.equalTo(47)
  216. }
  217. let editButton = UIButton()
  218. editButton.setBackgroundImage(.icSkillEdit, for: .normal)
  219. editButton.addAction(UIAction(handler: { [weak self] _ in
  220. guard let self else { return }
  221. guard let curDetail else { return }
  222. showLoading()
  223. LNGameMateManager.shared.getSkillEditFields(id: curDetail.id) { [weak self] info in
  224. dismissLoading()
  225. guard let self else { return }
  226. guard let info, !info.fields.isEmpty else { return }
  227. info.skillId = curDetail.id
  228. pushToSkillEdit(info)
  229. }
  230. }), for: .touchUpInside)
  231. container.addSubview(editButton)
  232. editButton.snp.makeConstraints { make in
  233. make.trailing.equalToSuperview()
  234. make.verticalEdges.equalToSuperview()
  235. }
  236. let editView = UIView()
  237. editView.isUserInteractionEnabled = false
  238. editButton.addSubview(editView)
  239. editView.snp.makeConstraints { make in
  240. make.centerY.equalToSuperview()
  241. make.centerX.equalToSuperview().offset(4)
  242. }
  243. let editIc = UIImageView()
  244. editIc.image = .icEditClear.withRenderingMode(.alwaysTemplate)
  245. editIc.tintColor = .fill
  246. editView.addSubview(editIc)
  247. editIc.snp.makeConstraints { make in
  248. make.verticalEdges.equalToSuperview()
  249. make.leading.equalToSuperview()
  250. make.width.height.equalTo(24)
  251. }
  252. let titleLabel = UILabel()
  253. titleLabel.font = .heading_h3
  254. titleLabel.textColor = .text_1
  255. titleLabel.text = .init(key: "A00226")
  256. titleLabel.isUserInteractionEnabled = false
  257. editView.addSubview(titleLabel)
  258. titleLabel.snp.makeConstraints { make in
  259. make.centerY.equalToSuperview()
  260. make.trailing.equalToSuperview()
  261. make.leading.equalTo(editIc.snp.trailing).offset(2)
  262. }
  263. let descView = UIView()
  264. container.addSubview(descView)
  265. descView.snp.makeConstraints { make in
  266. make.leading.verticalEdges.equalToSuperview()
  267. make.trailing.equalTo(editButton.snp.leading)
  268. }
  269. let priceView = UIView()
  270. descView.addSubview(priceView)
  271. priceView.snp.makeConstraints { make in
  272. make.center.equalToSuperview()
  273. }
  274. let coin = UIImageView.coinImageView()
  275. priceView.addSubview(coin)
  276. coin.snp.makeConstraints { make in
  277. make.leading.centerY.equalToSuperview()
  278. make.width.height.equalTo(20)
  279. }
  280. priceLabel.font = .heading_h2
  281. priceLabel.textColor = .text_5
  282. priceView.addSubview(priceLabel)
  283. priceLabel.snp.makeConstraints { make in
  284. make.verticalEdges.equalToSuperview()
  285. make.leading.equalTo(coin.snp.trailing).offset(4)
  286. }
  287. unitLabel.font = .body_s
  288. unitLabel.textColor = .text_5
  289. priceView.addSubview(unitLabel)
  290. unitLabel.snp.makeConstraints { make in
  291. make.leading.equalTo(priceLabel.snp.trailing)
  292. make.centerY.equalToSuperview()
  293. make.trailing.equalToSuperview()
  294. }
  295. return container
  296. }
  297. private func buildSettingsView() -> UIView {
  298. let button = UIButton()
  299. button.setBackgroundImage(.primary_3, for: .normal)
  300. button.layer.cornerRadius = 23.5
  301. button.clipsToBounds = true
  302. button.addAction(UIAction(handler: { [weak self] _ in
  303. guard let self else { return }
  304. guard let curDetail else { return }
  305. showLoading()
  306. LNGameMateManager.shared.getSkillSwitchInfo(id: curDetail.id) { [weak self] res in
  307. dismissLoading()
  308. guard self != nil else { return }
  309. guard let res else { return }
  310. let panel = LNSkillSettingMenu(skill: curDetail, switchInfo: res)
  311. panel.popup()
  312. }
  313. }), for: .touchUpInside)
  314. button.snp.makeConstraints { make in
  315. make.height.equalTo(47)
  316. make.width.greaterThanOrEqualTo(90)
  317. }
  318. let settingLabel = UILabel()
  319. settingLabel.text = .init(key: "B00095")
  320. settingLabel.font = .heading_h3
  321. settingLabel.textColor = .text_1
  322. settingLabel.textAlignment = .center
  323. button.addSubview(settingLabel)
  324. settingLabel.snp.makeConstraints { make in
  325. make.center.equalToSuperview()
  326. make.leading.equalToSuperview().offset(16)
  327. }
  328. return button
  329. }
  330. private func buildDiscountView() -> UIView {
  331. let triangle = UIImageView()
  332. triangle.image = .icTriangleDown.withRenderingMode(.alwaysTemplate)
  333. triangle.tintColor = .init(hex: "#FF6F32")
  334. discountView.addSubview(triangle)
  335. triangle.snp.makeConstraints { make in
  336. make.leading.equalToSuperview().offset(13)
  337. make.bottom.equalToSuperview()
  338. make.width.equalTo(10)
  339. make.height.equalTo(4)
  340. }
  341. discountView.addSubview(newbieDiscountView)
  342. newbieDiscountView.snp.makeConstraints { make in
  343. make.horizontalEdges.equalToSuperview()
  344. make.top.equalToSuperview()
  345. make.bottom.equalTo(triangle.snp.top)
  346. }
  347. return discountView
  348. }
  349. }