Преглед на файлове

feat: 调整技能价格展示逻辑

陈文艺 преди 2 месеца
родител
ревизия
a86ac09c76

+ 5 - 1
Lanu/Common/Extension/Double+Extension.swift

@@ -35,6 +35,10 @@ extension Double {
     }
     
     var durationDisplay: String {
-        "\(Int(rounded()))“"
+        "\(toDuration)“"
+    }
+    
+    var toDuration: Int {
+        Int(rounded())
     }
 }

+ 1 - 21
Lanu/Localizable.xcstrings

@@ -3728,27 +3728,7 @@
       }
     },
     "A00163" : {
-      "extractionState" : "manual",
-      "localizations" : {
-        "en" : {
-          "stringUnit" : {
-            "state" : "translated",
-            "value" : "%1$@ = IDR %2$@"
-          }
-        },
-        "id" : {
-          "stringUnit" : {
-            "state" : "translated",
-            "value" : "%1$@ = IDR %2$@"
-          }
-        },
-        "zh-Hans" : {
-          "stringUnit" : {
-            "state" : "translated",
-            "value" : "%1$@ = IDR %2$@"
-          }
-        }
-      }
+      "extractionState" : "manual"
     },
     "A00164" : {
       "extractionState" : "manual",

+ 0 - 12
Lanu/Manager/Config/LNConfigManager.swift

@@ -37,18 +37,6 @@ class LNConfigManager {
     }
 }
 
-extension LNConfigManager {
-    var coinToCash: Decimal? {
-        guard !commonConfig.commonCoinExchangeConsts.isEmpty else {
-            LNConfigManager.shared.reloadCommonConfig()
-            return nil
-        }
-        let coinToIDR = commonConfig.commonCoinExchangeConsts.first { $0.IDR != nil && $0.goldCoin != nil }
-        guard let coinToIDR else { return nil }
-        return Decimal(coinToIDR.IDR! / coinToIDR.goldCoin!)
-    }
-}
-
 extension LNConfigManager: LNAccountManagerNotify {
     func onUserLogin() {
         reloadCommonConfig()

+ 25 - 1
Lanu/Views/Game/Join/Input/BaseInfo/LNJoinUsInputInfoView.swift

@@ -8,6 +8,7 @@
 import Foundation
 import UIKit
 import SnapKit
+import Combine
 
 
 protocol LNJoinUsInputInfoViewDelegate: NSObject {
@@ -165,6 +166,28 @@ extension LNJoinUsInputInfoView {
         stackView.addArrangedSubview(buildLanguageView())
         stackView.addArrangedSubview(buildBioView())
         
+        let bottomMenu = UIView()
+        addSubview(bottomMenu)
+        bottomMenu.snp.makeConstraints { make in
+            make.horizontalEdges.equalToSuperview()
+            make.bottom.equalToSuperview()
+        }
+        
+        let bottomGradient = CAGradientLayer()
+        bottomGradient.colors = [
+            UIColor.white.withAlphaComponent(0).cgColor,
+            UIColor.white.cgColor,
+            UIColor.white.cgColor
+        ]
+        bottomGradient.locations = [0, 0.5, 1]
+        bottomGradient.startPoint = .init(x: 0, y: 0)
+        bottomGradient.endPoint = .init(x: 0, y: 1)
+        bottomMenu.layer.addSublayer(bottomGradient)
+        bottomMenu.publisher(for: \.bounds).removeDuplicates().sink { [weak bottomGradient] newValue in
+            guard let bottomGradient else { return }
+            bottomGradient.frame = newValue
+        }.store(in: &bag)
+        
         applyButton.setTitle(.init(key: "B00045"), for: .normal)
         applyButton.setTitleColor(.text_1, for: .normal)
         applyButton.titleLabel?.font = .heading_h3
@@ -191,10 +214,11 @@ extension LNJoinUsInputInfoView {
                 delegate?.joinUsInputInfoViewDidFinish(view: self)
             }
         }), for: .touchUpInside)
-        addSubview(applyButton)
+        bottomMenu.addSubview(applyButton)
         applyButton.snp.makeConstraints { make in
             make.horizontalEdges.equalToSuperview().inset(16)
             make.bottom.equalToSuperview().offset(commonBottomInset)
+            make.top.equalToSuperview()
             make.height.equalTo(47)
         }
     }

+ 1 - 0
Lanu/Views/Game/Join/Input/LNJoinUsViewController.swift

@@ -49,6 +49,7 @@ enum LNJoinUsStep: Int, CaseIterable {
 class LNJoinUsViewController: LNViewController {
     private var curStep: LNJoinUsStep = .inputPhone {
         didSet {
+            view.endEditing(true)
             inputPhoneView.isHidden = true
             inputCaptchaView.isHidden = true
             inputInfoView.isHidden = true

+ 20 - 4
Lanu/Views/Game/Join/Input/SkillInfo/LNJoinUsSkillFieldsEditView.swift

@@ -21,6 +21,20 @@ class LNJoinUsSkillFieldsEditView: UIView {
     private var fieldViews: [LNSkillFieldBaseEditView] = []
     private var field: LNCreateSkillInputFieldsVO?
     
+    override var isHidden: Bool {
+        didSet {
+            if isHidden {
+                LNVoicePlayer.shared.stop()
+                LNVoiceRecorder.shared.stopRecord()
+            }
+        }
+    }
+    
+    deinit {
+        LNVoicePlayer.shared.stop()
+        LNVoiceRecorder.shared.stopRecord()
+    }
+    
     override init(frame: CGRect) {
         super.init(frame: frame)
         
@@ -54,14 +68,16 @@ class LNJoinUsSkillFieldsEditView: UIView {
                 nil
             }
             if let view {
-                view.delegate = self
-                view.update(field)
                 stackView.addArrangedSubview(view)
                 fieldViews.append(view)
+                view.delegate = self
+                view.update(field)
             }
         }
         
         field = info
+        
+        checkSubmitButton()
     }
     
     required init?(coder: NSCoder) {
@@ -129,12 +145,12 @@ extension LNJoinUsSkillFieldsEditView {
 
 extension LNJoinUsSkillFieldsEditView: LNSkillFieldBaseEditViewDelegate {
     func onSkillFieldBaseEditViewInputChanged(view: LNSkillFieldBaseEditView) {
-        checkSaveButton()
+        checkSubmitButton()
     }
 }
 
 extension LNJoinUsSkillFieldsEditView {
-    private func checkSaveButton() {
+    private func checkSubmitButton() {
         let allInput = fieldViews.first { !$0.hasInput() } == nil
         
         if allInput != applyButton.isEnabled {

+ 13 - 3
Lanu/Views/Game/Skill/Edit/LNSkillFieldVoiceEditView.swift

@@ -42,10 +42,20 @@ class LNSkillFieldVoiceEditView: LNSkillFieldBaseEditView {
             maxDuration = Double(limit.max)
         }
         
-        if (field.value as? String)?.isEmpty == false {
+        if let url = field.value as? String, !url.isEmpty {
             recordView.isHidden = true
             displayView.isHidden = false
-            playDurationLabel.text = "\(field.duration)“"
+            if field.duration == 0 {
+                LNVoiceResourceManager.shared.getRemoteAudioDuration(urlStr: url) { [weak self] duration, _ in
+                    guard let self else { return }
+                    guard let duration else { return }
+                    guard field.value as? String == url else { return }
+                    field.duration = duration.toDuration
+                    playDurationLabel.text = "\(field.duration)“"
+                }
+            } else {
+                playDurationLabel.text = "\(field.duration)“"
+            }
         }
     }
     
@@ -64,7 +74,7 @@ extension LNSkillFieldVoiceEditView {
             return
         }
         field?.value = url.path
-        field?.duration = Int(duration)
+        field?.duration = duration.toDuration
         playDurationLabel.text = duration.durationDisplay
         
         recordView.isHidden = true

+ 2 - 2
Lanu/Views/Order/Create/LNCreateOrderViewController.swift

@@ -143,7 +143,7 @@ extension LNCreateOrderViewController {
             unit = ""
         }
         costLabel.text = cost.toDisplay
-        orderUnitLabel.text = "/\(curCount) \(unit)"
+//        orderUnitLabel.text = "/\(curCount) \(unit)"
     }
     
     private func setupViews() {
@@ -513,7 +513,7 @@ extension LNCreateOrderViewController {
         priceView.addSubview(coin)
         coin.snp.makeConstraints { make in
             make.leading.centerY.equalToSuperview()
-            make.width.height.equalTo(16)
+            make.width.height.equalTo(20)
         }
         
         costLabel.font = .heading_h2

+ 6 - 6
Lanu/Views/Order/OrderQR/LNOrderCustomView.swift

@@ -67,11 +67,11 @@ extension LNOrderCustomView {
         let cost = skill.price * Double(customCount)
         
         costLabel.text = cost.toDisplay
-        costUnitLabel.text = if customCount <= 1 {
-            "/\(skill.unit)"
-        } else {
-            "/\(customCount) \(skill.unit)"
-        }
+//        costUnitLabel.text = if customCount <= 1 {
+//            "/\(skill.unit)"
+//        } else {
+//            "/\(skill.unit)x\(customCount)"
+//        }
     }
     
     private func setupViews() {
@@ -257,7 +257,7 @@ extension LNOrderCustomView {
         container.addSubview(costLabel)
         costLabel.snp.makeConstraints { make in
             make.verticalEdges.equalToSuperview()
-            make.leading.equalTo(coin.snp.trailing).offset(6)
+            make.leading.equalTo(coin.snp.trailing).offset(2)
         }
         
         costUnitLabel.font = .body_m

+ 1 - 1
Lanu/Views/Order/OrderQR/LNOrderQRCodeShowView.swift

@@ -39,7 +39,7 @@ class LNOrderQRCodeShowView: UIView {
         unitLabel.text = if count <= 1 {
             "/\(skill.unit)"
         } else {
-            "/\(count) \(skill.unit)"
+            "/\(skill.unit) x \(count)"
         }
         
         qrCodeIc.image = nil

+ 3 - 16
Lanu/Views/Order/OrderQR/LNOrderShareImageGenerator.swift

@@ -37,20 +37,7 @@ class LNOrderShareImageGenerator {
         countLabel.text = .init(key: "A00162", count, skill.unit)
         
         let cost = skill.price * Double(count)
-        let text: String
-        if let ratio = LNConfigManager.shared.coinToCash {
-            let idr = Decimal(cost) * ratio
-            let formator = NumberFormatter()
-            formator.maximumFractionDigits = 2
-            
-            text = .init(key: "A00163", cost.toDisplay, formator.string(from: idr as NSNumber) ?? "")
-        } else {
-            text = ""
-        }
-        let attrStr = NSMutableAttributedString(string: text)
-        let range = (text as NSString).range(of: "\(cost.toDisplay)")
-        attrStr.addAttribute(.font, value: UIFont.heading_h2, range: range)
-        costLabel.attributedText = attrStr
+        costLabel.text = cost.toDisplay
         
         container.layoutIfNeeded()
     }
@@ -122,10 +109,10 @@ extension LNOrderShareImageGenerator {
         coin.snp.makeConstraints { make in
             make.centerY.equalToSuperview()
             make.leading.equalToSuperview()
-            make.width.height.equalTo(15)
+            make.width.height.equalTo(20)
         }
         
-        costLabel.font = .body_m
+        costLabel.font = .heading_h2
         costLabel.textColor = .text_5
         priceView.addSubview(costLabel)
         costLabel.snp.makeConstraints { make in

+ 22 - 23
Lanu/Views/Profile/Edit/LNEditVoicePanel.swift

@@ -59,7 +59,8 @@ class LNEditVoicePanel: LNPopupView {
             guard let self else { return }
             LNVoicePlayer.shared.stop()
             if LNVoiceRecorder.shared.isRecording {
-                stopRecord()
+                let (url, duration) = LNVoiceRecorder.shared.stopRecord()
+                handleRecordResult(url: url, duration: duration)
             } else if curState == .edit {
                 let alert = LNCommonAlertView()
                 alert.titleLabel.text = .init(key: "B00018")
@@ -96,8 +97,7 @@ extension LNEditVoicePanel {
         }
     }
     
-    private func stopRecord() {
-        let (url, duration) = LNVoiceRecorder.shared.stopRecord()
+    private func handleRecordResult(url: URL?, duration: Double) {
         guard let url else {
             return
         }
@@ -107,7 +107,7 @@ extension LNEditVoicePanel {
         }
         curUrl = url
         curDuration = duration
-        let intDuration = Int(duration)
+        let intDuration = duration.toDuration
         editDurationLabel.text = String(format: "%02d:%02d", intDuration / 60, intDuration % 60)
         curState = .edit
     }
@@ -115,37 +115,39 @@ extension LNEditVoicePanel {
 
 extension LNEditVoicePanel: LNVoicePlayerNotify {
     func onAudioUpdateDuration(path: String, cur: TimeInterval, total: TimeInterval) {
-        guard curUrl?.path == path else { return }
-        
         if !editView.isHidden {
+            guard curUrl?.path == path else { return }
             let remain = Int(total - cur)
             editDurationLabel.text = String(format: "%02d:%02d", remain / 60, remain % 60)
         } else if !displayView.isHidden {
+            guard path == myUserInfo.voiceBar else { return }
             playDurationLabel.text = (total - cur).durationDisplay
         }
     }
     
     func onAudioStopPlay(path: String) {
-        guard curUrl?.path == path else { return }
-        
-        guard let curDuration else { return }
         if !editView.isHidden {
-            let intDuration = Int(curDuration)
+            guard curUrl?.path == path else { return }
+            guard let curDuration else { return }
+            let intDuration = curDuration.toDuration
             editDurationLabel.text = String(format: "%02d:%02d", intDuration / 60, intDuration % 60)
             editPlayButton.setImage(.icVoiceEditPlay, for: .normal)
         } else if !displayView.isHidden {
-            playDurationLabel.text = curDuration.durationDisplay
+            guard path == myUserInfo.voiceBar else { return }
+            playDurationLabel.text = "\(myVoiceBarInfo.voiceBarDuration)“"
             playIcon.image = .icVoicePlay
+            voiceWaveView.stopAnimate()
         }
     }
     
     func onAudioStartPlay(path: String) {
-        guard curUrl?.path == path else { return }
-        
-        if !displayView.isHidden {
-            playIcon.image = .icVoicePause
-        } else if !editView.isHidden {
+        if !editView.isHidden {
+            guard curUrl?.path == path else { return }
             editPlayButton.setImage(.icVoiceEditPause, for: .normal)
+        } else if !displayView.isHidden {
+            guard path == myUserInfo.voiceBar else { return }
+            playIcon.image = .icVoicePause
+            voiceWaveView.startAnimate()
         }
     }
 }
@@ -174,11 +176,7 @@ extension LNEditVoicePanel: LNVoiceRecorderNotify {
     func onRecordTaskReachMaxDuration(taskId: String, fileUrl: URL?, duration: Double) {
         guard recordTaskId == taskId else { return }
         
-        curUrl = fileUrl
-        curDuration = duration
-        let intDuration = Int(duration)
-        editDurationLabel.text = String(format: "%02d:%02d", intDuration / 60, intDuration % 60)
-        curState = .edit
+        handleRecordResult(url: fileUrl, duration: duration)
     }
 }
 
@@ -267,7 +265,8 @@ extension LNEditVoicePanel {
         recordButton.addAction(UIAction(handler: { [weak self] _ in
             guard let self else { return }
             if LNVoiceRecorder.shared.isRecording {
-                stopRecord()
+                let (url, duration) = LNVoiceRecorder.shared.stopRecord()
+                handleRecordResult(url: url, duration: duration)
             } else {
                 recordTaskId = LNVoiceRecorder.shared.startRecord(maxDuration)
             }
@@ -407,7 +406,7 @@ extension LNEditVoicePanel {
                     showToast(err)
                     return
                 }
-                LNProfileManager.shared.setMyVoiceBar(url: url, duration: Int(curDuration))
+                LNProfileManager.shared.setMyVoiceBar(url: url, duration: curDuration.toDuration)
                 { [weak self] success in
                     guard let self else { return }
                     guard success else { return }

+ 2 - 2
Lanu/Views/Profile/Relation/LNUserRelationViewController.swift

@@ -52,9 +52,9 @@ extension LNUserRelationViewController: LNUserRelationListViewDelegate {
     func onUserRelationListViewTotalChanged(view: LNUserRelationListView, total: Int) {
         switch view.curType {
         case .fans:
-            followLabel.text = .init(key: "A00238", total)
-        case .follow:
             fansLabel.text = .init(key: "A00234", total)
+        case .follow:
+            followLabel.text = .init(key: "A00238", total)
         }
     }
 }