diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift index 48a252e3..6d106f2b 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseDetailVC.swift @@ -32,6 +32,7 @@ final class CourseDetailVC: UIViewController { private var isMyCourse: Bool? // MARK: - UI Components + private lazy var navibar = CustomNavigationBar(self, type: .titleWithLeftButton) private let moreButton = UIButton(type: .system).then { $0.setImage(ImageLiterals.icMore, for: .normal) @@ -83,9 +84,9 @@ final class CourseDetailVC: UIViewController { $0.font = .h4 } - private let courseDistanceInfoView = CourseDetailInfoView(title: "거리", description: "0.0km") + private let courseDistanceInfoView = CourseDetailInfoView(title: "거리", description: String()) - private let courseDepartureInfoView = CourseDetailInfoView(title: "출발지", description: "위치") + private let courseDepartureInfoView = CourseDetailInfoView(title: "출발지", description: String()) private lazy var courseDetailStackView = UIStackView(arrangedSubviews: [courseDistanceInfoView, courseDepartureInfoView]).then { $0.axis = .vertical @@ -113,6 +114,11 @@ final class CourseDetailVC: UIViewController { setUI() setLayout() setAddTarget() + self.hideTabBar(wantsToHide: true) + } + + override func viewWillAppear(_ animated: Bool) { + self.hideTabBar(wantsToHide: true) getUploadedCourseDetail() } } @@ -142,10 +148,11 @@ extension CourseDetailVC { if isMyCourse == true { let editAlertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - let courseEditVC = CourseEditVC() - courseEditVC.loadData(model: uploadedCourseDetailModel) - courseEditVC.publicCourseId = self.publicCourseId + let editAction = UIAlertAction(title: "수정하기", style: .default, handler: {(_: UIAlertAction!) in + let courseEditVC = CourseEditVC() + courseEditVC.loadData(model: uploadedCourseDetailModel) + courseEditVC.publicCourseId = self.publicCourseId self.navigationController?.pushViewController(courseEditVC, animated: false) }) let deleteAlertVC = RNAlertVC(description: "러닝 기록을 정말로 삭제하시겠어요?").setButtonTitle("취소", "삭제하기") @@ -155,7 +162,8 @@ extension CourseDetailVC { } deleteAlertVC.modalPresentationStyle = .overFullScreen let deleteAction = UIAlertAction(title: "삭제하기", style: .destructive, handler: {(_: UIAlertAction!) in - self.present(deleteAlertVC, animated: false, completion: nil)}) + self.present(deleteAlertVC, animated: false, completion: nil) + }) [ editAction, deleteAction, cancelAction].forEach { editAlertController.addAction($0) } present(editAlertController, animated: false, completion: nil) } else { @@ -205,7 +213,8 @@ extension CourseDetailVC { self.uploadedCourseDetailModel = model self.mapImageView.setImage(with: model.publicCourse.image) self.profileImageView.image = GoalRewardInfoModel.stampNameImageDictionary[model.user.image] - self.profileNameLabel.text = model.user.nickname + // 탈퇴 유저 처리 + model.user.nickname == "알 수 없음" ? setNullUser() : (self.profileNameLabel.text = model.user.nickname) self.runningLevelLabel.text = "Lv. \(model.user.level)" self.courseTitleLabel.text = model.publicCourse.title self.isMyCourse = model.user.isNowUser @@ -221,14 +230,21 @@ extension CourseDetailVC { private func setAddTarget() { likeButton.addTarget(self, action: #selector(likeButtonDidTap), for: .touchUpInside) - moreButton.addTarget(self, action: #selector(moreButtonDidTap), for: .touchUpInside) } + + private func setNullUser() { + self.profileImageView.image = ImageLiterals.imgPerson + self.profileNameLabel.textColor = .g2 + self.profileNameLabel.text = "(알 수 없음)" + self.runningLevelLabel.isHidden = true + } } +// MARK: - Layout Helpers + extension CourseDetailVC { - - // MARK: - Layout Helpers + private func setNavigationBar() { view.addSubview(navibar) view.addSubview(moreButton) @@ -237,7 +253,7 @@ extension CourseDetailVC { make.height.equalTo(48) } moreButton.snp.makeConstraints { make in - make.trailing.equalTo(self.view.safeAreaLayoutGuide).inset(16) + make.trailing.equalTo(self.view.safeAreaLayoutGuide) make.centerY.equalTo(navibar) } @@ -347,6 +363,8 @@ extension CourseDetailVC { } } +// MARK: - Network + extension CourseDetailVC { private func getUploadedCourseDetail() { guard let publicCourseId = self.publicCourseId else { return } diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseEditVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseEditVC.swift index dcd06a94..9fee3994 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseEditVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDetail/VC/CourseEditVC.swift @@ -14,11 +14,16 @@ import Moya class CourseEditVC: UIViewController { // MARK: - Properties - private let PublicCourseProvider = Providers.publicCourseProvider + private let PublicCourseProvider = Providers.publicCourseProvider + private let courseTitleMaxLength = 20 + private let activityTextMaxLength = 150 var publicCourseId: Int? + var currentTitle: String? + var currentDescription: String? + // MARK: - UI Components private lazy var navibar = CustomNavigationBar(self, type: .titleWithLeftButton).setTitle("") @@ -29,7 +34,7 @@ class CourseEditVC: UIViewController { private let mapImageView = UIImageView().then { $0.image = UIImage(named: "") } - private let courseTitleTextField = UITextField().then { + private lazy var courseTitleTextField = UITextField().then { $0.attributedPlaceholder = NSAttributedString( string: "글 제목", attributes: [.font: UIFont.h4, .foregroundColor: UIColor.g3] @@ -45,25 +50,26 @@ class CourseEditVC: UIViewController { private let departureInfoView = CourseDetailInfoView(title: "출발지", description: "") private let placeholder = "코스에 대한 소개를 적어주세요.(난이도/풍경/지형)" - let activityTextView = UITextView().then { - $0.font = .b4 + private let activityTextView = UITextView().then { + $0.font = .b3 $0.backgroundColor = .m3 $0.tintColor = .m1 $0.textContainerInset = UIEdgeInsets(top: 14, left: 12, bottom: 14, right: 12) } - + // MARK: - Life Cycle override func viewDidLoad() { super.viewDidLoad() + setDelegate() setNavigationBar() setUI() setLayout() - setupTextView() setAddTarget() setKeyboardNotification() setTapGesture() addKeyboardObserver() + textViewDidChange(self.activityTextView) } override func viewWillDisappear(_ animated: Bool) { @@ -79,20 +85,31 @@ class CourseEditVC: UIViewController { // MARK: - Methods extension CourseEditVC { + private func setDelegate() { + self.courseTitleTextField.delegate = self + self.activityTextView.delegate = self + } + private func setAddTarget() { self.courseTitleTextField.addTarget(self, action: #selector(textFieldTextDidChange), for: .editingChanged) self.editButton.addTarget(self, action: #selector(editButtonDidTap), for: .touchUpInside) } + private func setCurrentInfo() { + self.courseTitleTextField.text = self.currentTitle + self.activityTextView.text = self.currentDescription + } + // data 그대로 load하기 func loadData(model: UploadedCourseDetailResponseDto) { mapImageView.setImage(with: model.publicCourse.image) - courseTitleTextField.text = model.publicCourse.title - distanceInfoView.setDescriptionText(description: "\(model.publicCourse.distance ?? 0.0)") + self.currentTitle = model.publicCourse.title + distanceInfoView.setDescriptionText(description: "\(model.publicCourse.distance ?? 0.0)km") let departure = "\(model.publicCourse.departure.region) \(model.publicCourse.departure.city)" departureInfoView.setDescriptionText(description: departure) - activityTextView.text = model.publicCourse.description + self.currentDescription = model.publicCourse.description + setCurrentInfo() } // 키보드가 올라오면 scrollView 위치 조정 @@ -129,26 +146,28 @@ extension CourseEditVC { name: UIResponder.keyboardWillHideNotification, object: nil) } -} -// MARK: - @objc Function - -extension CourseEditVC { - @objc private func textFieldTextDidChange() { - guard let text = courseTitleTextField.text else { return } - - if text.count > courseTitleMaxLength { - let index = text.index(text.startIndex, offsetBy: courseTitleMaxLength) - let newString = text[text.startIndex.. courseTitleMaxLength { + let index = text.index(text.startIndex, offsetBy: courseTitleMaxLength) + let newString = text[text.startIndex.. 150 { - activityTextView.deleteBackward() + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.lineSpacing = 8 + + let attributedString = NSMutableAttributedString(string: textView.text) + attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, attributedString.length)) + + textView.attributedText = attributedString + textView.font = .b3 + textView.textColor = .g1 + + guard let courseTitleTextFieldText = self.courseTitleTextField.text else { return } + textDidChanged(courseTitleTextFieldText, text) + + if text.count > self.activityTextMaxLength { + self.activityTextView.deleteBackward() } } + func textViewDidEndEditing(_ textView: UITextView) { if textView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || textView.text == placeholder { activityTextView.textColor = .g3 @@ -337,7 +388,7 @@ extension CourseEditVC { case .success(let result): let status = result.statusCode if 200..<300 ~= status { - self.navigationController?.popViewController(animated: true) + showToast(message: "게시글 수정이 완료되었어요") } if status >= 400 { print("400 error") diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/MyCourseSelectVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/MyCourseSelectVC.swift index d397bd9e..127d8e9b 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/MyCourseSelectVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDiscovery/Views/VC/MyCourseSelectVC.swift @@ -29,10 +29,11 @@ class MyCourseSelectVC: UIViewController { // MARK: - UI Components private lazy var navibar = CustomNavigationBar(self, type: .titleWithLeftButton).setTitle("불러오기") - private let selectButton = CustomButton(title: "선택하기").setEnabled(false) - - // MARK: - collectionview + private lazy var selectButton = CustomButton(title: "선택하기").setEnabled(false).then { + $0.isHidden = true + } + private lazy var mapCollectionView: UICollectionView = { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .vertical @@ -45,6 +46,11 @@ class MyCourseSelectVC: UIViewController { return collectionView }() + private lazy var emptyView = ListEmptyView(description: "공유할 수 있는 코스가 없어요!\n코스를 그려주세요!", + buttonTitle: "코스 그리기").then { + $0.setImage(ImageLiterals.imgPaper, size: CGSize(width: 189, height: 169)) + } + // MARK: - Constants final let collectionViewInset = UIEdgeInsets(top: 28, left: 16, bottom: 28, right: 16) @@ -75,11 +81,14 @@ extension MyCourseSelectVC { private func setData(courseList: [Course]) { self.courseList = courseList mapCollectionView.reloadData() + self.emptyView.isHidden = !courseList.isEmpty + self.selectButton.isHidden = courseList.isEmpty } - + private func setDelegate() { mapCollectionView.delegate = self mapCollectionView.dataSource = self + emptyView.delegate = self } private func register() { @@ -117,11 +126,13 @@ extension MyCourseSelectVC { private func setUI() { view.backgroundColor = .w1 self.tabBarController?.tabBar.isHidden = true + self.emptyView.isHidden = true } private func setLayout() { view.addSubviews(selectButton, mapCollectionView) self.view.bringSubviewToFront(selectButton) + mapCollectionView.addSubview(emptyView) selectButton.snp.makeConstraints { make in make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(16) @@ -134,6 +145,11 @@ extension MyCourseSelectVC { make.leading.trailing.equalTo(view.safeAreaLayoutGuide) make.bottom.equalTo(selectButton.snp.top).inset(-25) } + + emptyView.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.centerY.equalTo(view.safeAreaLayoutGuide) + } } } // MARK: - UICollectionViewDelegate, UICollectionViewDataSource @@ -236,3 +252,11 @@ extension MyCourseSelectVC { } } } + +// MARK: - Section Heading + +extension MyCourseSelectVC: ListEmptyViewDelegate { + func emptyViewButtonTapped() { + self.tabBarController?.selectedIndex = 0 + } +} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift index 28bc7694..08256ebd 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseStorage/Views/CourseListView/PrivateCourseListView.swift @@ -169,7 +169,7 @@ extension PrivateCourseListView { make.trailing.equalToSuperview().inset(16) make.width.equalTo(47) make.height.equalTo(22) - make.top.equalToSuperview().offset(5) + make.top.equalToSuperview().offset(8) } courseListCollectionView.snp.makeConstraints { make in diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordDetailVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordDetailVC.swift index 07988475..33436594 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordDetailVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordDetailVC.swift @@ -140,7 +140,9 @@ extension ActivityRecordDetailVC { self?.deleteRecord() } - [ editAction, deleteAlertAction ].forEach { alertController.addAction($0) } + let cancelAction = UIAlertAction(title: "닫기", style: .cancel, handler: nil) + + [ editAction, deleteAlertAction, cancelAction ].forEach { alertController.addAction($0) } present(alertController, animated: true, completion: nil) } @@ -186,8 +188,7 @@ extension ActivityRecordDetailVC { } @objc private func finishEditButtonDidTap() { -// editRecordTitle() - showToast(message: "제목 수정이 완료되었어요") + editRecordTitle() // 수정이 완료되면 팝업 뜨지 않음 self.navibar.resetLeftButtonAction({ [weak self] in @@ -516,6 +517,7 @@ extension ActivityRecordDetailVC { let status = result.statusCode if 200..<300 ~= status { print("제목 수정 성공") + showToast(message: "제목 수정이 완료되었어요") } if status >= 400 { print("400 error") diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift index 5abaa988..12d8dd04 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/ActivityRecordInfoVC.swift @@ -227,7 +227,8 @@ extension ActivityRecordInfoVC { } emptyView.snp.makeConstraints { make in - make.center.equalToSuperview() + make.centerX.equalToSuperview() + make.centerY.equalTo(view.safeAreaLayoutGuide) make.leading.trailing.equalToSuperview().inset(80) } } diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift index d30d70a1..b713da69 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/InfoVC/UploadedCourseInfoVC.swift @@ -229,7 +229,8 @@ extension UploadedCourseInfoVC { make.leading.bottom.trailing.equalToSuperview() } emptyView.snp.makeConstraints { make in - make.center.equalToSuperview() + make.centerX.equalToSuperview() + make.centerY.equalTo(view.safeAreaLayoutGuide) make.leading.trailing.equalToSuperview().inset(80) } } diff --git a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/SettingVC/SettingVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/SettingVC/SettingVC.swift index f2771c06..77f959f0 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/SettingVC/SettingVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/MyPage/VC/SettingVC/SettingVC.swift @@ -26,7 +26,7 @@ final class SettingVC: UIViewController { let reportUrl = NSURL(string: "https://docs.google.com/forms/d/e/1FAIpQLSek2rkClKfGaz1zwTEHX3Oojbq_pbF3ifPYMYezBU0_pe-_Tg/viewform") lazy var reportSafariView: SFSafariViewController = SFSafariViewController(url: self.reportUrl! as URL) - let termsOfServiceUrl = NSURL(string: "https://www.notion.so/Runnect-81cf5a3a507b40e4b6104b5d08f12792?pvs=4") + let termsOfServiceUrl = NSURL(string: "https://third-sight-046.notion.site/Runnect-5dfee19ccff04c388590e5ee335e77ed") lazy var termsOfServiceSafariView: SFSafariViewController = SFSafariViewController(url: self.termsOfServiceUrl! as URL) private lazy var personalInfoView = makeInfoView(title: "계정 정보").then {