-
Notifications
You must be signed in to change notification settings - Fork 15
계산기 [Step3] is, june #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
vanism2091
wants to merge
38
commits into
tasty-code:1_is
Choose a base branch
from
vanism2091:Step3
base: 1_is
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
bd2ae01
feat: 1-9 버튼 ViewController와 연결 - IBAction 생성
vanism2091 29ce91e
feat: 사칙연산 버튼 ViewController와 연결 - IBAction 생성
zhunhe c10cf31
feat: equals, clear 버튼 ViewController와 연결
vanism2091 a8c4cc1
feat: "0", "00", "." 버튼 ViewController와 연결
zhunhe 0ce2192
feat: operator label, number label 연결 및 operator label touch 시 label 설정
vanism2091 1cd76be
feat: "1" ~ "9" 버튼 동작 구현
zhunhe 936562b
feat: ⁺⁄₋ 버튼 동작 구현
zhunhe 5bcdcc9
feat: initializeCurrentDisplay 구현 및 CE 구현
vanism2091 80df8ab
feat: "0", "00", "." 버튼 구현
zhunhe 014a591
feat: stackView dynamic append 구현
vanism2091 ca80f68
refactor: ViewController 이름 변경
zhunhe 471ed40
feat: UIScroll - scroll to bottom 구현
vanism2091 19e91ae
refactor: UILabel 변수 명 변경, 매직 넘버 삭제, isNumberTyped 삭제
vanism2091 63b8f52
fix: 소수점 관련 제대로 토글되지 않는 문제 수정
vanism2091 446cb53
refactor: 계산기 버튼 관련 매직스트링 사용하지 않도록 수정
vanism2091 4135218
refactor: computed property - isEntryNumberZeroOnly 추가
vanism2091 652a5e6
feat: AC, CE 구현중
vanism2091 fa8010a
feat: HistoryStackView, HistoryLabel - CustomView 구현
vanism2091 5f373c7
feat: result 제외 equal 구현
vanism2091 7c1e761
feat: equalsDidTap, calcuationResult 구현, Formula resul의 반환 값 변경
vanism2091 cd8c457
fix: digitDidTap - 연산 결과 표시 후 숫자를 누르면 새로운 숫자가 눌리게 수정
vanism2091 472df48
chore: 사용하지 않는 메서드 buildDisplayLabel 삭제
vanism2091 b5ee9af
feat: clearAll History stack 지우기 구현
vanism2091 512b26c
style: UIScrollView+Extension.swift indent 수정
vanism2091 7c9fb3d
feat: 사용자가 숫자를 입력중인지 아닌지를 확인할 수 있는 변수 isNumberInTyping 구현, displayNum…
vanism2091 bc1b781
refactor: Formula-result 내 변수명 변경
vanism2091 dca6236
refactor: zeroOrPointDidTap 메서드 리팩토링
vanism2091 d63b674
refactor: 접근 제어 private 적용
vanism2091 7b045b0
feat: NumberFormatter 추가
vanism2091 1e5632f
style: 공백 없애기 등
vanism2091 293f4f1
fix: Not a number 일 오류 때 수정
vanism2091 405b0f3
refactor: hasDisplayNumberDecimalPlaces, viewDidLoad 삭제
vanism2091 c60a383
refactor: ScrollView 내 StackView에 사용하지 않는 element 삭제
vanism2091 f144b84
refactor: computed property의 get, set 에 개행 삽입
vanism2091 630afc2
refactor: IBAction method 이름에 UIView Component (Button) 삽입
vanism2091 207c278
refactor: { return } 을 모두 개행 처리
vanism2091 a55e550
refactor: view controller와 연결된 method renaming 반영
vanism2091 20588fb
refactor: 1. View와 controller의 분리 2. 변수 naming 3. string literal 제거
vanism2091 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
199 changes: 199 additions & 0 deletions
199
Calculator/Calculator/Controller/CalculatorViewController.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,199 @@ | ||
| // | ||
| // Calculator - ViewController.swift | ||
| // Created by yagom. | ||
| // Copyright © yagom. All rights reserved. | ||
| // | ||
|
|
||
| import UIKit | ||
|
|
||
| final class CalculatorViewController: UIViewController { | ||
|
|
||
| private enum Constant { | ||
| static let zero = "0" | ||
| static let doubleZero = "00" | ||
| static let dot = "." | ||
| static let allClear = "AC" | ||
| static let clearEntry = "CE" | ||
| static let NotANumber = "NaN" | ||
| static let emptyString = "" | ||
| static let comma = "," | ||
| static let nine = "9" | ||
| } | ||
|
|
||
| @IBOutlet private weak var operatorLabel: UILabel! | ||
| @IBOutlet private weak var entryNumberLabel: UILabel! | ||
| @IBOutlet private weak var calculationHistoryScrollView: UIScrollView! | ||
| @IBOutlet private weak var calculationHistoryContentView: UIStackView! | ||
|
|
||
| private let numberFormatter: NumberFormatter = { | ||
| let formatter = NumberFormatter() | ||
| formatter.numberStyle = .decimal | ||
| formatter.minimumFractionDigits = 0 | ||
| formatter.maximumFractionDigits = 20 | ||
| return formatter | ||
| }() | ||
|
|
||
| private let maxDigitLength = 15 | ||
| private var isDisplayNumberZeroOnly: Bool { | ||
| displayNumber == Constant.zero | ||
| } | ||
| private var formulaString = Constant.emptyString | ||
| private var isTypingNumber = false | ||
| private var displayNumber: String = Constant.zero { | ||
| willSet { | ||
| guard let lastElement = newValue.last else { | ||
| return | ||
| } | ||
| let lastCharacter = String(lastElement) | ||
| switch lastCharacter { | ||
| case Constant.dot: | ||
| entryNumberLabel.text?.append(lastCharacter) | ||
| case Constant.zero...Constant.nine: | ||
| entryNumberLabel.text = parse(newValue) | ||
| default: | ||
| entryNumberLabel.text = newValue | ||
| } | ||
| } | ||
| } | ||
| private var displayOperator: String = Constant.emptyString { | ||
| willSet { | ||
| operatorLabel.text = newValue | ||
| } | ||
| } | ||
|
|
||
| @IBAction private func digitButtonDidTap(_ sender: UIButton) { | ||
| guard let digit = sender.currentTitle, displayNumber.count < maxDigitLength else { | ||
| return | ||
| } | ||
| if isTypingNumber { | ||
| displayNumber += digit | ||
| } else { | ||
| displayNumber = digit | ||
| isTypingNumber = true | ||
| } | ||
| } | ||
|
|
||
| @IBAction private func arithmeticOperatorButtonDidTap(_ sender: UIButton) { | ||
| if displayNumber == Constant.NotANumber { | ||
| displayNumber = Constant.zero | ||
| } | ||
| guard let buttonTitle = sender.currentTitle else { | ||
| return | ||
| } | ||
| if isTypingNumber || false == isDisplayNumberZeroOnly { | ||
| addCalculationHistory() | ||
| } | ||
| displayOperator = buttonTitle | ||
| clearEntry() | ||
| } | ||
|
|
||
| @IBAction private func equalsButtonDidTap(_ sender: UIButton) { | ||
| guard false == displayOperator.isEmpty else { | ||
| return | ||
| } | ||
| print(formulaString) | ||
| addCalculationHistory() | ||
| let result = calculationResult(from: formulaString) | ||
| print(formulaString, result, displayNumber) | ||
| displayNumber = result | ||
| clearOperatorAndFormulaString() | ||
| isTypingNumber = false | ||
| } | ||
|
|
||
| @IBAction private func clearButtonDidTap(_ sender: UIButton) { | ||
| switch sender.currentTitle { | ||
| case Constant.clearEntry: | ||
| clearEntry() | ||
| case Constant.allClear: | ||
| clearAll() | ||
| default: | ||
| return | ||
| } | ||
| } | ||
|
|
||
| @IBAction private func signToggleButtonDidTap(_ sender: UIButton) { | ||
| guard nil != sender.currentTitle, | ||
| false == isDisplayNumberZeroOnly, | ||
| let number = Double(displayNumber) else { | ||
| return | ||
| } | ||
| displayNumber = String(number * -1) | ||
| } | ||
|
|
||
| @IBAction private func zeroOrPointButtonDidTap(_ sender: UIButton) { | ||
| guard let buttonTitle = sender.currentTitle, | ||
| displayNumber.count < maxDigitLength else { | ||
| return | ||
| } | ||
|
|
||
| switch buttonTitle { | ||
| case Constant.zero, Constant.doubleZero: | ||
| if isDisplayNumberZeroOnly { | ||
| return | ||
| } | ||
| let suffix = (displayNumber + buttonTitle).count > maxDigitLength ? Constant.zero : buttonTitle | ||
| displayNumber += suffix | ||
| case Constant.dot: | ||
| if displayNumber.contains(Constant.dot) { | ||
| return | ||
| } | ||
| displayNumber += buttonTitle | ||
| isTypingNumber = true | ||
| default: | ||
| return | ||
| } | ||
| } | ||
| } | ||
|
|
||
| extension CalculatorViewController { | ||
| // MARK: CalculationResult | ||
| private func calculationResult(from formula: String) -> String { | ||
| let result = ExpressionParser.parse(from: formula).result() | ||
| switch result { | ||
| case .success(let res): | ||
| return String(res) | ||
| case .failure(let error): | ||
| return error.description | ||
| } | ||
| } | ||
|
|
||
| // MARK: Parse - numberFormat | ||
| private func parse(_ value: String) -> String { | ||
| let removedComma = value.replacingOccurrences(of: Constant.comma, with: Constant.emptyString) | ||
| let nsNumber = numberFormatter.number(from: removedComma) | ||
| return (numberFormatter.string(for: nsNumber) ?? Constant.zero) | ||
| } | ||
|
|
||
| // MARK: Add History | ||
| private func addCalculationHistory() { | ||
| let currOperator = formulaString.isEmpty ? Constant.emptyString : displayOperator | ||
| appendHistoryStackView(operator: currOperator) | ||
| formulaString += "\(currOperator)\(displayNumber)" | ||
| } | ||
|
|
||
| private func appendHistoryStackView(operator: String?) { | ||
| let parsedNumber = parse(displayNumber) | ||
| let stackView = HistoryStackView(operator: `operator`, operand: parsedNumber) | ||
| calculationHistoryContentView.addArrangedSubview(stackView) | ||
|
|
||
| view.layoutIfNeeded() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. layoutIfNeeded는 왜 호출했나요? 꼭 필요한 코드인가요? |
||
| calculationHistoryScrollView.scrollToBottom() | ||
| } | ||
|
|
||
| // MARK: Clear | ||
| private func clearEntry() { | ||
| displayNumber = Constant.zero | ||
| isTypingNumber = false | ||
| } | ||
|
|
||
| private func clearOperatorAndFormulaString() { | ||
| displayOperator = Constant.emptyString | ||
| formulaString = Constant.emptyString | ||
| } | ||
|
|
||
| private func clearAll() { | ||
| clearEntry() | ||
| clearOperatorAndFormulaString() | ||
| calculationHistoryContentView.removeAllHistorySubviews() | ||
| } | ||
| } | ||
This file was deleted.
Oops, something went wrong.
15 changes: 15 additions & 0 deletions
15
Calculator/Calculator/Extensions/UIScrollView+Extension.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| // | ||
| // UIScrollView+Extension.swift | ||
| // Calculator | ||
| // | ||
| // Created by sei_dev on 1/25/23. | ||
| // | ||
|
|
||
| import UIKit | ||
|
|
||
| extension UIScrollView { | ||
| func scrollToBottom() { | ||
| let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height + contentInset.bottom) | ||
| setContentOffset(bottomOffset, animated: true) | ||
| } | ||
| } |
16 changes: 16 additions & 0 deletions
16
Calculator/Calculator/Extensions/UIStackView+Extension.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| // | ||
| // UIStackView+Extension.swift | ||
| // Calculator | ||
| // | ||
| // Created by sei_dev on 1/25/23. | ||
| // | ||
|
|
||
| import UIKit | ||
|
|
||
| extension UIStackView { | ||
| func removeAllHistorySubviews() { | ||
| arrangedSubviews.forEach { history in | ||
| history.removeFromSuperview() | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
상수를 enum으로 정리한 부분 좋습니다 👍