Skip to content

Commit

Permalink
Merge pull request #283 from boostcampwm2023/iOS/feat#273
Browse files Browse the repository at this point in the history
feat: 업로드 태그 개수 제한, 필드 글자수 제한
  • Loading branch information
anyukyung authored Dec 11, 2023
2 parents df52f8e + 46a2cd0 commit 55168bf
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 14 deletions.
8 changes: 8 additions & 0 deletions iOS/Layover/Layover/DesignSystem/LOTagStackView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
//

import UIKit

protocol LOTagStackViewDelegate: AnyObject {
func tagStackViewDidDeletedTag(_ stackView: LOTagStackView, sender: UIButton)
}

final class LOTagStackView: UIStackView {

// MARK: - TagStackView Style
Expand All @@ -25,6 +30,8 @@ final class LOTagStackView: UIStackView {

private let style: Style

weak var delegate: LOTagStackViewDelegate?

// MARK: - Initializer

init(style: Style) {
Expand Down Expand Up @@ -97,5 +104,6 @@ final class LOTagStackView: UIStackView {
guard let button = sender.superview else { return }
removeArrangedSubview(button)
button.removeFromSuperview()
delegate?.tagStackViewDidDeletedTag(self, sender: sender)
}
}
29 changes: 29 additions & 0 deletions iOS/Layover/Layover/DesignSystem/LOTextField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ import UIKit

final class LOTextField: UITextField {

private let textCountLabel: UILabel = {
let label: UILabel = UILabel()
label.font = .loFont(type: .caption)
label.textColor = .grey500
return label
}()

override var placeholder: String? {
didSet {
setPlaceholderColor()
Expand All @@ -18,12 +25,16 @@ final class LOTextField: UITextField {
init() {
super.init(frame: .zero)
setUI()
setConstraints()
addTarget()
delegate = self
}

required init?(coder: NSCoder) {
super.init(coder: coder)
setUI()
setConstraints()
addTarget()
delegate = self
}

Expand All @@ -34,6 +45,20 @@ final class LOTextField: UITextField {
backgroundColor = UIColor.clear
setPadding()
}

private func setConstraints() {
addSubview(textCountLabel)
textCountLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
textCountLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
textCountLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10)
])
}

private func addTarget() {
self.addTarget(self, action: #selector(textDidChange), for: .editingChanged)
}

private func setPlaceholderColor() {
guard let placeholder else { return }
attributedPlaceholder = NSAttributedString(string: placeholder, attributes: [.foregroundColor: UIColor.grey500])
Expand All @@ -53,6 +78,10 @@ final class LOTextField: UITextField {
textColor = color
}

@objc private func textDidChange() {
textCountLabel.text = "\(text?.count ?? 0)"
}

}

extension LOTextField: UITextFieldDelegate {
Expand Down
16 changes: 14 additions & 2 deletions iOS/Layover/Layover/Scenes/EditTag/EditTagInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import UIKit

protocol EditTagBusinessLogic {
func fetchTags()
func editTag(request: EditTagModels.EditTag.Request)
func editTags(request: EditTagModels.EditTags.Request)
func addTag(request: EditTagModels.AddTag.Request)
}

protocol EditTagDataStore {
Expand All @@ -32,8 +33,19 @@ final class EditTagInteractor: EditTagBusinessLogic, EditTagDataStore {
presenter?.presentTags(with: EditTagModels.FetchTags.Response(tags: tags))
}

func editTag(request: EditTagModels.EditTag.Request) {
func editTags(request: EditTagModels.EditTags.Request) {
tags = request.editedTags
guard let tags else { return }
presenter?.presentEditedTags(with: EditTagModels.EditTags.Response(editedTags: tags))
}

func addTag(request: EditTagModels.AddTag.Request) {
if request.tags.count >= Models.maxTagCount { return }
tags = request.tags
tags?.append(request.newTag)
let response = Models.AddTag.Response(tags: tags ?? [],
addedTag: request.newTag)
presenter?.presentAddedTag(with: response)
}

}
27 changes: 26 additions & 1 deletion iOS/Layover/Layover/Scenes/EditTag/EditTagModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import UIKit

enum EditTagModels {

static let maxTagCount: Int = 3
static let maxTagLength: Int = 5

enum FetchTags {
struct Request {

Expand All @@ -19,12 +22,34 @@ enum EditTagModels {
}
struct ViewModel {
let tags: [String]
var tagCountDescription: String
}
}

enum EditTag {
enum AddTag {
struct Request {
let tags: [String]
let newTag: String
}
struct Response {
let tags: [String]
let addedTag: String?
}
struct ViewModel {
let addedTag: String?
let tagCountDescription: String
}
}

enum EditTags {
struct Request {
let editedTags: [String]
}
struct Response {
let editedTags: [String]
}
struct ViewModel {
let tagCountDescription: String
}
}

Expand Down
17 changes: 16 additions & 1 deletion iOS/Layover/Layover/Scenes/EditTag/EditTagPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import UIKit

protocol EditTagPresentationLogic {
func presentTags(with response: EditTagModels.FetchTags.Response)
func presentEditedTags(with response: EditTagModels.EditTags.Response)
func presentAddedTag(with response: EditTagModels.AddTag.Response)
}

final class EditTagPresenter: EditTagPresentationLogic {
Expand All @@ -20,7 +22,20 @@ final class EditTagPresenter: EditTagPresentationLogic {
weak var viewController: EditTagDisplayLogic?

func presentTags(with response: EditTagModels.FetchTags.Response) {
viewController?.displayTags(viewModel: EditTagModels.FetchTags.ViewModel(tags: response.tags))
let viewModel = Models.FetchTags.ViewModel(tags: response.tags,
tagCountDescription: "\(response.tags.count)/\(Models.maxTagCount)")
viewController?.displayTags(viewModel: viewModel)
}

func presentEditedTags(with response: EditTagModels.EditTags.Response) {
let viewModel = EditTagModels.EditTags.ViewModel(tagCountDescription: "\(response.editedTags.count)/\(Models.maxTagCount)")
viewController?.displayEditedTags(viewModel: viewModel)
}

func presentAddedTag(with response: EditTagModels.AddTag.Response) {
let viewModel = Models.AddTag.ViewModel(addedTag: response.addedTag,
tagCountDescription: "\(response.tags.count)/\(Models.maxTagCount)")
viewController?.displayAddedTag(viewModel: viewModel)
}

}
9 changes: 6 additions & 3 deletions iOS/Layover/Layover/Scenes/EditTag/EditTagRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@ final class EditTagRouter: NSObject, EditTagRoutingLogic, EditTagDataPassing {
let tabbarViewController = presentingViewController.viewControllers.last as? UITabBarController,
let selectedViewcontroller = tabbarViewController.selectedViewController as? UINavigationController,
let previousViewController = selectedViewcontroller.viewControllers.last as? UploadPostViewController,
var destination = previousViewController.router?.dataStore
let dataStore, var destination = previousViewController.router?.dataStore
else { return }

destination.tags = dataStore?.tags
passDataToBack(source: dataStore, destination: &destination)
viewController?.dismiss(animated: true)
}

private func passDataToBack(source: EditTagDataStore, destination: inout UploadPostDataStore) {
destination.tags = source.tags
}

}
57 changes: 52 additions & 5 deletions iOS/Layover/Layover/Scenes/EditTag/EditTagViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import UIKit

protocol EditTagDisplayLogic: AnyObject {
func displayTags(viewModel: EditTagModels.FetchTags.ViewModel)
func displayEditedTags(viewModel: EditTagModels.EditTags.ViewModel)
func displayAddedTag(viewModel: EditTagModels.AddTag.ViewModel)
}

final class EditTagViewController: BaseViewController {
Expand All @@ -29,6 +31,13 @@ final class EditTagViewController: BaseViewController {
return textField
}()

private let tagCountLabel: UILabel = {
let label: UILabel = UILabel()
label.font = .loFont(type: .caption)
label.textColor = .grey400
return label
}()

private let tagStackView: LOTagStackView = {
let stackView: LOTagStackView = LOTagStackView(style: .edit)
return stackView
Expand Down Expand Up @@ -63,12 +72,12 @@ final class EditTagViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
interactor?.fetchTags()
tagTextField.delegate = self
setDelegation()
}

override func setConstraints() {
super.setConstraints()
view.addSubviews(closeButton, tagTextField, tagStackView)
view.addSubviews(closeButton, tagTextField, tagCountLabel, tagStackView)
view.subviews.forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
}
Expand All @@ -82,6 +91,9 @@ final class EditTagViewController: BaseViewController {
tagTextField.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
tagTextField.heightAnchor.constraint(equalToConstant: 44),

tagCountLabel.centerYAnchor.constraint(equalTo: tagTextField.centerYAnchor),
tagCountLabel.trailingAnchor.constraint(equalTo: tagTextField.trailingAnchor, constant: -10),

tagStackView.topAnchor.constraint(equalTo: tagTextField.bottomAnchor, constant: 14),
tagStackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
tagStackView.heightAnchor.constraint(equalToConstant: 25)
Expand All @@ -90,9 +102,12 @@ final class EditTagViewController: BaseViewController {

// MARK: - Methods

private func setDelegation() {
tagTextField.delegate = self
tagStackView.delegate = self
}

@objc private func closeButtonDidTap() {
let request = EditTagModels.EditTag.Request(tags: tagStackView.tags)
interactor?.editTag(request: request)
router?.routeToBack()
}

Expand All @@ -103,17 +118,49 @@ final class EditTagViewController: BaseViewController {
extension EditTagViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
guard let tagText = textField.text else { return true }
tagStackView.addTag(tagText)
textField.text = nil
let request = Models.AddTag.Request(tags: tagStackView.tags, newTag: tagText)
interactor?.addTag(request: request)
return true
}

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let text = textField.text else { return true }
if let char = string.cString(using: String.Encoding.utf8) {
let isBackSpace = strcmp(char, "\\b")
if isBackSpace == -92 { return true }
}
guard text.count < Models.maxTagLength else { return false }
return true
}
}

extension EditTagViewController: LOTagStackViewDelegate {

func tagStackViewDidDeletedTag(_ stackView: LOTagStackView, sender: UIButton) {
let request = EditTagModels.EditTags.Request(editedTags: stackView.tags)
interactor?.editTags(request: request)
}

}

extension EditTagViewController: EditTagDisplayLogic {

func displayTags(viewModel: EditTagModels.FetchTags.ViewModel) {
tagStackView.resetTagStackView()
viewModel.tags.forEach { tagStackView.addTag($0) }
tagCountLabel.text = viewModel.tagCountDescription
}

func displayEditedTags(viewModel: EditTagModels.EditTags.ViewModel) {
tagCountLabel.text = viewModel.tagCountDescription
}

func displayAddedTag(viewModel: EditTagModels.AddTag.ViewModel) {
if let tag = viewModel.addedTag {
tagStackView.addTag(tag)
}
tagCountLabel.text = viewModel.tagCountDescription
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import OSLog

protocol UploadPostBusinessLogic {
func fetchTags()
func editTags(with request: UploadPostModels.EditTags.Request)

@discardableResult
func fetchThumbnailImage() -> Task<Bool, Never>
Expand Down Expand Up @@ -64,6 +65,10 @@ final class UploadPostInteractor: NSObject, UploadPostBusinessLogic, UploadPostD
presenter?.presentTags(with: Models.FetchTags.Response(tags: tags))
}

func editTags(with request: UploadPostModels.EditTags.Request) {
tags = request.tags
}

@discardableResult
func fetchThumbnailImage() -> Task<Bool, Never> {
Task {
Expand Down
9 changes: 9 additions & 0 deletions iOS/Layover/Layover/Scenes/UploadPost/UploadPostModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import UIKit

enum UploadPostModels {

static let titleMaxLength: Int = 15
static let contentMaxLength: Int = 50

enum CanUploadPost {
struct Request {
let title: String?
Expand All @@ -35,6 +38,12 @@ enum UploadPostModels {
}
}

enum EditTags {
struct Request {
let tags: [String]
}
}

enum FetchThumbnail {
struct Request {

Expand Down
Loading

0 comments on commit 55168bf

Please sign in to comment.