Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
583 changes: 583 additions & 0 deletions CalculatorProject/CalculatorProject.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
17 changes: 17 additions & 0 deletions CalculatorProject/CalculatorProject/CalculatorProjectApp.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// CalculatorProjectApp.swift
// CalculatorProject
//
// Created by JIN on 12/25/25.
//

import SwiftUI

@main
struct CalculatorProjectApp: App {
var body: some Scene {
WindowGroup {
CalculatorView()
}
}
}
24 changes: 24 additions & 0 deletions CalculatorProject/CalculatorProject/ContentView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// ContentView.swift
// CalculatorProject
//
// Created by JIN on 12/25/25.
//

import SwiftUI

struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.padding()
}
}

#Preview {
ContentView()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// AppDIContainer.swift
// CalculatorProject
//
// Created by JIN on 12/26/25.
//

import Foundation

final class AppDIContainer {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이걸 썻네

static let shared = AppDIContainer()

private init() {}

func makeCalculatorViewModel() -> CalculatorViewModel {
let calculator = Calculator()
return CalculatorViewModel(calculator: calculator)
}
}
29 changes: 29 additions & 0 deletions CalculatorProject/CalculatorProject/Models/Calculator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// Calculator.swift
// CalculatorProject
//
// Created by JIN on 12/25/25.
//

import SwiftUI

// MARK: - Protocol
protocol CalculatorProtocol {
func calculate(lhs: Double, rhs: Double, operation: Operation) -> Double
}

// MARK: - Implementation
final class Calculator: CalculatorProtocol {
func calculate(lhs: Double, rhs: Double, operation: Operation) -> Double {
switch operation {
case .add:
return lhs + rhs
case .subtract:
return lhs - rhs
case .multiply:
return lhs * rhs
case .divide:
return rhs != 0 ? lhs / rhs : 0
}
}
}
68 changes: 68 additions & 0 deletions CalculatorProject/CalculatorProject/Models/CalculatorButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//
// Button.swift
// CalculatorProject
//
// Created by JIN on 12/25/25.
//

import SwiftUI

enum CalculatorButton: Hashable {
case zero, one, two, three, four
case five, six, seven, eight, nine

case add
case subtract
case multiply
case divide

case equal
case clear

var title: String {
switch self {
case .zero: return "0"
case .one: return "1"
case .two: return "2"
case .three: return "3"
case .four: return "4"
case .five: return "5"
case .six: return "6"
case .seven: return "7"
case .eight: return "8"
case .nine: return "9"
case .add: return "+"
case .subtract: return "-"
case .multiply: return "×"
case .divide: return "÷"
case .equal: return "="
case .clear: return "AC"
}
}

var number: Int? {
switch self {
case .zero: return 0
case .one: return 1
case .two: return 2
case .three: return 3
case .four: return 4
case .five: return 5
case .six: return 6
case .seven: return 7
case .eight: return 8
case .nine: return 9
default: return nil
}
}

var operation: Operation? {
switch self {
case .add: return .add
case .subtract: return .subtract
case .multiply: return .multiply
case .divide: return .divide
default: return nil
}
}
}
22 changes: 22 additions & 0 deletions CalculatorProject/CalculatorProject/Models/CalculatorSate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// CalculatorSate.swift
// CalculatorProject
//
// Created by JIN on 12/25/25.
//

import SwiftUI

struct CalculatorState {
var currentValue: Double = 0
var storedValue: Double?
var currentOperation: Operation?
var isNewInput: Bool = true

mutating func reset() {
currentValue = 0
storedValue = nil
currentOperation = nil
isNewInput = true
}
}
24 changes: 24 additions & 0 deletions CalculatorProject/CalculatorProject/Models/Operation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// Operation.swift
// CalculatorProject
//
// Created by JIN on 12/25/25.
//

import SwiftUI

enum Operation {
case add
case subtract
case multiply
case divide

var symbol: String {
switch self {
case .add: return "+"
case .subtract: return "-"
case .multiply: return "×"
case .divide: return "÷"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//
// CalculatorViewModel.swift
// CalculatorProject
//
// Created by JIN on 12/26/25.
//

import Foundation
import Combine

final class CalculatorViewModel: ObservableObject {
@Published private(set) var state: CalculatorState
private let calculator: CalculatorProtocol

var displayValue: String {
formatNumber(state.currentValue)
}

init(calculator: CalculatorProtocol) {
self.calculator = calculator
self.state = CalculatorState()
}

func buttonPressed(_ button: CalculatorButton) {
switch button {
case .zero, .one, .two, .three, .four, .five, .six, .seven, .eight, .nine:
handleNumberInput(button)
case .add, .subtract, .multiply, .divide:
handleOperation(button)
case .equal:
handleEqual()
case .clear:
handleClear()
}
}

// MARK: - Private Methods

private func handleNumberInput(_ button: CalculatorButton) {
guard let number = button.number else { return }

if state.isNewInput {
state.currentValue = Double(number)
state.isNewInput = false
} else {
let currentString = String(Int(state.currentValue))
let newString = currentString + String(number)
state.currentValue = Double(newString) ?? state.currentValue
}
}

private func handleOperation(_ button: CalculatorButton) {
guard let operation = button.operation else { return }

if let storedValue = state.storedValue,
let currentOperation = state.currentOperation,
!state.isNewInput {
let result = calculator.calculate(
lhs: storedValue,
rhs: state.currentValue,
operation: currentOperation
)
state.currentValue = result
}
state.storedValue = state.currentValue
state.currentOperation = operation
state.isNewInput = true
}

private func handleEqual() {
guard let storedValue = state.storedValue,
let operation = state.currentOperation else {
return
}

let result = calculator.calculate(
lhs: storedValue,
rhs: state.currentValue,
operation: operation
)

state.currentValue = result
state.storedValue = nil
state.currentOperation = nil
state.isNewInput = true
}

private func handleClear() {
state.reset()
}

private func formatNumber(_ value: Double) -> String {
if value.truncatingRemainder(dividingBy: 1) == 0 {
return String(Int(value))
} else {
return String(value)
}
}
}
Loading