LNGameMateCenterViewController.swift 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. //
  2. // LNGameMateCenterViewController.swift
  3. // Gami
  4. //
  5. // Created by OneeChan on 2026/1/22.
  6. //
  7. import Foundation
  8. import UIKit
  9. import SnapKit
  10. extension UIView {
  11. func pushToMateCenter() {
  12. let vc = LNGameMateCenterViewController()
  13. navigationController?.pushViewController(vc, animated: true)
  14. }
  15. }
  16. class LNGameMateCenterViewController: LNViewController {
  17. private let incomeLabel = UILabel()
  18. private let exposureLabel = UILabel()
  19. private let visitorLabel = UILabel()
  20. private let statusButton = UIButton()
  21. private let statusLabel = UILabel()
  22. private let statusDescLabel = UILabel()
  23. private let skillStackView = UIStackView()
  24. override func viewDidLoad() {
  25. super.viewDidLoad()
  26. setupViews()
  27. LNEventDeliver.addObserver(self)
  28. onUserInfoChanged(userInfo: myUserInfo)
  29. onGameMateManagerInfoChanged()
  30. }
  31. }
  32. extension LNGameMateCenterViewController: LNProfileManagerNotify, LNGameMateManagerNotify {
  33. func onUserInfoChanged(userInfo: LNUserProfileVO) {
  34. guard userInfo.userNo.isMyUid else { return }
  35. skillStackView.arrangedSubviews.forEach {
  36. skillStackView.removeArrangedSubview($0)
  37. $0.removeFromSuperview()
  38. }
  39. skillStackView.superview?.isHidden = userInfo.skills.isEmpty
  40. for skill in userInfo.skills {
  41. let view = buildSkillItem(skill)
  42. skillStackView.addArrangedSubview(view)
  43. }
  44. }
  45. func onGameMateManagerInfoChanged() {
  46. guard let myGameMateInfo else { return }
  47. incomeLabel.text = myGameMateInfo.weekBeanIncome.toDisplay
  48. exposureLabel.text = "\(myGameMateInfo.exposureCountDay)"
  49. visitorLabel.text = "\(myGameMateInfo.potentialUserCount)"
  50. if myGameMateInfo.playmateOpen {
  51. statusButton.setBackgroundImage(.primary_7, for: .normal)
  52. statusLabel.text = .init(key: "B00087")
  53. statusDescLabel.text = .init(key: "B00088")
  54. } else {
  55. statusButton.setBackgroundImage(.primary_8, for: .normal)
  56. statusLabel.text = .init(key: "B00089")
  57. statusDescLabel.text = .init(key: "B00090")
  58. }
  59. }
  60. }
  61. extension LNGameMateCenterViewController {
  62. private func setupViews() {
  63. navigationBarColor = .clear
  64. view.backgroundColor = .primary_1
  65. title = .init(key: "B00071")
  66. let topCover = UIImageView()
  67. topCover.image = .icHomeTopBg
  68. topCover.backgroundColor = .primary_1
  69. view.addSubview(topCover)
  70. topCover.snp.makeConstraints { make in
  71. make.horizontalEdges.equalToSuperview()
  72. make.top.equalTo(fakeNaviBgView)
  73. }
  74. let scrollView = UIScrollView()
  75. scrollView.showsVerticalScrollIndicator = false
  76. scrollView.showsHorizontalScrollIndicator = false
  77. scrollView.contentInset = .init(top: 0, left: 0, bottom: -view.commonBottomInset, right: 0)
  78. view.addSubview(scrollView)
  79. scrollView.snp.makeConstraints { make in
  80. make.verticalEdges.equalToSuperview()
  81. make.horizontalEdges.equalToSuperview().inset(16)
  82. }
  83. let stackView = UIStackView()
  84. stackView.axis = .vertical
  85. stackView.spacing = 12
  86. scrollView.addSubview(stackView)
  87. stackView.snp.makeConstraints { make in
  88. make.edges.equalToSuperview()
  89. make.width.equalToSuperview()
  90. }
  91. stackView.addArrangedSubview(buildRecordInfos())
  92. stackView.addArrangedSubview(buildSkillList())
  93. stackView.addArrangedSubview(buildOrderRecord())
  94. }
  95. private func buildRecordInfos() -> UIView {
  96. let container = UIView()
  97. container.layer.cornerRadius = 12
  98. container.backgroundColor = .fill
  99. let stackView = UIStackView()
  100. stackView.axis = .vertical
  101. stackView.spacing = 20
  102. container.addSubview(stackView)
  103. stackView.snp.makeConstraints { make in
  104. make.horizontalEdges.equalToSuperview().inset(10)
  105. make.verticalEdges.equalToSuperview().inset(20)
  106. }
  107. stackView.addArrangedSubview(buildIncome())
  108. stackView.addArrangedSubview(buildDataView())
  109. stackView.addArrangedSubview(buildOpenButton())
  110. return container
  111. }
  112. private func buildIncome() -> UIView {
  113. let container = UIView()
  114. container.onTap { [weak self] in
  115. guard let self else { return }
  116. view.pushToBeanView()
  117. }
  118. let incomeView = UIView()
  119. incomeView.isUserInteractionEnabled = false
  120. container.addSubview(incomeView)
  121. incomeView.snp.makeConstraints { make in
  122. make.top.equalToSuperview()
  123. make.centerX.equalToSuperview()
  124. }
  125. let beanIc = UIImageView.beanImageView()
  126. incomeView.addSubview(beanIc)
  127. beanIc.snp.makeConstraints { make in
  128. make.centerY.equalToSuperview()
  129. make.leading.equalToSuperview()
  130. make.width.height.equalTo(28)
  131. }
  132. incomeLabel.text = "0"
  133. incomeLabel.font = .systemFont(ofSize: 30, weight: .semibold)
  134. incomeLabel.textColor = .text_5
  135. incomeView.addSubview(incomeLabel)
  136. incomeLabel.snp.makeConstraints { make in
  137. make.verticalEdges.equalToSuperview()
  138. make.leading.equalTo(beanIc.snp.trailing)
  139. make.trailing.equalToSuperview()
  140. }
  141. let descView = UIView()
  142. descView.isUserInteractionEnabled = false
  143. container.addSubview(descView)
  144. descView.snp.makeConstraints { make in
  145. make.centerX.equalToSuperview()
  146. make.top.equalTo(incomeView.snp.bottom).offset(4)
  147. make.bottom.equalToSuperview()
  148. }
  149. let descLabel = UILabel()
  150. descLabel.text = .init(key: "B00072")
  151. descLabel.font = .body_m
  152. descLabel.textColor = .text_5
  153. descView.addSubview(descLabel)
  154. descLabel.snp.makeConstraints { make in
  155. make.leading.equalToSuperview()
  156. make.verticalEdges.equalToSuperview()
  157. }
  158. let arrow = UIImageView.arrowImageView(size: 12)
  159. arrow.tintColor = .text_4
  160. descView.addSubview(arrow)
  161. arrow.snp.makeConstraints { make in
  162. make.centerY.equalToSuperview()
  163. make.trailing.equalToSuperview()
  164. make.leading.equalTo(descLabel.snp.trailing).offset(4)
  165. }
  166. return container
  167. }
  168. private func buildDataView() -> UIView {
  169. let container = UIView()
  170. let stackView = UIStackView()
  171. stackView.axis = .horizontal
  172. stackView.distribution = .fillEqually
  173. container.addSubview(stackView)
  174. stackView.snp.makeConstraints { make in
  175. make.horizontalEdges.equalToSuperview().inset(5)
  176. make.verticalEdges.equalToSuperview()
  177. }
  178. stackView.addArrangedSubview(buildDataItemView(.init(key: "B00073"), contentLabel: exposureLabel, showArrow: false))
  179. let visitorView = buildDataItemView(.init(key: "B00116"), contentLabel: visitorLabel)
  180. visitorView.onTap { [weak self] in
  181. guard let self else { return }
  182. view.pushToPotentialUsers()
  183. }
  184. stackView.addArrangedSubview(visitorView)
  185. let line = buildLine()
  186. stackView.addSubview(line)
  187. line.snp.makeConstraints { make in
  188. make.center.equalToSuperview()
  189. }
  190. return container
  191. }
  192. private func buildDataItemView(_ title: String, contentLabel: UILabel, showArrow: Bool = true) -> UIView {
  193. let container = UIView()
  194. contentLabel.text = "0"
  195. contentLabel.font = .heading_h2
  196. contentLabel.textColor = .text_5
  197. container.addSubview(contentLabel)
  198. contentLabel.snp.makeConstraints { make in
  199. make.top.equalToSuperview()
  200. make.centerX.equalToSuperview()
  201. }
  202. let descView = UIView()
  203. container.addSubview(descView)
  204. descView.snp.makeConstraints { make in
  205. make.centerX.equalToSuperview()
  206. make.top.equalTo(contentLabel.snp.bottom).offset(6)
  207. make.bottom.equalToSuperview()
  208. }
  209. let descLabel = UILabel()
  210. descLabel.text = title
  211. descLabel.font = .body_s
  212. descLabel.textColor = .text_4
  213. descView.addSubview(descLabel)
  214. descLabel.snp.makeConstraints { make in
  215. make.leading.equalToSuperview()
  216. make.verticalEdges.equalToSuperview()
  217. if !showArrow {
  218. make.trailing.equalToSuperview()
  219. }
  220. }
  221. if showArrow {
  222. let arrow = UIImageView.arrowImageView(size: 10)
  223. arrow.tintColor = .text_4
  224. descView.addSubview(arrow)
  225. arrow.snp.makeConstraints { make in
  226. make.centerY.equalToSuperview()
  227. make.trailing.equalToSuperview()
  228. make.leading.equalTo(descLabel.snp.trailing).offset(4)
  229. }
  230. }
  231. return container
  232. }
  233. private func buildOpenButton() -> UIView {
  234. statusButton.layer.cornerRadius = 26
  235. statusButton.clipsToBounds = true
  236. statusButton.setBackgroundImage(.primary_8, for: .normal)
  237. statusButton.addAction(UIAction(handler: { _ in
  238. showLoading()
  239. let isOpen = myGameMateInfo?.playmateOpen == true
  240. LNGameMateManager.shared.enableGameMate(open: !isOpen) { success in
  241. dismissLoading()
  242. }
  243. }), for: .touchUpInside)
  244. statusButton.snp.makeConstraints { make in
  245. make.height.equalTo(56)
  246. }
  247. let container = UIView()
  248. container.isUserInteractionEnabled = false
  249. statusButton.addSubview(container)
  250. container.snp.makeConstraints { make in
  251. make.center.equalToSuperview()
  252. make.leading.greaterThanOrEqualToSuperview().offset(16)
  253. }
  254. statusLabel.font = .heading_h3
  255. statusLabel.textColor = .text_1
  256. statusLabel.textAlignment = .center
  257. container.addSubview(statusLabel)
  258. statusLabel.snp.makeConstraints { make in
  259. make.horizontalEdges.equalToSuperview()
  260. make.top.equalToSuperview()
  261. }
  262. statusDescLabel.font = .body_xs
  263. statusDescLabel.textColor = .primary_1
  264. container.addSubview(statusDescLabel)
  265. statusDescLabel.snp.makeConstraints { make in
  266. make.horizontalEdges.equalToSuperview()
  267. make.bottom.equalToSuperview()
  268. make.top.equalTo(statusLabel.snp.bottom)
  269. }
  270. return statusButton
  271. }
  272. private func buildLine() -> UIView {
  273. let line = UIView()
  274. line.backgroundColor = .init(hex: "#D9D9D9")
  275. line.snp.makeConstraints { make in
  276. make.width.equalTo(1)
  277. make.height.equalTo(37)
  278. }
  279. return line
  280. }
  281. private func buildSkillList() -> UIView {
  282. let container = UIView()
  283. container.layer.cornerRadius = 12
  284. container.backgroundColor = .fill
  285. let stackView = UIStackView()
  286. stackView.axis = .vertical
  287. container.addSubview(stackView)
  288. stackView.snp.makeConstraints { make in
  289. make.edges.equalToSuperview()
  290. }
  291. let header = buildSkillHeader()
  292. stackView.addArrangedSubview(header)
  293. let skillContainer = UIView()
  294. stackView.addArrangedSubview(skillContainer)
  295. skillStackView.axis = .vertical
  296. skillStackView.spacing = 8
  297. skillContainer.addSubview(skillStackView)
  298. skillStackView.snp.makeConstraints { make in
  299. make.horizontalEdges.equalToSuperview().inset(12)
  300. make.top.equalToSuperview().offset(4)
  301. make.bottom.equalToSuperview().offset(-12)
  302. }
  303. return container
  304. }
  305. private func buildSkillHeader() -> UIView {
  306. let container = UIView()
  307. container.onTap { [weak self] in
  308. guard let self else { return }
  309. view.pushToSkillManager()
  310. }
  311. container.snp.makeConstraints { make in
  312. make.height.equalTo(40)
  313. }
  314. let titleLabel = UILabel()
  315. titleLabel.text = .init(key: "B00075")
  316. titleLabel.font = .heading_h3
  317. titleLabel.textColor = .text_5
  318. container.addSubview(titleLabel)
  319. titleLabel.snp.makeConstraints { make in
  320. make.centerY.equalToSuperview()
  321. make.leading.equalToSuperview().offset(16)
  322. }
  323. let arrow = UIImageView.arrowImageView(size: 12)
  324. arrow.tintColor = .text_4
  325. container.addSubview(arrow)
  326. arrow.snp.makeConstraints { make in
  327. make.centerY.equalToSuperview()
  328. make.trailing.equalToSuperview().offset(-16)
  329. }
  330. return container
  331. }
  332. private func buildSkillItem(_ skill: LNGameMateSkillVO) -> UIView {
  333. let container = UIView()
  334. container.layer.cornerRadius = 12
  335. container.layer.borderColor = .fill_4
  336. container.layer.borderWidth = 1
  337. container.snp.makeConstraints { make in
  338. make.height.equalTo(54)
  339. }
  340. let ic = UIImageView()
  341. ic.sd_setImage(with: URL(string: skill.icon))
  342. container.addSubview(ic)
  343. ic.snp.makeConstraints { make in
  344. make.centerY.equalToSuperview()
  345. make.leading.equalToSuperview().offset(10)
  346. make.width.height.equalTo(50)
  347. }
  348. let priceView = UIView()
  349. container.addSubview(priceView)
  350. priceView.snp.makeConstraints { make in
  351. make.centerY.equalToSuperview()
  352. make.trailing.equalToSuperview().offset(-10)
  353. }
  354. let coin = UIImageView.coinImageView()
  355. priceView.addSubview(coin)
  356. coin.snp.makeConstraints { make in
  357. make.centerY.equalToSuperview()
  358. make.leading.equalToSuperview()
  359. make.width.height.equalTo(16)
  360. }
  361. let priceLabel = UILabel()
  362. priceLabel.text = skill.price.toDisplay
  363. priceLabel.font = .heading_h4
  364. priceLabel.textColor = .text_5
  365. priceView.addSubview(priceLabel)
  366. priceLabel.snp.makeConstraints { make in
  367. make.verticalEdges.equalToSuperview()
  368. make.leading.equalTo(coin.snp.trailing).offset(1)
  369. }
  370. let unitLabel = UILabel()
  371. unitLabel.text = "/\(skill.unit)"
  372. unitLabel.font = .body_s
  373. unitLabel.textColor = .text_4
  374. priceView.addSubview(unitLabel)
  375. unitLabel.snp.makeConstraints { make in
  376. make.centerY.equalToSuperview()
  377. make.leading.equalTo(priceLabel.snp.trailing).offset(1)
  378. make.trailing.equalToSuperview()
  379. }
  380. let nameLabel = UILabel()
  381. nameLabel.text = skill.name
  382. nameLabel.font = .heading_h4
  383. nameLabel.textColor = .text_5
  384. nameLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
  385. nameLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
  386. container.addSubview(nameLabel)
  387. nameLabel.snp.makeConstraints { make in
  388. make.centerY.equalToSuperview()
  389. make.leading.equalTo(ic.snp.trailing).offset(4)
  390. make.trailing.lessThanOrEqualTo(priceView.snp.leading).offset(-20)
  391. }
  392. return container
  393. }
  394. private func buildOrderRecord() -> UIView {
  395. let container = UIView()
  396. container.layer.cornerRadius = 12
  397. container.backgroundColor = .fill
  398. container.onTap { [weak self] in
  399. guard let self else { return }
  400. view.pushToOrderRecord()
  401. }
  402. container.snp.makeConstraints { make in
  403. make.height.equalTo(40)
  404. }
  405. let titleLabel = UILabel()
  406. titleLabel.text = .init(key: "A00209")
  407. titleLabel.font = .heading_h3
  408. titleLabel.textColor = .text_5
  409. container.addSubview(titleLabel)
  410. titleLabel.snp.makeConstraints { make in
  411. make.centerY.equalToSuperview()
  412. make.leading.equalToSuperview().offset(16)
  413. }
  414. let arrow = UIImageView.arrowImageView(size: 12)
  415. arrow.tintColor = .text_4
  416. container.addSubview(arrow)
  417. arrow.snp.makeConstraints { make in
  418. make.centerY.equalToSuperview()
  419. make.trailing.equalToSuperview().offset(-16)
  420. }
  421. return container
  422. }
  423. }