Skip to content

Commit

Permalink
[FEAT][#7] 출석코드입력란 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
tngusmiso committed Feb 11, 2023
1 parent 2ee20ab commit a430a9b
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 9 deletions.
8 changes: 8 additions & 0 deletions momoIOS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
3ABBF75129975EDA004D4D0B /* AdminSessionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ABBF74E29975ED9004D4D0B /* AdminSessionCell.swift */; };
3ABBF75229975EDA004D4D0B /* AdminSessionTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ABBF74F29975ED9004D4D0B /* AdminSessionTableViewController.swift */; };
3ABBF75329975EDA004D4D0B /* AddSessionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ABBF75029975ED9004D4D0B /* AddSessionViewController.swift */; };
3AE3323229976C2E0024C0C5 /* Collection+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE3323029976C2E0024C0C5 /* Collection+Extension.swift */; };
3AE3323329976C2E0024C0C5 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE3323129976C2E0024C0C5 /* String+Extension.swift */; };
BF0408632987B3AA00F1129B /* LoginController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0408622987B3AA00F1129B /* LoginController.swift */; };
BF04086B2987E34800F1129B /* AuthCommonConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF04086A2987E34800F1129B /* AuthCommonConstants.swift */; };
BF04086D2987E38C00F1129B /* RegistrationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF04086C2987E38C00F1129B /* RegistrationController.swift */; };
Expand Down Expand Up @@ -58,6 +60,8 @@
3ABBF74E29975ED9004D4D0B /* AdminSessionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdminSessionCell.swift; sourceTree = "<group>"; };
3ABBF74F29975ED9004D4D0B /* AdminSessionTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdminSessionTableViewController.swift; sourceTree = "<group>"; };
3ABBF75029975ED9004D4D0B /* AddSessionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddSessionViewController.swift; sourceTree = "<group>"; };
3AE3323029976C2E0024C0C5 /* Collection+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Collection+Extension.swift"; sourceTree = "<group>"; };
3AE3323129976C2E0024C0C5 /* String+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = "<group>"; };
BF0408622987B3AA00F1129B /* LoginController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginController.swift; sourceTree = "<group>"; };
BF04086A2987E34800F1129B /* AuthCommonConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthCommonConstants.swift; sourceTree = "<group>"; };
BF04086C2987E38C00F1129B /* RegistrationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -231,10 +235,12 @@
E8207930298A163400B36FC9 /* Extensions */ = {
isa = PBXGroup;
children = (
3AE3323029976C2E0024C0C5 /* Collection+Extension.swift */,
3A5AC30F29898B330080323A /* UIButton+Extension.swift */,
3AA713D0298946FF006F922F /* UIColor+Extension.swift */,
BFB8431E298CFF9200BA11EC /* UIStackView+Extension.swift */,
E8207931298A163400B36FC9 /* UIView+Extension.swift */,
3AE3323129976C2E0024C0C5 /* String+Extension.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -398,6 +404,7 @@
E8207932298A163400B36FC9 /* UIView+Extension.swift in Sources */,
BFB8431F298CFF9200BA11EC /* UIStackView+Extension.swift in Sources */,
3ABBF75129975EDA004D4D0B /* AdminSessionCell.swift in Sources */,
3AE3323229976C2E0024C0C5 /* Collection+Extension.swift in Sources */,
E820792D298A137700B36FC9 /* MainSessionTimeCell.swift in Sources */,
E820792B298A119900B36FC9 /* MainSessionDetailCell.swift in Sources */,
E8207936298A248200B36FC9 /* MainSessionNoInfoCell.swift in Sources */,
Expand All @@ -406,6 +413,7 @@
3AA713C929884007006F922F /* MainAttendanceDoneCell.swift in Sources */,
BF43B57A29952AFF0026DCE3 /* MoimSettingCell.swift in Sources */,
E820792F298A138500B36FC9 /* MainSessionAbsentCell.swift in Sources */,
3AE3323329976C2E0024C0C5 /* String+Extension.swift in Sources */,
BF4310FA298C525900270DBF /* AttendanceHistoryCell.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
14 changes: 14 additions & 0 deletions momoIOS/Common/Extensions/Collection+Extension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// Collection+Extension.swift
// momoIOS
//
// Created by 임수현 on 2023/02/11.
//

import Foundation

extension Collection {
subscript (safe index: Index) -> Element? {
return indices.contains(index) ? self[index] : nil
}
}
40 changes: 40 additions & 0 deletions momoIOS/Common/Extensions/String+Extension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// String+Extension.swift
// momoIOS
//
// Created by 임수현 on 2023/02/11.
//

import Foundation

extension String {
subscript (safe index: Int) -> String? {
guard self.count > index else { return nil }
let index = self.index(self.startIndex, offsetBy: index)
return "\(self[index])"
}

subscript (range: Range<Int>) -> String? {
let fromIndex = self.index(self.startIndex, offsetBy: max(0, range.lowerBound))
let toIndex = self.index(self.startIndex, offsetBy: min(range.upperBound, self.count))
return String(self[fromIndex..<toIndex])
}

subscript(_ range: Range<Int>) -> String {
let fromIndex = self.index(self.startIndex, offsetBy: range.startIndex)
let toIndex = self.index(self.startIndex, offsetBy: range.endIndex)
return String(self[fromIndex..<toIndex])
}

func replaced(_ string: String, in range: NSRange) -> String? {
guard let range = Range(range, in: self) else { return nil }
return self.replacingCharacters(in: range, with: string)
}

var isBackspace: Bool {
if let char = self.cString(using: String.Encoding.utf8) {
return strcmp(char, "\\b") == -92
}
return false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ class AttendanceCodeDetailViewController: UIViewController {
private func setupKeyboardNotifications() {
NotificationCenter.default.addObserver(
self,
selector: #selector(self.keyboardWillShow),
selector: #selector(keyboardWillShow(_:)),
name: UIResponder.keyboardWillShowNotification,
object: nil)

NotificationCenter.default.addObserver(
self,
selector: #selector(self.keyboardWillHide),
selector: #selector(keyboardWillHide(_:)),
name: UIResponder.keyboardWillHideNotification,
object: nil)
}
Expand Down Expand Up @@ -74,8 +74,7 @@ class AttendanceCodeDetailViewController: UIViewController {
textField.textColor = .white
textField.font = .systemFont(ofSize: 32, weight: .medium)
textField.keyboardType = .numberPad
// textField.delegate = self
// textField.dataSource = self
textField.delegate = self
}

self.descriptionLabel.text = "운영진이 공지해준 출석체크 코드를 입력해주세요!"
Expand Down Expand Up @@ -139,8 +138,51 @@ class AttendanceCodeDetailViewController: UIViewController {
make.height.equalTo(54)
}
}
}

// MARK: - UITextFieldDelegate
extension AttendanceCodeDetailViewController: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let currentText = textField.text ?? ""
let newText = range.lowerBound == 0 ? string : currentText.replaced(string, in: range) ?? ""

if newText.count == 0 {
textField.text = newText
self.prevTextField(textField)?.becomeFirstResponder()
} else {
self.fillTextField(textField, with: newText)
}
return false
}

// MARK: - TextField Values
private var isEditingCode: Bool {
for textField in self.codeTextFields where textField.isEditing == true {
return true
}
return false
}

private func textFieldIndex(of textField: UITextField) -> Int? {
for index in 0..<self.codeTextFields.count {
if textField == self.codeTextFields[index] {
return index
}
}
return nil
}

// MARK: - Actions
private func prevTextField(_ textField: UITextField) -> UITextField? {
guard let index = self.textFieldIndex(of: textField) else { return nil }
return self.codeTextFields[safe: index - 1]
}

private func nextTextField(_ textField: UITextField) -> UITextField? {
guard let index = self.textFieldIndex(of: textField) else { return nil }
return self.codeTextFields[safe: index + 1]
}

// MARK: - TextField Actions
@objc func keyboardWillShow(_ notification: NSNotification) {
if self.isEditingCode {
self.attendButton.moveWithKeyboard(
Expand All @@ -159,9 +201,31 @@ class AttendanceCodeDetailViewController: UIViewController {
)
}

// MARK: - Logics
private var isEditingCode: Bool {
let textFileds = self.codeTextFields
return textFileds[0].isEditing || textFileds[1].isEditing || textFileds[2].isEditing || textFileds[3].isEditing
private func fillTextField(_ textField: UITextField, with string: String) {
let string = string.trimmingCharacters(in: CharacterSet(charactersIn: "0123456789.").inverted)
guard !string.isEmpty else { return }
textField.text = string[safe: 0]

guard let nextTextField = self.nextTextField(textField) else { return }
nextTextField.becomeFirstResponder()
if nextTextField.text?.isEmpty == false {
self.setCursor(of: nextTextField, at: 0)
}
self.fillTextField(nextTextField, with: string[1..<string.count])
}

private func clearTextField(after textField: UITextField) {
guard let index = self.textFieldIndex(of: textField) else { return }
let nextIndex: Int = index + 1
let totalCount = self.codeTextFields.count

for index in nextIndex..<totalCount {
self.codeTextFields[safe: index]?.text = ""
}
}

private func setCursor(of textField: UITextField, at position: Int) {
let position = textField.position(from: textField.beginningOfDocument, offset: position)!
textField.selectedTextRange = textField.textRange(from: position, to: position)
}
}

0 comments on commit a430a9b

Please sign in to comment.