| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- //
- // LNBaseInfoSetupViewController.swift
- // Lanu
- //
- // Created by OneeChan on 2025/12/2.
- //
- import Foundation
- import UIKit
- import SnapKit
- import Combine
- extension UIView {
- func pushToBaseInfoSetup(_ config: LNProfileUpdateConfig) {
- let vc = LNBaseInfoSetupViewController(config: config)
- navigationController?.pushViewController(vc, animated: true)
- }
- }
- enum LNAvatarModifyType: CaseIterable {
- case camera
- case photo
- case random
-
- var title: String {
- switch self {
- case .camera: .init(key: "A00011")
- case .photo: .init(key: "A00012")
- case .random: .init(key: "A00100")
- }
- }
- }
- class LNBaseInfoSetupViewController: LNViewController {
- private let updateConfig: LNProfileUpdateConfig
-
- private let container = UIView()
- private let avatar = LNImageUploadView()
- private let nameInputField = UITextField()
- private let randomView = UIView()
-
- // private let birthDayLabel = UILabel()
- // private var curDate: TimeInterval = Date().yearAgo(-18).timeIntervalSince1970 {
- // didSet {
- // birthDayLabel.text = curDate.formattedFullDate("-")
- // }
- // }
-
- private let nextButton = UIButton()
-
- private var randomProfile: LNProfileRandomInfoVO?
-
- init(config: LNProfileUpdateConfig) {
- updateConfig = config
- super.init(nibName: nil, bundle: nil)
- }
-
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
- setupViews()
- loadRandomProfile()
- LNEventDeliver.addObserver(self)
- }
- }
- extension LNBaseInfoSetupViewController {
- private func changeAvatar() {
- let handler: (UIImage?, URL?) -> Void = { [weak self] image, _ in
- guard let self, let image = image?.compress(type: .avatar) else { return }
- avatar.uploadImage(image: image)
- checkNextButtonEnable()
- }
- let panel = LNBottomSheetMenu()
- var titles: [String] = [
- LNAvatarModifyType.camera.title,
- LNAvatarModifyType.photo.title,
- ]
- if randomProfile?.avatars.isEmpty == false {
- titles.append(LNAvatarModifyType.random.title)
- }
- panel.update(titles) { [weak self] index, text in
- guard let self else { return }
- if index == 0 {
- LNMediaPicker.shared.pick(from: view, type: .camera, options: .init(allowEdit: true), handler: handler)
- } else if index == 1 {
- LNMediaPicker.shared.pick(from: view, type: .photo, options: .init(allowEdit: true), handler: handler)
- } else if index == 2 {
- guard let item = randomProfile?.avatars.randomElement() else { return }
- avatar.loadImage(url: item)
- checkNextButtonEnable()
- }
- }
- panel.popup()
- }
-
- private func loadRandomProfile() {
- LNProfileManager.shared.getRandomProfile { [weak self] male, female in
- guard let self else { return }
-
- if updateConfig.gender == .male, let male {
- randomProfile = male
- randomView.isHidden = male.nicknames.isEmpty
- } else if updateConfig.gender == .female, let female {
- randomProfile = female
- randomView.isHidden = female.nicknames.isEmpty
- }
-
- if let url = randomProfile?.avatars.randomElement() {
- avatar.loadImage(url: url)
- }
- nameInputField.text = randomProfile?.nicknames.randomElement()
-
- checkNextButtonEnable()
- }
- }
- }
- extension LNBaseInfoSetupViewController: LNImageUploadViewDelegate {
- func onImageUploadViewStartUpload(view: LNImageUploadView) {
- checkNextButtonEnable()
- }
-
- func onImageUploadView(view: LNImageUploadView, didUploadImage url: String) {
- checkNextButtonEnable()
- }
- }
- extension LNBaseInfoSetupViewController: LNKeyboardNotify {
- func onKeyboardWillShow(curInput: UIView?, keyboardHeight: CGFloat) {
- guard let curInput, curInput.isDescendant(of: view) else { return }
-
- let frame = curInput.convert(curInput.frame, to: view)
- let offset = keyboardHeight - (view.bounds.height - CGRectGetMaxY(frame) - 20)
- if offset > 0 {
- container.snp.updateConstraints { make in
- make.top.equalToSuperview().offset(-offset)
- }
- }
- }
-
- func onKeyboardShow(curInput: UIView?, keyboardHeight: CGFloat) {
- guard curInput == nameInputField else { return }
-
- view.layoutIfNeeded()
- }
-
- func onKeyboardWillHide(curInput: UIView?) {
- guard curInput == nameInputField else { return }
-
- container.snp.updateConstraints { make in
- make.top.equalToSuperview().offset(0)
- }
- }
-
- func onKeyboardHide(curInput: UIView?) {
- guard curInput == nameInputField else { return }
-
- view.layoutIfNeeded()
- }
- }
- extension LNBaseInfoSetupViewController {
- private func checkNextButtonEnable() {
- let name = nameInputField.text ?? ""
- nextButton.isEnabled = !name.isEmpty && avatar.imageUrl?.isEmpty == false
- }
-
- private func setupViews() {
- navigationBarColor = .clear
- view.backgroundColor = .primary_1
-
- view.addSubview(container)
- container.onTap { [weak self] in
- guard let self else { return }
- self.view.endEditing(true)
- }
- container.snp.makeConstraints { make in
- make.top.equalToSuperview().offset(0)
- make.horizontalEdges.equalToSuperview()
- make.height.equalToSuperview()
- }
-
- let bg = UIImageView()
- bg.image = .icLoginProfileBg
- container.addSubview(bg)
- bg.snp.makeConstraints { make in
- make.horizontalEdges.equalToSuperview()
- make.top.equalTo(fakeNaviBgView)
- }
-
- let titleView = buildTitles()
- container.addSubview(titleView)
- titleView.snp.makeConstraints { make in
- make.horizontalEdges.equalToSuperview().inset(22)
- make.top.equalToSuperview().offset(22)
- }
-
- let baseInfo = buildBaseInfoView()
- container.addSubview(baseInfo)
- baseInfo.snp.makeConstraints { make in
- make.centerY.equalToSuperview().multipliedBy(0.8)
- make.horizontalEdges.equalToSuperview().inset(22)
- }
-
- nextButton.setBackgroundImage(.primary_8, for: .normal)
- nextButton.setTitle(.init(key: "A00101"), for: .normal)
- nextButton.setTitleColor(.text_1, for: .normal)
- nextButton.titleLabel?.font = .heading_h3
- nextButton.layer.cornerRadius = 23.5
- nextButton.clipsToBounds = true
- nextButton.isEnabled = false
- nextButton.addAction(UIAction(handler: { [weak self] _ in
- guard let self else { return }
- updateConfig.nickName = nameInputField.text ?? ""
- // updateConfig.birthday = curDate.formattedFullDate("-", normal: true)
- updateConfig.avatar = avatar.imageUrl ?? ""
- view.pushToInterestSetup(updateConfig)
- }), for: .touchUpInside)
- container.addSubview(nextButton)
- nextButton.snp.makeConstraints { make in
- make.horizontalEdges.equalToSuperview().inset(16)
- make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-4)
- make.height.equalTo(47)
- }
- }
-
- private func buildTitles() -> UIView {
- let stackView = UIStackView()
- stackView.axis = .vertical
- stackView.spacing = 6
-
- let mainLabel = UILabel()
- mainLabel.text = .init(key: "A00102")
- mainLabel.font = .init(name: UIFont.boldFontName, size: 40)
- mainLabel.textColor = .text_5
- mainLabel.numberOfLines = 0
- stackView.addArrangedSubview(mainLabel)
-
- let subTitleLabel = UILabel()
- subTitleLabel.text = .init(key: "A00103")
- subTitleLabel.font = .heading_h1
- subTitleLabel.numberOfLines = 0
- stackView.addArrangedSubview(subTitleLabel)
-
- return stackView
- }
-
- private func buildBaseInfoView() -> UIView {
- let container = UIView()
-
- let avatar = buildAvatar()
- container.addSubview(avatar)
- avatar.snp.makeConstraints { make in
- make.centerX.equalToSuperview()
- make.top.equalToSuperview()
- }
-
- let name = buildNickName()
- container.addSubview(name)
- name.snp.makeConstraints { make in
- make.horizontalEdges.equalToSuperview()
- make.top.equalTo(avatar.snp.bottom).offset(16)
- make.bottom.equalToSuperview()
- }
-
- // let birthDay = buildBirthDay()
- // container.addSubview(birthDay)
- // birthDay.snp.makeConstraints { make in
- // make.horizontalEdges.equalToSuperview()
- // make.top.equalTo(name.snp.bottom).offset(22)
- // make.bottom.equalToSuperview()
- // }
-
- return container
- }
-
- private func buildAvatar() -> UIView {
- let container = UIView()
-
- avatar.uploadType = .avatar
- avatar.image = .icProfileLoginAvatar
- avatar.layer.borderColor = UIColor.fill.cgColor
- avatar.layer.borderWidth = 2
- avatar.layer.cornerRadius = 60
- avatar.clipsToBounds = true
- avatar.delegate = self
- avatar.isUserInteractionEnabled = true
- avatar.onTap { [weak self] in
- guard let self else { return }
- changeAvatar()
- }
- container.addSubview(avatar)
- avatar.snp.makeConstraints { make in
- make.width.height.equalTo(120)
- make.edges.equalToSuperview()
- }
-
- let editAvatar = UIButton()
- editAvatar.setImage(.icLogonAvatarEdit, for: .normal)
- editAvatar.addAction(UIAction(handler: { [weak self] _ in
- guard let self else { return }
- changeAvatar()
- }), for: .touchUpInside)
- container.addSubview(editAvatar)
- editAvatar.snp.makeConstraints { make in
- make.trailing.bottom.equalToSuperview()
- }
-
- return container
- }
-
- private func buildNickName() -> UIView {
- let container = UIView()
- container.backgroundColor = .fill
- container.layer.cornerRadius = 26
- container.snp.makeConstraints { make in
- make.height.equalTo(52)
- }
-
- randomView.isHidden = true
- container.addSubview(randomView)
- randomView.snp.makeConstraints { make in
- make.verticalEdges.equalToSuperview()
- make.trailing.equalToSuperview().offset(-16)
- }
-
- let config = UIImage.SymbolConfiguration(pointSize: 16)
- let refresh = UIButton()
- refresh.setImage(.init(systemName: "arrow.clockwise", withConfiguration: config), for: .normal)
- refresh.tintColor = .text_3
- refresh.addAction(UIAction(handler: { [weak self] _ in
- guard let self else { return }
- guard let randomProfile else { return }
- nameInputField.text = randomProfile.nicknames.randomElement()
- checkNextButtonEnable()
- }), for: .touchUpInside)
- randomView.addSubview(refresh)
- refresh.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.trailing.equalToSuperview()
- make.width.equalTo(17)
- }
-
- let random = UILabel()
- random.text = .init(key: "A00104")
- random.font = .body_m
- random.textColor = .text_3
- random.setContentHuggingPriority(.defaultHigh, for: .horizontal)
- random.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
- randomView.addSubview(random)
- random.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.trailing.equalTo(refresh.snp.leading).offset(-6)
- make.leading.equalToSuperview()
- }
-
- nameInputField.textColor = .text_5
- nameInputField.font = .heading_h3
- nameInputField.attributedPlaceholder = .init(
- string: .init(key: "A00105"),
- attributes: [
- .font: UIFont.body_l,
- .foregroundColor: UIColor.text_2
- ]
- )
- nameInputField.addAction(UIAction(handler: { [weak self] _ in
- guard let self else { return }
- checkNextButtonEnable()
- }), for: .editingChanged)
- container.addSubview(nameInputField)
- nameInputField.snp.makeConstraints { make in
- make.verticalEdges.equalToSuperview()
- make.leading.equalToSuperview().offset(16)
- make.trailing.equalTo(randomView.snp.leading).offset(-6)
- }
-
- return container
- }
-
- // private func buildBirthDay() -> UIView {
- // let container = UIView()
- // container.backgroundColor = .fill
- // container.layer.cornerRadius = 26
- // container.snp.makeConstraints { make in
- // make.height.equalTo(52)
- // }
- // container.onTap { [weak self] in
- // guard let self else { return }
- // let panel = LNBirthdayDatePickerPanel()
- // panel.setDefault(curDate)
- // panel.handler = { [weak self] date in
- // guard let self else { return }
- // curDate = date
- // }
- // panel.showIn(view)
- // }
- //
- // let config = UIImage.SymbolConfiguration(pointSize: 6)
- // let arrow = UIImageView()
- // arrow.image = .init(systemName: "arrowtriangle.down.fill", withConfiguration: config)
- // arrow.tintColor = .text_5
- // container.addSubview(arrow)
- // arrow.snp.makeConstraints { make in
- // make.centerY.equalToSuperview()
- // make.trailing.equalToSuperview().offset(-16)
- // }
- //
- // birthDayLabel.text = curDate.formattedFullDate("-")
- // birthDayLabel.font = .body_l
- // birthDayLabel.textColor = .text_5
- // container.addSubview(birthDayLabel)
- // birthDayLabel.snp.makeConstraints { make in
- // make.centerY.equalToSuperview()
- // make.leading.equalToSuperview().offset(16)
- // }
- //
- // return container
- // }
- }
- #if DEBUG
- import SwiftUI
- struct LNBaseInfoSetupViewControllerPreview: UIViewControllerRepresentable {
- func makeUIViewController(context: Context) -> some UIViewController {
- LNBaseInfoSetupViewController(config: LNProfileUpdateConfig())
- }
-
- func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
-
- }
- }
- #Preview(body: {
- LNBaseInfoSetupViewControllerPreview()
- })
- #endif
|