Przeglądaj źródła

feat: 补充技能订单评论列表功能

陈文艺 2 miesięcy temu
rodzic
commit
00f2995be2

+ 2 - 0
Lanu.xcodeproj/project.pbxproj

@@ -203,6 +203,8 @@
 				Views/Game/Skill/Edit/LNSkillFieldSingleLineEditView.swift,
 				Views/Game/Skill/Edit/LNSkillFieldVoiceEditView.swift,
 				Views/Game/Skill/LNSkillBottomMenuView.swift,
+				Views/Game/Skill/LNSkillCommentsPanel.swift,
+				Views/Game/Skill/LNSkillCommentsView.swift,
 				Views/Game/Skill/LNSkillDetailViewController.swift,
 				Views/Game/Skill/LNSkillPhotosView.swift,
 				Views/Game/Skill/LNSkillSettingMenu.swift,

+ 44 - 1
Lanu/Localizable.xcstrings

@@ -3728,7 +3728,27 @@
       }
     },
     "A00163" : {
-      "extractionState" : "manual"
+      "extractionState" : "manual",
+      "localizations" : {
+        "en" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "User Comments %d"
+          }
+        },
+        "id" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Komentar %d"
+          }
+        },
+        "zh-Hans" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "用户评论 % d"
+          }
+        }
+      }
     },
     "A00164" : {
       "extractionState" : "manual",
@@ -9134,6 +9154,29 @@
           }
         }
       }
+    },
+    "B00111" : {
+      "extractionState" : "manual",
+      "localizations" : {
+        "en" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "All reviews"
+          }
+        },
+        "id" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "Semua Ulasan"
+          }
+        },
+        "zh-Hans" : {
+          "stringUnit" : {
+            "state" : "translated",
+            "value" : "全部评论"
+          }
+        }
+      }
     }
   },
   "version" : "1.1"

+ 13 - 0
Lanu/Manager/GameMate/LNGameMateManager.swift

@@ -87,6 +87,19 @@ extension LNGameMateManager {
             }
         }
     }
+    
+    func getSkillCommentList(id: String, next: String? = nil,
+                             queue: DispatchQueue = .main,
+                             handler: @escaping (LNSkillCommentListResponse?) -> Void) {
+        LNHttpManager.shared.getSkillCommentList(id: id, size: 30, next: next ?? "") { res, err in
+            queue.asyncIfNotGlobal {
+                handler(res)
+            }
+            if let err {
+                showToast(err.errorDesc)
+            }
+        }
+    }
 }
 
 extension LNGameMateManager {

+ 17 - 0
Lanu/Manager/GameMate/Network/LNGameMateResponse.swift

@@ -448,3 +448,20 @@ class LNSkillFilterConfig: Decodable {
 class LNSkillFilterConfigList: Decodable {
     var list: [LNSkillFilterConfig] = []
 }
+
+@AutoCodable
+class LNSkillCommentVO: Decodable {
+    var time: Int = 0
+    var avatar: String = ""
+    var nickname: String = ""
+    var star: Double = 0
+    var userNo: String = ""
+    var comment: String = ""
+}
+
+@AutoCodable
+class LNSkillCommentListResponse: Decodable {
+    var list: [LNSkillCommentVO] = []
+    var next: String = ""
+    var total: Int = 0
+}

+ 13 - 1
Lanu/Manager/GameMate/Network/LNHttpManager+GameMate.swift

@@ -16,6 +16,7 @@ private let kNetPath_GameMate_Skills = "/skill/user/goods"
 private let kNetPath_GameMate_Info = "/user/playmate/info"
 private let kNetPath_GameMate_Skill_Detail = "/skill/detail"
 private let kNetPath_GameMate_Score = "/user/playmate/charmStar"
+private let kNetPath_GameMate_Skill_Comment = "/skill/goods/comments"
 
 private let kNetPath_GameMate_Search = "/playmate/search"
 
@@ -147,7 +148,7 @@ extension LNHttpManager {
     }
 }
 
-// MARK: 获取陪玩师各种信息
+// MARK: 陪玩师信息查询
 extension LNHttpManager {
     func getUserSkills(uid: String, completion: @escaping (LNGameMateSkillListResponse?, LNHttpError?) -> Void) {
         post(path: kNetPath_GameMate_Skills, params: ["id": uid], completion: completion)
@@ -179,6 +180,17 @@ extension LNHttpManager {
             "star": score
         ], completion: completion)
     }
+    
+    func getSkillCommentList(id: String, size: Int, next: String,
+                             completion: @escaping (LNSkillCommentListResponse?, LNHttpError?) -> Void) {
+        post(path: kNetPath_GameMate_Skill_Comment, params: [
+            "skillId": id,
+            "page": [
+                "size": size,
+                "next": next
+            ]
+        ], completion: completion)
+    }
 }
 
 // MARK: 陪玩师申请

+ 13 - 2
Lanu/Views/Game/Skill/LNSkillBottomMenuView.swift

@@ -17,7 +17,18 @@ class LNSkillBottomMenuView: UIView {
     
     private var curDetail: LNGameMateSkillDetailVO?
     
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        
+        setupViews()
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
     func update(_ detail: LNGameMateSkillDetailVO) {
+        isHidden = false
         priceLabel.text = detail.price.toDisplay
         unitLabel.text = "/\(detail.unit)"
         
@@ -27,7 +38,7 @@ class LNSkillBottomMenuView: UIView {
                 addSubview(editView)
                 editView.snp.makeConstraints { make in
                     make.leading.equalToSuperview().inset(16)
-                    make.bottom.equalToSuperview().offset(-4)
+                    make.bottom.equalToSuperview().offset(commonBottomInset)
                     make.top.equalToSuperview().offset(16)
                 }
                 
@@ -43,7 +54,7 @@ class LNSkillBottomMenuView: UIView {
                 addSubview(orderView)
                 orderView.snp.makeConstraints { make in
                     make.leading.equalToSuperview().inset(16)
-                    make.bottom.equalToSuperview().offset(-4)
+                    make.bottom.equalToSuperview().offset(commonBottomInset)
                     make.top.equalToSuperview().offset(16)
                 }
                 

+ 161 - 0
Lanu/Views/Game/Skill/LNSkillCommentsPanel.swift

@@ -0,0 +1,161 @@
+//
+//  LNSkillCommentsPanel.swift
+//  Gami
+//
+//  Created by OneeChan on 2026/2/3.
+//
+
+import Foundation
+import UIKit
+import SnapKit
+import MJRefresh
+
+
+class LNSkillCommentsPanel: LNPopupView {
+    private let tableView = UITableView()
+    
+    private var skillId = ""
+    private var nextTag: String?
+    private var list: [LNSkillCommentVO] = []
+    
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        
+        setupViews()
+    }
+    
+    func update(_ skillId: String) {
+        self.skillId = skillId
+        
+        tableView.mj_header?.beginRefreshing()
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+}
+
+extension LNSkillCommentsPanel {
+    private func loadList() {
+        LNGameMateManager.shared.getSkillCommentList(id: skillId, next: nextTag) { [weak self] res in
+            guard let self else { return }
+            tableView.mj_header?.endRefreshing()
+            
+            if let list = res?.list {
+                if nextTag == nil {
+                    self.list = list
+                } else {
+                    self.list.append(contentsOf: list)
+                }
+                tableView.reloadData()
+            }
+            nextTag = res?.next
+            if res?.next.isEmpty != false {
+                tableView.mj_footer?.endRefreshingWithNoMoreData()
+            }
+        }
+    }
+}
+
+extension LNSkillCommentsPanel: UITableViewDataSource {
+    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+        list.count
+    }
+    
+    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        let cell = tableView.dequeueReusableCell(withIdentifier: LNSkillCommentCell.className, for: indexPath) as! LNSkillCommentCell
+        
+        cell.update(list[indexPath.row])
+        
+        return cell
+    }
+}
+
+extension LNSkillCommentsPanel {
+    private func setupViews() {
+        containerHeight = .percent(0.8)
+        
+        let header = buildHeader()
+        container.addSubview(header)
+        header.snp.makeConstraints { make in
+            make.horizontalEdges.equalToSuperview()
+            make.top.equalToSuperview()
+        }
+        
+        let listView = buildListView()
+        container.addSubview(listView)
+        listView.snp.makeConstraints { make in
+            make.horizontalEdges.equalToSuperview()
+            make.top.equalTo(header.snp.bottom)
+            make.bottom.equalToSuperview()
+        }
+    }
+    
+    private func buildHeader() -> UIView {
+        let container = UIView()
+        container.snp.makeConstraints { make in
+            make.height.equalTo(52)
+        }
+        
+        let titleLabel = UILabel()
+        titleLabel.text = .init(key: "B00111")
+        titleLabel.font = .heading_h3
+        titleLabel.textColor = .text_5
+        container.addSubview(titleLabel)
+        titleLabel.snp.makeConstraints { make in
+            make.center.equalToSuperview()
+        }
+        
+        return container
+    }
+    
+    private func buildListView() -> UIView {
+        let header = MJRefreshNormalHeader { [weak self] in
+            guard let self else { return }
+            self.nextTag = nil
+            self.loadList()
+        }
+        header.lastUpdatedTimeLabel?.isHidden = true
+        header.stateLabel?.isHidden = true
+        tableView.mj_header = header
+        
+        let footer = MJRefreshAutoNormalFooter { [weak self] in
+            guard let self else { return }
+            self.loadList()
+        }
+        footer.setTitle("", for: .noMoreData)
+        footer.setTitle(.init(key: "A00046"), for: .idle)
+        tableView.mj_footer = footer
+        
+        tableView.register(LNSkillCommentCell.self, forCellReuseIdentifier: LNSkillCommentCell.className)
+        tableView.dataSource = self
+        tableView.allowsSelection = false
+        tableView.separatorStyle = .singleLine
+        tableView.separatorInset = .init(top: 0, left: 16, bottom: 0, right: 16)
+        tableView.backgroundColor = .clear
+        
+        return tableView
+    }
+}
+
+private class LNSkillCommentCell: UITableViewCell {
+    private let commentView = LNSkillCommentItemView()
+    
+    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+        super.init(style: style, reuseIdentifier: reuseIdentifier)
+        
+        contentView.addSubview(commentView)
+        commentView.snp.makeConstraints { make in
+            make.horizontalEdges.equalToSuperview().inset(16)
+            make.verticalEdges.equalToSuperview()
+        }
+    }
+    
+    func update(_ comment: LNSkillCommentVO) {
+        commentView.update(comment)
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+}

+ 225 - 0
Lanu/Views/Game/Skill/LNSkillCommentsView.swift

@@ -0,0 +1,225 @@
+//
+//  LNSkillCommentsView.swift
+//  Gami
+//
+//  Created by OneeChan on 2026/2/3.
+//
+
+import Foundation
+import UIKit
+import SnapKit
+
+
+class LNSkillCommentsView: UIView {
+    private let starLabel = UILabel()
+    private let titleLabel = UILabel()
+    private let stackView = UIStackView()
+    
+    private var curSkill: LNGameMateSkillDetailVO?
+    
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        
+        setupViews()
+    }
+    
+    func update(_ detail: LNGameMateSkillDetailVO) {
+        curSkill = detail
+        starLabel.text = "\(detail.star)"
+        
+        LNGameMateManager.shared.getSkillCommentList(id: detail.id) { [weak self] res in
+            guard let self else { return }
+            guard let res else { return }
+            isHidden = res.list.isEmpty
+            titleLabel.text = .init(key: "A00163", res.total)
+            reloadList(res.list)
+        }
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+}
+
+extension LNSkillCommentsView {
+    private func reloadList(_ list: [LNSkillCommentVO]) {
+        stackView.arrangedSubviews.forEach {
+            stackView.removeArrangedSubview($0)
+            $0.removeFromSuperview()
+        }
+        
+        let comments = list.prefix(3)
+        comments.forEach {
+            let itemView = LNSkillCommentItemView()
+            itemView.update($0)
+            stackView.addArrangedSubview(itemView)
+            if $0.userNo != comments.last?.userNo {
+                let line = UIView()
+                line.backgroundColor = .fill_2
+                line.snp.makeConstraints { make in
+                    make.height.equalTo(1)
+                }
+                stackView.addArrangedSubview(line)
+            }
+        }
+    }
+    
+    private func setupViews() {
+        let header = buildHeader()
+        addSubview(header)
+        header.snp.makeConstraints { make in
+            make.horizontalEdges.equalToSuperview()
+            make.top.equalToSuperview()
+        }
+        
+        stackView.axis = .vertical
+        stackView.spacing = 0
+        addSubview(stackView)
+        stackView.snp.makeConstraints { make in
+            make.horizontalEdges.equalToSuperview()
+            make.top.equalTo(header.snp.bottom)
+            make.bottom.equalToSuperview()
+        }
+    }
+    
+    private func buildHeader() -> UIView {
+        let container = UIView()
+        container.onTap { [weak self] in
+            guard let self else { return }
+            guard let curSkill else { return }
+            let panel = LNSkillCommentsPanel()
+            panel.update(curSkill.id)
+            panel.popup()
+        }
+        
+        let starIc = UIImageView(image: .icStarFill)
+        container.addSubview(starIc)
+        starIc.snp.makeConstraints { make in
+            make.leading.equalToSuperview()
+            make.centerY.equalToSuperview()
+            make.width.height.equalTo(16)
+        }
+        
+        starLabel.font = .heading_h3
+        starLabel.textColor = .text_5
+        container.addSubview(starLabel)
+        starLabel.snp.makeConstraints { make in
+            make.verticalEdges.equalToSuperview()
+            make.leading.equalTo(starIc.snp.trailing).offset(4)
+        }
+        
+        let dotView = UIView()
+        dotView.backgroundColor = .text_3
+        dotView.layer.cornerRadius = 2
+        container.addSubview(dotView)
+        dotView.snp.makeConstraints { make in
+            make.centerY.equalToSuperview()
+            make.leading.equalTo(starLabel.snp.trailing).offset(8)
+            make.width.height.equalTo(4)
+        }
+        
+        titleLabel.font = .heading_h3
+        titleLabel.textColor = .text_5
+        container.addSubview(titleLabel)
+        titleLabel.snp.makeConstraints { make in
+            make.centerY.equalToSuperview()
+            make.leading.equalTo(dotView.snp.trailing).offset(8)
+        }
+        
+        let arrow = UIImageView.arrowImageView(size: 10)
+        arrow.tintColor = .text_4
+        container.addSubview(arrow)
+        arrow.snp.makeConstraints { make in
+            make.trailing.equalToSuperview()
+            make.centerY.equalToSuperview()
+        }
+        
+        let moreLabel = UILabel()
+        moreLabel.text = .init(key: "A00048")
+        moreLabel.font = .body_s
+        moreLabel.textColor = .text_5
+        container.addSubview(moreLabel)
+        moreLabel.snp.makeConstraints { make in
+            make.centerY.equalToSuperview()
+            make.trailing.equalTo(arrow.snp.leading).offset(-4)
+        }
+        
+        return container
+    }
+}
+
+
+class LNSkillCommentItemView: UIView {
+    private let avatar = UIImageView()
+    private let nameLabel = UILabel()
+    private let starView = LNFiveStarScoreView()
+    private let commentLabel = UILabel()
+    private let timeLabel = UILabel()
+    
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        
+        setupViews()
+    }
+    
+    func update(_ comment: LNSkillCommentVO) {
+        avatar.sd_setImage(with: URL(string: comment.avatar))
+        nameLabel.text = comment.nickname
+        starView.score = comment.star
+        commentLabel.text = comment.comment
+        timeLabel.text = TimeInterval(comment.time / 1_000).tencentIMTimeDesc
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+}
+
+extension LNSkillCommentItemView {
+    private func setupViews() {
+        avatar.layer.cornerRadius = 21
+        avatar.clipsToBounds = true
+        addSubview(avatar)
+        avatar.snp.makeConstraints { make in
+            make.leading.equalToSuperview()
+            make.top.equalToSuperview().offset(18)
+            make.width.height.equalTo(42)
+        }
+        
+        nameLabel.font = .heading_h4
+        nameLabel.textColor = .text_5
+        addSubview(nameLabel)
+        nameLabel.snp.makeConstraints { make in
+            make.leading.equalTo(avatar.snp.trailing).offset(10)
+            make.top.equalTo(avatar)
+        }
+        
+        starView.icSize = 13
+        starView.spacing = 2
+        addSubview(starView)
+        starView.snp.makeConstraints { make in
+            make.trailing.equalToSuperview()
+            make.centerY.equalTo(nameLabel)
+            make.leading.greaterThanOrEqualTo(nameLabel.snp.trailing).offset(16)
+        }
+        
+        commentLabel.font = .body_m
+        commentLabel.textColor = .text_5
+        commentLabel.numberOfLines = 0
+        addSubview(commentLabel)
+        commentLabel.snp.makeConstraints { make in
+            make.leading.equalTo(nameLabel)
+            make.top.equalTo(nameLabel.snp.bottom).offset(4)
+            make.trailing.equalToSuperview()
+        }
+        
+        timeLabel.font = .body_xs
+        timeLabel.textColor = .text_3
+        addSubview(timeLabel)
+        timeLabel.snp.makeConstraints { make in
+            make.leading.equalTo(nameLabel)
+            make.top.equalTo(commentLabel.snp.bottom).offset(4)
+            make.bottom.equalToSuperview().offset(-18)
+        }
+    }
+}

+ 36 - 21
Lanu/Views/Game/Skill/LNSkillDetailViewController.swift

@@ -35,6 +35,7 @@ class LNSkillDetailViewController: LNViewController {
     private let descLabel = UILabel()
     private let tagView = LNSkillTagView()
     private let photosView = LNSkillPhotosView()
+    private let commentsView = LNSkillCommentsView()
     private let bottomMenu = LNSkillBottomMenuView()
     
     private var detail: LNGameMateSkillDetailVO?
@@ -81,9 +82,15 @@ extension LNSkillDetailViewController {
             cover.sd_setImage(with: URL(string: info.cover.isEmpty ? info.avatar : info.cover))
             userInfoView.update(info)
             gameNameLabel.text = info.categoryName
+            
+            descLabel.isHidden = info.summary.isEmpty
             descLabel.text = info.summary
+            
             tagView.update(info.labels)
             photosView.update(info)
+            
+            commentsView.update(info)
+            
             bottomMenu.update(info)
             
             avatar.sd_setImage(with: URL(string: info.avatar))
@@ -169,12 +176,13 @@ extension LNSkillDetailViewController {
         }
         
         let scrollView = UIScrollView()
+        scrollView.delegate = self
+        scrollView.clipsToBounds = false
+        scrollView.backgroundColor = .fill
         scrollView.contentInsetAdjustmentBehavior = .never
         scrollView.showsVerticalScrollIndicator = false
         scrollView.showsHorizontalScrollIndicator = false
-        scrollView.backgroundColor = .fill
-        scrollView.delegate = self
-        scrollView.clipsToBounds = false
+        scrollView.contentInset = .init(top: 0, left: 0, bottom: -view.commonBottomInset + 47, right: 0)
         stackView.addArrangedSubview(scrollView)
         
         let fakeView = UIView()
@@ -209,7 +217,11 @@ extension LNSkillDetailViewController {
         }
         
         let menu = buildBottomMenu()
-        stackView.addArrangedSubview(menu)
+        view.addSubview(menu)
+        menu.snp.makeConstraints { make in
+            make.horizontalEdges.equalToSuperview()
+            make.bottom.equalToSuperview()
+        }
     }
     
     private func setupNavBar() {
@@ -311,6 +323,7 @@ extension LNSkillDetailViewController {
         
         cover.contentMode = .scaleAspectFill
         cover.isUserInteractionEnabled = true
+        cover.clipsToBounds = true
         cover.onTap { [weak self] in
             guard let self else { return }
             guard let cover = detail?.cover,
@@ -352,28 +365,30 @@ extension LNSkillDetailViewController {
             make.height.equalTo(1)
         }
         
-        descLabel.font = .body_m
-        descLabel.textColor = .text_4
-        descLabel.numberOfLines = 0
-        container.addSubview(descLabel)
-        descLabel.snp.makeConstraints { make in
+        let stackView = UIStackView()
+        stackView.axis = .vertical
+        stackView.spacing = 12
+        container.addSubview(stackView)
+        stackView.snp.makeConstraints { make in
             make.horizontalEdges.equalToSuperview().inset(16)
             make.top.equalTo(line.snp.bottom).offset(10)
+            make.bottom.equalToSuperview()
         }
         
-        container.addSubview(tagView)
-        tagView.snp.makeConstraints { make in
-            make.horizontalEdges.equalToSuperview().inset(16)
-            make.top.equalTo(descLabel.snp.bottom).offset(14)
-            make.height.equalTo(0).priority(.low)
-        }
+        descLabel.font = .body_m
+        descLabel.textColor = .text_4
+        descLabel.numberOfLines = 0
+        descLabel.isHidden = true
+        stackView.addArrangedSubview(descLabel)
         
-        container.addSubview(photosView)
-        photosView.snp.makeConstraints { make in
-            make.horizontalEdges.equalToSuperview().inset(16)
-            make.top.equalTo(tagView.snp.bottom).offset(16)
-            make.bottom.equalToSuperview()
-        }
+        tagView.isHidden = true
+        stackView.addArrangedSubview(tagView)
+        
+        photosView.isHidden = true
+        stackView.addArrangedSubview(photosView)
+        
+        commentsView.isHidden = true
+        stackView.addArrangedSubview(commentsView)
         
         return container
     }

+ 1 - 0
Lanu/Views/Game/Skill/LNSkillPhotosView.swift

@@ -26,6 +26,7 @@ class LNSkillPhotosView: UIView {
             stackView.removeArrangedSubview($0)
             $0.removeFromSuperview()
         }
+        isHidden = detail.images.isEmpty
         let urls = detail.images
         for (index, url) in urls.enumerated() {
             let container = UIView()

+ 6 - 0
Lanu/Views/Game/Skill/LNSkillTagView.swift

@@ -20,6 +20,8 @@ class LNSkillTagView: UIView {
     }
     
     func update(_ tags: [String]) {
+        isHidden = tags.isEmpty
+        
         var itemViews: [UIView] = []
         tags.forEach {
             let container = UIView()
@@ -52,6 +54,10 @@ class LNSkillTagView: UIView {
 
 extension LNSkillTagView {
     private func setupViews() {
+        snp.makeConstraints { make in
+            make.height.equalTo(0).priority(.low)
+        }
+        
         stackView.spacing = 8
         stackView.itemSpacing = 10
         addSubview(stackView)

+ 2 - 2
Lanu/Views/Game/Skill/LNSkillUserInfoView.swift

@@ -184,7 +184,7 @@ extension LNSkillUserInfoView {
         orderView.snp.makeConstraints { make in
             make.centerX.equalToSuperview()
             make.bottom.equalToSuperview()
-            make.top.equalTo(scoreLabel.snp.bottom).offset(4)
+            make.top.equalTo(scoreLabel.snp.bottom)
         }
         
         let orderLabel = UILabel()
@@ -202,7 +202,7 @@ extension LNSkillUserInfoView {
         orderView.addSubview(orderCountLabel)
         orderCountLabel.snp.makeConstraints { make in
             make.leading.equalTo(orderLabel.snp.trailing).offset(2)
-            make.verticalEdges.equalTo(orderLabel)
+            make.verticalEdges.equalToSuperview()
             make.trailing.equalToSuperview()
         }
         

+ 1 - 1
Lanu/Views/Profile/Profile/LNProfileBottomMenu.swift

@@ -104,7 +104,7 @@ extension LNProfileBottomMenu {
         stackView.snp.makeConstraints { make in
             make.horizontalEdges.equalToSuperview().inset(16)
             make.top.equalToSuperview().offset(16)
-            make.bottom.equalToSuperview().offset(-4)
+            make.bottom.equalToSuperview().offset(commonBottomInset)
         }
         
         let follow = buildFollowView()

+ 1 - 1
Lanu/Views/Profile/Profile/LNProfileViewController.swift

@@ -248,7 +248,7 @@ extension LNProfileViewController {
         view.addSubview(menu)
         menu.snp.makeConstraints { make in
             make.horizontalEdges.equalToSuperview()
-            make.bottom.equalToSuperview().offset(-view.safeBottomInset)
+            make.bottom.equalToSuperview()
         }
         
         scoreView.isHidden = true