diff --git a/JuiceMaker/JuiceMaker.xcodeproj/project.pbxproj b/JuiceMaker/JuiceMaker.xcodeproj/project.pbxproj index e31ef2356..0ec1208df 100644 --- a/JuiceMaker/JuiceMaker.xcodeproj/project.pbxproj +++ b/JuiceMaker/JuiceMaker.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 6B5FDE8C272A761200C04135 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5FDE8B272A761200C04135 /* Message.swift */; }; 6B5FDEAE272ADC7100C04135 /* Text.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5FDEAD272ADC7100C04135 /* Text.swift */; }; + 6B7A79452734F914008D7D10 /* UIButton+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B7A79442734F914008D7D10 /* UIButton+Ext.swift */; }; 6BEB79292726956400FF66D4 /* FruitStoreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BEB79282726956400FF66D4 /* FruitStoreViewController.swift */; }; 9A757554271D599A00108EB8 /* RequestError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A757553271D599A00108EB8 /* RequestError.swift */; }; C71CD66B266C7ACB0038B9CB /* FruitStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = C71CD66A266C7ACB0038B9CB /* FruitStore.swift */; }; @@ -26,6 +27,7 @@ 6B5FDEAD272ADC7100C04135 /* Text.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Text.swift; sourceTree = ""; }; 6B5FDEAF272ADD5E00C04135 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Main.strings; sourceTree = ""; }; 6B5FDEB0272ADD5E00C04135 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/LaunchScreen.strings; sourceTree = ""; }; + 6B7A79442734F914008D7D10 /* UIButton+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+Ext.swift"; sourceTree = ""; }; 6BEB79282726956400FF66D4 /* FruitStoreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FruitStoreViewController.swift; sourceTree = ""; }; 9A757553271D599A00108EB8 /* RequestError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestError.swift; sourceTree = ""; }; C71CD66A266C7ACB0038B9CB /* FruitStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FruitStore.swift; sourceTree = ""; }; @@ -51,6 +53,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 6B7A79432734F8F5008D7D10 /* Extension */ = { + isa = PBXGroup; + children = ( + 6B7A79442734F914008D7D10 /* UIButton+Ext.swift */, + ); + path = Extension; + sourceTree = ""; + }; C71CD66D266C7B470038B9CB /* Controller */ = { isa = PBXGroup; children = ( @@ -103,6 +113,7 @@ C73DAF35255D0CDD00020D38 /* JuiceMaker */ = { isa = PBXGroup; children = ( + 6B7A79432734F8F5008D7D10 /* Extension */, C71CD66D266C7B470038B9CB /* Controller */, C71CD66F266C7B500038B9CB /* Model */, C71CD671266C7B570038B9CB /* View */, @@ -187,6 +198,7 @@ 6B5FDE8C272A761200C04135 /* Message.swift in Sources */, 9A757554271D599A00108EB8 /* RequestError.swift in Sources */, 6B5FDEAE272ADC7100C04135 /* Text.swift in Sources */, + 6B7A79452734F914008D7D10 /* UIButton+Ext.swift in Sources */, C73DAF37255D0CDD00020D38 /* AppDelegate.swift in Sources */, C73DAF39255D0CDD00020D38 /* SceneDelegate.swift in Sources */, C73DAF4C255D0D0400020D38 /* JuiceMaker.swift in Sources */, diff --git a/JuiceMaker/JuiceMaker/Controller/FruitStoreViewController.swift b/JuiceMaker/JuiceMaker/Controller/FruitStoreViewController.swift index 235a9c4bd..583535017 100644 --- a/JuiceMaker/JuiceMaker/Controller/FruitStoreViewController.swift +++ b/JuiceMaker/JuiceMaker/Controller/FruitStoreViewController.swift @@ -7,13 +7,189 @@ import UIKit +// MARK: - Properties and Lifecycle, Transition class FruitStoreViewController: UIViewController { - + var juiceMaker: JuiceMaker? + + @IBOutlet weak var strawberryStockLabel: UILabel! + @IBOutlet weak var bananaStockLabel: UILabel! + @IBOutlet weak var pineappleStockLabel: UILabel! + @IBOutlet weak var kiwiStockLabel: UILabel! + @IBOutlet weak var mangoStockLabel: UILabel! + + @IBOutlet weak var strawberryStockStepper: UIStepper! + @IBOutlet weak var bananaStockStepper: UIStepper! + @IBOutlet weak var pineappleStockStepper: UIStepper! + @IBOutlet weak var kiwiStockStepper: UIStepper! + @IBOutlet weak var mangoStockStepper: UIStepper! + override func viewDidLoad() { super.viewDidLoad() + updateFruitLabels() + updateFruitSteppers() + + NotificationCenter.default.addObserver(self, selector: #selector(fruitStockChanged(notification:)), name: .changedFruitStockNotification, object: nil) + print(NotificationCenter.default) + } + + deinit { + NotificationCenter.default.removeObserver(self) } @IBAction func cancelButtonTapped(_ sender: UIButton) { self.dismiss(animated: true, completion: nil) } } + +// MARK: - Label and Stepper Values Setting +extension FruitStoreViewController { + func updateFruitLabels() { + guard let fruitStore = juiceMaker?.fruitStore else { return } + do { + let strawberryStock = try fruitStore.stock(fruit: .strawberry) + let bananaStock = try fruitStore.stock(fruit: .banana) + let pineappleStock = try fruitStore.stock(fruit: .pineapple) + let kiwiStock = try fruitStore.stock(fruit: .kiwi) + let mangoStock = try fruitStore.stock(fruit: .mango) + + updateCurrentStockLabel(stock: strawberryStock, label: strawberryStockLabel) + updateCurrentStockLabel(stock: bananaStock, label: bananaStockLabel) + updateCurrentStockLabel(stock: pineappleStock, label: pineappleStockLabel) + updateCurrentStockLabel(stock: kiwiStock, label: kiwiStockLabel) + updateCurrentStockLabel(stock: mangoStock, label: mangoStockLabel) + } catch { + guard let requestError = error as? RequestError else { return } + showNotificationAlert(message: requestError.errorDescription) + } + } + + func updateFruitSteppers() { + guard let fruitStore = juiceMaker?.fruitStore else { return } + do { + let strawberryStock = try fruitStore.stock(fruit: .strawberry) + let bananaStock = try fruitStore.stock(fruit: .banana) + let pineappleStock = try fruitStore.stock(fruit: .pineapple) + let kiwiStock = try fruitStore.stock(fruit: .kiwi) + let mangoStock = try fruitStore.stock(fruit: .mango) + + updeteCurrentStockStepper(stock: strawberryStock, stepper: strawberryStockStepper) + updeteCurrentStockStepper(stock: bananaStock, stepper: bananaStockStepper) + updeteCurrentStockStepper(stock: pineappleStock, stepper: pineappleStockStepper) + updeteCurrentStockStepper(stock: kiwiStock, stepper: kiwiStockStepper) + updeteCurrentStockStepper(stock: mangoStock, stepper: mangoStockStepper) + } catch { + guard let requestError = error as? RequestError else { return } + showNotificationAlert(message: requestError.errorDescription) + } + } + + func updateCurrentStockLabel(stock: Int, label: UILabel) { + label.text = stock.description + } + + func updeteCurrentStockStepper(stock: Int, stepper: UIStepper) { + stepper.value = Double(stock) + } + + @IBAction func stepperTapped(_ sender: UIStepper) { + switch sender { + case strawberryStockStepper: + changeFruitStock(fruit: .strawberry, value: sender.value) + case bananaStockStepper: + changeFruitStock(fruit: .banana, value: sender.value) + case pineappleStockStepper: + changeFruitStock(fruit: .pineapple, value: sender.value) + case kiwiStockStepper: + changeFruitStock(fruit: .kiwi, value: sender.value) + case mangoStockStepper: + changeFruitStock(fruit: .mango, value: sender.value) + default: + showNotificationAlert(message: Message.unknownError.description) + } + } +} + +// MARK: Stepper Operation +extension FruitStoreViewController { + func changeFruitStock(fruit: Fruit, value: Double) { + let oldStockValue: Int + let newStockValue = Int(value) + guard let fruitStore = juiceMaker?.fruitStore else { return } + + do { + oldStockValue = try fruitStore.stock(fruit: fruit) + chooseCalculator(fruit: fruit, oldStockValue: oldStockValue, newStockValue: newStockValue) + } catch { + showNotificationAlert(message: Message.unknownError.description) + } + } + + func chooseCalculator(fruit: Fruit, oldStockValue: Int, newStockValue: Int) { + guard let fruitStore = juiceMaker?.fruitStore else { return } + + if oldStockValue < newStockValue { + let count = newStockValue - oldStockValue + calculateFruitStock(fruit: fruit, count: count, calculate: fruitStore.addFruitStock) + } else { + let count = oldStockValue - newStockValue + calculateFruitStock(fruit: fruit, count: count, calculate: fruitStore.subtractFruitStock) + } + } + + func calculateFruitStock(fruit: Fruit, count: Int, calculate: (Fruit, Int) throws -> Void ) { + do { + try calculate(fruit, count) + } catch { + showNotificationAlert(message: Message.unknownError.description) + } + } + + func showNotificationAlert(message: String, title: String = Text.ok.title) { + let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) + let cancel = UIAlertAction(title: title, style: .cancel, handler: nil) + alert.addAction(cancel) + present(alert, animated: true, completion: nil) + } +} + +// MARK: - Notification +extension FruitStoreViewController { + @objc func fruitStockChanged(notification: Notification) { + guard let fruitStock = notification.object as? FruitStock else { + showNotificationAlert(message: Message.unknownError.description) + return + } + updateCurrentStockLabel(stock: fruitStock.stock, label: fruitlabel(of: fruitStock.fruit)) + updeteCurrentStockStepper(stock: fruitStock.stock, stepper: fruitStepper(of: fruitStock.fruit)) + } + + func fruitlabel(of fruit: Fruit) -> UILabel { + switch fruit { + case .strawberry: + return strawberryStockLabel + case .banana: + return bananaStockLabel + case .pineapple: + return pineappleStockLabel + case .kiwi: + return kiwiStockLabel + case .mango: + return mangoStockLabel + } + } + + func fruitStepper(of fruit: Fruit) -> UIStepper { + switch fruit { + case .strawberry: + return strawberryStockStepper + case .banana: + return bananaStockStepper + case .pineapple: + return pineappleStockStepper + case .kiwi: + return kiwiStockStepper + case .mango: + return mangoStockStepper + } + } +} diff --git a/JuiceMaker/JuiceMaker/Controller/JuiceMakerViewController.swift b/JuiceMaker/JuiceMaker/Controller/JuiceMakerViewController.swift index cec65319b..8272df6f1 100644 --- a/JuiceMaker/JuiceMaker/Controller/JuiceMakerViewController.swift +++ b/JuiceMaker/JuiceMaker/Controller/JuiceMakerViewController.swift @@ -6,8 +6,8 @@ import UIKit +// MARK: - Properties and Lifecycle class JuiceMakerViewController: UIViewController { - private let juiceMaker = JuiceMaker() @IBOutlet weak var strawberryStockLabel: UILabel! @@ -27,10 +27,65 @@ class JuiceMakerViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() updateFruitLabels() - + setUpbuttonLabelFontAttributes() + NotificationCenter.default.addObserver(self, selector: #selector(fruitLabelChanged(notification:)), name: .changedFruitStockNotification, object: nil) } +} + +// MARK: - Setup Label and Button +extension JuiceMakerViewController { + func setUpbuttonLabelFontAttributes() { + orderStrawberryBananaJuiceButton.setUpTitleLabelFontAttributes() + orderMangoKiwiJuiceButton.setUpTitleLabelFontAttributes() + orderStrawberryJuiceButton.setUpTitleLabelFontAttributes() + orderBananaJuiceButton.setUpTitleLabelFontAttributes() + orderPineappleJuiceButton.setUpTitleLabelFontAttributes() + orderKiwiJuiceButton.setUpTitleLabelFontAttributes() + orderMangoJuiceButton.setUpTitleLabelFontAttributes() + } + func updateFruitLabels() { + do { + let strawberryStock = try juiceMaker.fruitStore.stock(fruit: .strawberry) + let bananaStock = try juiceMaker.fruitStore.stock(fruit: .banana) + let pineappleStock = try juiceMaker.fruitStore.stock(fruit: .pineapple) + let kiwiStock = try juiceMaker.fruitStore.stock(fruit: .kiwi) + let mangoStock = try juiceMaker.fruitStore.stock(fruit: .mango) + + updateCurrentStockLabel(stock: strawberryStock, label: strawberryStockLabel) + updateCurrentStockLabel(stock: bananaStock, label: bananaStockLabel) + updateCurrentStockLabel(stock: pineappleStock, label: pineappleStockLabel) + updateCurrentStockLabel(stock: kiwiStock, label: kiwiStockLabel) + updateCurrentStockLabel(stock: mangoStock, label: mangoStockLabel) + } catch { + guard let requestError = error as? RequestError else { return } + showNotificationAlert(message: requestError.errorDescription) + } + } + + func updateCurrentStockLabel(stock: Int, label: UILabel) { + label.text = stock.description + } + + func fruitlabel(of fruit: Fruit) -> UILabel { + switch fruit { + case .strawberry: + return strawberryStockLabel + case .banana: + return bananaStockLabel + case .pineapple: + return pineappleStockLabel + case .kiwi: + return kiwiStockLabel + case .mango: + return mangoStockLabel + } + } +} + +// MARK: - Order Juice +extension JuiceMakerViewController { @IBAction func orderJuiceButtonTapped(_ sender: UIButton) { let juice: Juice @@ -70,48 +125,6 @@ class JuiceMakerViewController: UIViewController { } } - @objc func fruitLabelChanged(notification: Notification) { - guard let fruit = notification.object as? Fruit else { - showNotificationAlert(message: Message.unknownError.description) - return - } - currentStockLabelUpdate(fruit: fruit, label: fruitlabel(of: fruit)) - } - - func updateFruitLabels() { - currentStockLabelUpdate(fruit: .strawberry, label: strawberryStockLabel) - currentStockLabelUpdate(fruit: .banana, label: bananaStockLabel) - currentStockLabelUpdate(fruit: .pineapple, label: pineappleStockLabel) - currentStockLabelUpdate(fruit: .kiwi, label: kiwiStockLabel) - currentStockLabelUpdate(fruit: .mango, label: mangoStockLabel) - } - - func currentStockLabelUpdate(fruit: Fruit, label: UILabel) { - do { - let stock = try FruitStore.shared.stock(fruit: fruit) - label.text = stock.description - } catch let error as RequestError { - showNotificationAlert(message: error.errorDescription) - } catch { - showNotificationAlert(message: Message.unknownError.description) - } - } - - func fruitlabel(of fruit: Fruit) -> UILabel { - switch fruit { - case .strawberry: - return strawberryStockLabel - case .banana: - return bananaStockLabel - case .pineapple: - return pineappleStockLabel - case .kiwi: - return kiwiStockLabel - case .mango: - return mangoStockLabel - } - } - func showNotificationAlert(message: String, title: String = Text.ok.title) { let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) let cancel = UIAlertAction(title: title, style: .cancel, handler: nil) @@ -127,10 +140,33 @@ class JuiceMakerViewController: UIViewController { alert.addAction(okAction) present(alert, animated: true, completion: nil) } - +} + +// MARK: - Transition +extension JuiceMakerViewController { private func presentFruitStoreViewController(_ action: UIAlertAction) { - guard let viewController = self.storyboard?.instantiateViewController(withIdentifier: "FruitStoreViewController") else { return } + guard let viewController = self.storyboard?.instantiateViewController(withIdentifier: "FruitStoreViewController") as? UINavigationController else { return } self.present(viewController, animated: true, completion: nil) + guard let nextViewController = viewController.topViewController as? FruitStoreViewController else { return } + nextViewController.juiceMaker = juiceMaker + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + guard let navigationController = segue.destination as? UINavigationController else { return } + guard let nextViewController = navigationController.topViewController as? FruitStoreViewController else { return } + nextViewController.juiceMaker = juiceMaker } + + } +// MARK: - Notification +extension JuiceMakerViewController { + @objc func fruitLabelChanged(notification: Notification) { + guard let fruitStock = notification.object as? FruitStock else { + showNotificationAlert(message: Message.unknownError.description) + return + } + updateCurrentStockLabel(stock: fruitStock.stock, label: fruitlabel(of: fruitStock.fruit)) + } +} diff --git a/JuiceMaker/JuiceMaker/Extension/UIButton+Ext.swift b/JuiceMaker/JuiceMaker/Extension/UIButton+Ext.swift new file mode 100644 index 000000000..f38b155af --- /dev/null +++ b/JuiceMaker/JuiceMaker/Extension/UIButton+Ext.swift @@ -0,0 +1,15 @@ +// +// UIButton+Ext.swift +// JuiceMaker +// +// Created by 김진태 on 2021/11/05. +// + +import UIKit + +extension UIButton { + func setUpTitleLabelFontAttributes() { + titleLabel?.adjustsFontForContentSizeCategory = true + titleLabel?.adjustsFontSizeToFitWidth = true + } +} diff --git a/JuiceMaker/JuiceMaker/Model/FruitStore.swift b/JuiceMaker/JuiceMaker/Model/FruitStore.swift index 3cefda0bd..bdf2be543 100644 --- a/JuiceMaker/JuiceMaker/Model/FruitStore.swift +++ b/JuiceMaker/JuiceMaker/Model/FruitStore.swift @@ -6,6 +6,7 @@ import Foundation +typealias FruitStock = (fruit: Fruit, stock: Int) enum Fruit: CaseIterable { case strawberry @@ -20,7 +21,6 @@ private enum Const { } class FruitStore { - static let shared: FruitStore = FruitStore() private var fruitBasket: [Fruit: Int] init(count: Int = Const.defaultFruitCount) { @@ -52,13 +52,15 @@ class FruitStore { guard let oldFruitCount = fruitBasket[fruit] else { throw RequestError.fruitNotFound } - guard count <= oldFruitCount else { + let newFruitCount = calculator(oldFruitCount, count) + guard newFruitCount >= 0 else { throw RequestError.fruitStockOut } - let newFruitCount = calculator(oldFruitCount, count) fruitBasket[fruit] = newFruitCount - NotificationCenter.default.post(name: .changedFruitStockNotification, object: fruit) + let fruitStock = (fruit: fruit, stock: newFruitCount) + + NotificationCenter.default.post(name: .changedFruitStockNotification, object: fruitStock) } func hasFruitStock(of fruit: Fruit, count fruitCountSubtracted: Int) -> Bool { diff --git a/JuiceMaker/JuiceMaker/Model/JuiceMaker.swift b/JuiceMaker/JuiceMaker/Model/JuiceMaker.swift index f156182a5..83f32617a 100644 --- a/JuiceMaker/JuiceMaker/Model/JuiceMaker.swift +++ b/JuiceMaker/JuiceMaker/Model/JuiceMaker.swift @@ -42,9 +42,9 @@ enum Juice: String { } struct JuiceMaker { - private let fruitStore: FruitStore + let fruitStore: FruitStore - init(fruitStore: FruitStore = FruitStore.shared) { + init(fruitStore: FruitStore = FruitStore()) { self.fruitStore = fruitStore } diff --git a/JuiceMaker/JuiceMaker/Model/Text.swift b/JuiceMaker/JuiceMaker/Model/Text.swift index ddd3788d6..e4730ca1d 100644 --- a/JuiceMaker/JuiceMaker/Model/Text.swift +++ b/JuiceMaker/JuiceMaker/Model/Text.swift @@ -12,21 +12,11 @@ enum Text { case ok var title: String { - return localizedTitle(key: self.key) - } - - private var key: String { switch self { case .cancel: - return "Cancel" + return "취소" case .ok: - return "OK" + return "확인" } } - - private func localizedTitle(key: String) -> String { - let bundle = Bundle.init(for: UIButton.self) - let title = bundle.localizedString(forKey: key, value: nil, table: nil) - return title - } } diff --git a/JuiceMaker/JuiceMaker/View/Base.lproj/Main.storyboard b/JuiceMaker/JuiceMaker/View/Base.lproj/Main.storyboard index ccbbba830..0fde192a8 100644 --- a/JuiceMaker/JuiceMaker/View/Base.lproj/Main.storyboard +++ b/JuiceMaker/JuiceMaker/View/Base.lproj/Main.storyboard @@ -1,6 +1,7 @@ - + + @@ -15,23 +16,23 @@ - + - + - + - - + - - + - - + - - + - - + - +