diff --git a/week2/2022-iOS-2week.xcodeproj/project.pbxproj b/week2/2022-iOS-2week.xcodeproj/project.pbxproj index 74c35d0..3cc1050 100644 --- a/week2/2022-iOS-2week.xcodeproj/project.pbxproj +++ b/week2/2022-iOS-2week.xcodeproj/project.pbxproj @@ -13,7 +13,7 @@ D4265FCA289C0EED007B9AD9 /* CardListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4265FC1289C0EED007B9AD9 /* CardListView.swift */; }; D4265FCB289C0EED007B9AD9 /* BottomButtonListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4265FC2289C0EED007B9AD9 /* BottomButtonListView.swift */; }; D4265FCD289C0EED007B9AD9 /* MainGameBoardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4265FC4289C0EED007B9AD9 /* MainGameBoardView.swift */; }; - D4AFE63A28A7A58600814689 /* ConstantEmojiContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4AFE63928A7A58600814689 /* ConstantEmojiContent.swift */; }; + D4AFE63A28A7A58600814689 /* Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4AFE63928A7A58600814689 /* Emoji.swift */; }; D4E4D29D289805D400432365 /* ChanggyoAssignment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4E4D29C289805D400432365 /* ChanggyoAssignment.swift */; }; D4E4D2A1289805D500432365 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D4E4D2A0289805D500432365 /* Assets.xcassets */; }; D4E4D2A4289805D500432365 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D4E4D2A3289805D500432365 /* Preview Assets.xcassets */; }; @@ -28,7 +28,7 @@ D4265FC1289C0EED007B9AD9 /* CardListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardListView.swift; sourceTree = ""; }; D4265FC2289C0EED007B9AD9 /* BottomButtonListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BottomButtonListView.swift; sourceTree = ""; }; D4265FC4289C0EED007B9AD9 /* MainGameBoardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainGameBoardView.swift; sourceTree = ""; }; - D4AFE63928A7A58600814689 /* ConstantEmojiContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConstantEmojiContent.swift; sourceTree = ""; }; + D4AFE63928A7A58600814689 /* Emoji.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Emoji.swift; sourceTree = ""; }; D4E4D299289805D400432365 /* 2022-iOS-2week.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "2022-iOS-2week.app"; sourceTree = BUILT_PRODUCTS_DIR; }; D4E4D29C289805D400432365 /* ChanggyoAssignment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChanggyoAssignment.swift; sourceTree = ""; }; D4E4D2A0289805D500432365 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -99,7 +99,7 @@ D4E4D2A0289805D500432365 /* Assets.xcassets */, D4E4D29C289805D400432365 /* ChanggyoAssignment.swift */, D4265FC4289C0EED007B9AD9 /* MainGameBoardView.swift */, - D4AFE63928A7A58600814689 /* ConstantEmojiContent.swift */, + D4AFE63928A7A58600814689 /* Emoji.swift */, D4265FCE289C1120007B9AD9 /* Model */, D4265FD0289C1136007B9AD9 /* Viewmodel */, D4265FBF289C0EED007B9AD9 /* View */, @@ -185,7 +185,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - D4AFE63A28A7A58600814689 /* ConstantEmojiContent.swift in Sources */, + D4AFE63A28A7A58600814689 /* Emoji.swift in Sources */, D4265FCD289C0EED007B9AD9 /* MainGameBoardView.swift in Sources */, D4265FCB289C0EED007B9AD9 /* BottomButtonListView.swift in Sources */, D4265FC5289C0EED007B9AD9 /* CardView.swift in Sources */, diff --git a/week2/2022-iOS-2week/ConstantEmojiContent.swift b/week2/2022-iOS-2week/Emoji.swift similarity index 100% rename from week2/2022-iOS-2week/ConstantEmojiContent.swift rename to week2/2022-iOS-2week/Emoji.swift diff --git a/week2/2022-iOS-2week/Model/ImojiGame.swift b/week2/2022-iOS-2week/Model/ImojiGame.swift new file mode 100644 index 0000000..465c113 --- /dev/null +++ b/week2/2022-iOS-2week/Model/ImojiGame.swift @@ -0,0 +1,134 @@ + +struct EmojiGame { + var leftCardSetCount: Int { cards.count - cards.filter {$0.state == .isMatched}.count } + + private(set) var cards: [Card] + private(set) var point: Int + + private var isFaceUpCard = false + + // MARK: mutating Func + mutating func changeGameTheme(cardEmojis: [String], displayCardCount: Int) { + let startIndex = Int.random(in: 1...1000) % cardEmojis.count + let endIndex = startIndex + displayCardCount + var newCards = [Card]() + + for i in startIndex ... endIndex { + let index = i % cardEmojis.count + newCards.append(Card(imoji: cardEmojis[index], id: index * 2 + 1)) + newCards.append(Card(imoji: cardEmojis[index], id: index * 2 )) + } + + point = 0 + cards = newCards.shuffled() + } + + mutating func changeStateCard(cardId: Int) { + guard let chosenIndex = cards.firstIndex(where: {cardId == $0.id}) else { return } + if cards[chosenIndex].state == .isMatched { return } + + if isFaceUpCard { + cards[chosenIndex].state.changeCardState() + calculatePoint() + isFaceUpCard = false + } + else { + for index in 0 ..< cards.count { + if cards[index].state != .isFaceDown { + cards[index].state.changeCardState() + } + } + isFaceUpCard = true + cards[chosenIndex].state.changeCardState() + } + } + + mutating private func calculatePoint() { + guard let firstCardIndex = cards.firstIndex(where: { $0.state == .isFaceUp }), + let secondCardIndex = cards.lastIndex(where: { $0.state == .isFaceUp }) else { return } + + if cards[firstCardIndex].imoji == cards[secondCardIndex].imoji { + point += 3 + if leftCardSetCount == 2 { + cards[firstCardIndex].state = .isMatched + cards[secondCardIndex].state = .isMatched + print(leftCardSetCount) + } + else { + cards[firstCardIndex].state = .waitForMatched + cards[secondCardIndex].state = .waitForMatched + } + } + else if !cards[firstCardIndex].didSelected && !cards[secondCardIndex].didSelected { + point += 0 + } + else if cards[firstCardIndex].didSelected && cards[secondCardIndex].didSelected { + point -= 2 + } + else { + point -= 1 + } + + cards[firstCardIndex].didSelected = true + cards[secondCardIndex].didSelected = true + } +} + +// MARK: - extension Nested Struct +extension EmojiGame { + struct Card: Identifiable, Hashable { + var didSelected = false + var state: CardState = .isFaceDown + var imoji: String + var id: Int + } + + enum CardState { + case isFaceUp + case isFaceDown + case isMatched + case waitForMatched + + mutating func changeCardState() { + switch self { + case .waitForMatched: + self = .isMatched + case .isFaceUp: + self = .isFaceDown + case .isFaceDown: + self = .isFaceUp + case .isMatched: + self = .isMatched + } + } + } +} + +extension EmojiGame { + struct ConstantContent { + static let face = ["๐Ÿ˜€","๐Ÿ˜","๐Ÿคช","๐Ÿค‘","๐Ÿ˜”","๐Ÿ˜ฐ","๐Ÿคฏ","๐Ÿค•","๐Ÿค","๐Ÿคฉ","๐Ÿคก","๐Ÿค ","๐Ÿ˜ถ","๐Ÿ‘ฟ","๐Ÿ˜ถโ€๐ŸŒซ๏ธ","๐Ÿฅถ"] + static let animal = ["๐Ÿถ","๐Ÿญ","๐Ÿป","๐Ÿฏ","๐Ÿจ","๐Ÿธ","๐Ÿฆง","๐ŸฆŠ","๐Ÿฆ","๐Ÿท","๐Ÿฆ","๐Ÿฆฅ","๐Ÿฆ’"] + static let sports = ["๐Ÿ‰","๐Ÿˆ","โšฝ","๐Ÿ€","โšพ","๐ŸฅŽ","๐ŸŽพ","๐Ÿ","๐ŸŽฑ","๐Ÿฅ","๐Ÿ“","๐Ÿฅ…","๐Ÿชƒ","๐Ÿ’","๐Ÿฅ","๐ŸฅŠ"] + static let heart = ["๐Ÿงก","๐Ÿ’”","๐Ÿ’™","๐Ÿ’œ","๐Ÿ’›","๐Ÿ’š","๐ŸคŽ","๐Ÿค","๐Ÿ–ค","โค๏ธโ€๐Ÿ”ฅ","๐Ÿ’","๐Ÿ’—"] + static let vehicle = ["๐Ÿš—","๐Ÿš‘","๐Ÿš™","๐Ÿš“","๐Ÿš’","๐Ÿš•","๐Ÿ›บ","๐Ÿš","๐ŸšŒ","๐Ÿ›ป","๐ŸšŽ","๐Ÿšš","๐ŸŽ","๐Ÿš›","๐Ÿ","๐Ÿ›ต","๐Ÿš"] + static let outfit = ["๐Ÿ‘š","๐Ÿฅผ","๐Ÿฆบ","๐Ÿงฅ","๐Ÿ‘™","๐Ÿฉฑ","๐Ÿ‘ž","๐Ÿฅฟ","๐Ÿฅพ","๐Ÿงข","๐Ÿ‘ก","๐Ÿ‘ ","๐Ÿงฆ","๐Ÿ‘˜","๐Ÿ‘—","๐Ÿงค","๐Ÿงฃ","๐Ÿ‘“"] + + static func emit(willChangeTheme theme: Theme.Kind) -> [String] { + switch theme { + case .face: + return face + case .animal: + return animal + case .sports: + return sports + case .vehicle: + return vehicle + case .heart: + return heart + case .outfit: + return outfit + } + } + } + +} diff --git a/week3/Calculator/Calculator.xcodeproj/project.pbxproj b/week3/Calculator/Calculator.xcodeproj/project.pbxproj index b8a22d1..efbd0f6 100644 --- a/week3/Calculator/Calculator.xcodeproj/project.pbxproj +++ b/week3/Calculator/Calculator.xcodeproj/project.pbxproj @@ -72,6 +72,8 @@ D460BBA128A93C4800FACD16 /* Preview Content */, D49F037928AE1B9500E3D308 /* View */, D49F037A28AE1B9F00E3D308 /* Model */, + D4156BA428B23BA200F51371 /* DoubleExtension.swift */, + D4156BA628B23BAA00F51371 /* StringExtension.swift */, D49F037828AE1B7300E3D308 /* ViewModel */, ); path = Calculator; @@ -89,8 +91,6 @@ isa = PBXGroup; children = ( D460BBAD28A952A700FACD16 /* Calculator.swift */, - D4156BA428B23BA200F51371 /* DoubleExtension.swift */, - D4156BA628B23BAA00F51371 /* StringExtension.swift */, ); path = ViewModel; sourceTree = ""; diff --git a/week3/Calculator/Calculator/ViewModel/DoubleExtension.swift b/week3/Calculator/Calculator/DoubleExtension.swift similarity index 100% rename from week3/Calculator/Calculator/ViewModel/DoubleExtension.swift rename to week3/Calculator/Calculator/DoubleExtension.swift diff --git a/week3/Calculator/Calculator/Model/CalculatorButton.swift b/week3/Calculator/Calculator/Model/CalculatorButton.swift index 70c672b..ab2e5ed 100644 --- a/week3/Calculator/Calculator/Model/CalculatorButton.swift +++ b/week3/Calculator/Calculator/Model/CalculatorButton.swift @@ -5,124 +5,3 @@ // Created by changgyo seo on 2022/08/21. // -enum CalculatorButton: Identifiable, Equatable { - case equal - case add(Bool) - case subtract(Bool) - case multiply(Bool) - case divide(Bool) - case percent - case sign - case clear(clearType) - case numberOrDot(String) - case none - - var id: String { return content } - - var content: String { - switch self { - case .equal: - return "=" - case .add: - return "+" - case .subtract: - return "-" - case .multiply: - return "*" - case .divide: - return "/" - case .percent: - return "%" - case .sign: - return "ยฑ" - case .clear(.displayresult): - return "C" - case .clear(.alldata): - return "AC" - case .numberOrDot(let value): - return value - default: - return "" - } - } - - var backgroundColor: (red: Double, green: Double, blue: Double, opacity: Double) { - switch self { - case .clear, .percent, .sign: - return (160 / 255, 160 / 255, 160 / 255 , 1) - case .numberOrDot: - return (50 / 255, 50 / 255, 50 / 255, 1) - case .add, .divide, .multiply, .subtract: - if isActive { - return (1, 1, 1, 1) - } - else { - return (233 / 255, 157 / 255, 57 / 255, 1) - } - default: - return (233 / 255, 157 / 255, 57 / 255, 1) - } - } - - var textColorColor: (red: Double, green: Double, blue: Double, opacity: Double) { - switch self { - case .clear, .percent, .sign: - return (0, 0, 0, 1) - case .add, .divide, .multiply, .subtract: - if isActive { - return (233 / 255, 157 / 255, 57 / 255, 1) - } - else { - return (1, 1, 1, 1) - } - default: - return (1, 1, 1, 1) - } - } - - var buttonSize: Int { - switch self { - case .numberOrDot("0"): - return 2 - default: - return 1 - } - } - - var isActive: Bool { - switch self { - case .add(let isActive): - return isActive - case .subtract(let isActive): - return isActive - case .multiply(let isActive): - return isActive - case .divide(let isActive): - return isActive - default: - return false - } - } - - mutating func activeButton(active: Bool) { - switch self { - case .divide: - self = .divide(active) - case .multiply: - self = .multiply(active) - case .subtract: - self = .subtract(active) - case .add: - self = .add(active) - default: - break - } - } -} - -extension CalculatorButton { - enum clearType { - case alldata - case displayresult - } -} diff --git a/week3/Calculator/Calculator/ViewModel/StringExtension.swift b/week3/Calculator/Calculator/StringExtension.swift similarity index 100% rename from week3/Calculator/Calculator/ViewModel/StringExtension.swift rename to week3/Calculator/Calculator/StringExtension.swift diff --git a/week3/Calculator/Calculator/View/CalculatorView.swift b/week3/Calculator/Calculator/View/CalculatorView.swift index dbd7b35..480988b 100644 --- a/week3/Calculator/Calculator/View/CalculatorView.swift +++ b/week3/Calculator/Calculator/View/CalculatorView.swift @@ -22,6 +22,112 @@ struct CalculatorView: View { } } +extension CalculatorView { + enum Button: Identifiable, Equatable { + case equal + case plus + case minus + case multiply + case divide + case percent + case sign + case clear(clearType) + case numberOrDot(Decimal) + case none + + var id: String { return content } + + var content: String { + switch self { + case .equal: + return "=" + case .plus: + return "+" + case .minus: + return "-" + case .multiply: + return "*" + case .divide: + return "/" + case .percent: + return "%" + case .sign: + return "ยฑ" + case .clear(.displayResult): + return "C" + case .clear(.allData): + return "AC" + case .numberOrDot(let value): + return "\(value)" + default: + return "" + } + } + + var backgroundColor: (red: Double, green: Double, blue: Double, opacity: Double) { + switch self { + case .clear, .percent, .sign: + return (160 / 255, 160 / 255, 160 / 255 , 1) + case .numberOrDot: + return (50 / 255, 50 / 255, 50 / 255, 1) + case .plus, .divide, .multiply, .minus: + if isActive { + return (1, 1, 1, 1) + } + else { + return (233 / 255, 157 / 255, 57 / 255, 1) + } + default: + return (233 / 255, 157 / 255, 57 / 255, 1) + } + } + + var textColorColor: (red: Double, green: Double, blue: Double, opacity: Double) { + switch self { + case .clear, .percent, .sign: + return (0, 0, 0, 1) + case .plus, .divide, .multiply, .minus: + if isActive { + return (233 / 255, 157 / 255, 57 / 255, 1) + } + else { + return (1, 1, 1, 1) + } + default: + return (1, 1, 1, 1) + } + } + + var buttonSize: Int { + switch self { + case .numberOrDot(0): + return 2 + default: + return 1 + } + } + + mutating func activeButton(active: Bool) { + switch self { + case .divide: + self = .divide + case .multiply: + self = .multiply + case .minus: + self = .minus + case .plus: + self = .plus + default: + break + } + } + } + enum clearType { + case allData + case displayResult + } +} + extension CalculatorView { enum DrawConstans { static let veticalModlColumnsCount = 4 diff --git a/week4/Calculator/Calculator.xcodeproj/project.pbxproj b/week4/Calculator/Calculator.xcodeproj/project.pbxproj index 026e5f3..1eba70e 100644 --- a/week4/Calculator/Calculator.xcodeproj/project.pbxproj +++ b/week4/Calculator/Calculator.xcodeproj/project.pbxproj @@ -14,8 +14,8 @@ 6F1A922928B13AE8009FBF28 /* CalculatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F1A922828B13AE8009FBF28 /* CalculatorModel.swift */; }; 6F1A922B28B13B04009FBF28 /* CaculatorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F1A922A28B13B04009FBF28 /* CaculatorManager.swift */; }; 6F1A922D28B2159B009FBF28 /* ResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F1A922C28B2159B009FBF28 /* ResultView.swift */; }; - 6F2AB33028B8D9970054B4BB /* NumberPadGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2AB32F28B8D9970054B4BB /* NumberPadGrid.swift */; }; - 6F2AB33228B8D9A60054B4BB /* NumberPad.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2AB33128B8D9A60054B4BB /* NumberPad.swift */; }; + 6F2AB33028B8D9970054B4BB /* NumberPad.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2AB32F28B8D9970054B4BB /* NumberPad.swift */; }; + 6F2AB33228B8D9A60054B4BB /* CalculatorButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2AB33128B8D9A60054B4BB /* CalculatorButton.swift */; }; 6F2AB33528B8DC930054B4BB /* Ex+Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2AB33428B8DC930054B4BB /* Ex+Color.swift */; }; 6F2AB33728B90EB10054B4BB /* Ex+String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2AB33628B90EB10054B4BB /* Ex+String.swift */; }; /* End PBXBuildFile section */ @@ -29,8 +29,8 @@ 6F1A922828B13AE8009FBF28 /* CalculatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalculatorModel.swift; sourceTree = ""; }; 6F1A922A28B13B04009FBF28 /* CaculatorManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaculatorManager.swift; sourceTree = ""; }; 6F1A922C28B2159B009FBF28 /* ResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultView.swift; sourceTree = ""; }; - 6F2AB32F28B8D9970054B4BB /* NumberPadGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberPadGrid.swift; sourceTree = ""; }; - 6F2AB33128B8D9A60054B4BB /* NumberPad.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberPad.swift; sourceTree = ""; }; + 6F2AB32F28B8D9970054B4BB /* NumberPad.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberPad.swift; sourceTree = ""; }; + 6F2AB33128B8D9A60054B4BB /* CalculatorButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalculatorButton.swift; sourceTree = ""; }; 6F2AB33428B8DC930054B4BB /* Ex+Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Ex+Color.swift"; sourceTree = ""; }; 6F2AB33628B90EB10054B4BB /* Ex+String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Ex+String.swift"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -113,8 +113,8 @@ isa = PBXGroup; children = ( 6F1A922C28B2159B009FBF28 /* ResultView.swift */, - 6F2AB32F28B8D9970054B4BB /* NumberPadGrid.swift */, - 6F2AB33128B8D9A60054B4BB /* NumberPad.swift */, + 6F2AB32F28B8D9970054B4BB /* NumberPad.swift */, + 6F2AB33128B8D9A60054B4BB /* CalculatorButton.swift */, ); path = SubViews; sourceTree = ""; @@ -205,8 +205,8 @@ 6F2AB33728B90EB10054B4BB /* Ex+String.swift in Sources */, 6F1A922B28B13B04009FBF28 /* CaculatorManager.swift in Sources */, 6F1A921828B13A71009FBF28 /* CalculatorApp.swift in Sources */, - 6F2AB33228B8D9A60054B4BB /* NumberPad.swift in Sources */, - 6F2AB33028B8D9970054B4BB /* NumberPadGrid.swift in Sources */, + 6F2AB33228B8D9A60054B4BB /* CalculatorButton.swift in Sources */, + 6F2AB33028B8D9970054B4BB /* NumberPad.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -335,7 +335,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Calculator/Preview Content\""; - DEVELOPMENT_TEAM = 3FAK98S72C; + DEVELOPMENT_TEAM = VT6KC94KM7; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; @@ -348,7 +348,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = jum.Calculator; + PRODUCT_BUNDLE_IDENTIFIER = pccommen.Calculator; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -364,7 +364,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Calculator/Preview Content\""; - DEVELOPMENT_TEAM = 3FAK98S72C; + DEVELOPMENT_TEAM = VT6KC94KM7; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; @@ -377,7 +377,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = jum.Calculator; + PRODUCT_BUNDLE_IDENTIFIER = pccommen.Calculator; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; diff --git a/week4/Calculator/Calculator/CalculatorApp.swift b/week4/Calculator/Calculator/CalculatorApp.swift index 5bb77cd..3a3c0fd 100644 --- a/week4/Calculator/Calculator/CalculatorApp.swift +++ b/week4/Calculator/Calculator/CalculatorApp.swift @@ -14,7 +14,7 @@ struct CalculatorApp: App { var body: some Scene { WindowGroup { - ContentView(calculatorManager: caculatorManager) + ContentView().environmentObject(caculatorManager) } } } diff --git a/week4/Calculator/Calculator/Model/CalculatorModel.swift b/week4/Calculator/Calculator/Model/CalculatorModel.swift index eb0e7c3..ff40a9c 100644 --- a/week4/Calculator/Calculator/Model/CalculatorModel.swift +++ b/week4/Calculator/Calculator/Model/CalculatorModel.swift @@ -8,211 +8,164 @@ import Foundation struct Calculator { - - var state: InputState = .newPreviousNumber - var operation: ArithmeticOperation? { - willSet { - if nextNumber != nil { calculate() } - } - } - var showingText: String - private(set) var previousNumber: Decimal? { - didSet { - guard let previousNumber = previousNumber else { return } - showingText = "\(previousNumber)" - } - } - private(set) var nextNumber: Decimal? { - didSet { - guard let nextNumber = nextNumber else { return } - showingText = "\(nextNumber)" - } - } - private(set) var result: Decimal { - didSet { - showingText = "\(result)" - previousNumber = result - nextNumber = nil - state = .finishInput - } - } - - enum InputState { - case newPreviousNumber - case newNextNumber - case ongoingPreviousNumber - case ongoingNextNumber - case finishInput - } - - mutating func clickNumber(_ number: Decimal) { - switch state { - case .newPreviousNumber, .finishInput: - previousNumber = number - state = .ongoingPreviousNumber - case .newNextNumber: - nextNumber = number - state = .ongoingNextNumber - case .ongoingPreviousNumber: - previousNumber = joinNumbers(with: number) - case .ongoingNextNumber: - nextNumber = joinNumbers(with: number) + + var state: InputState = .firstNumber(isStart: false) + var `operator`: ArithmeticOperation? { + + willSet { + + if state == .secondNumber(isStart: true) { calculate() } + } } - } - - mutating func calculate() { - guard let priorNumber = previousNumber, - let laterNumber = nextNumber, - let operation = operation else { return } - switch operation { - case .multiply: - result = priorNumber * laterNumber - case .divide: - result = priorNumber / laterNumber - case .minus: - result = priorNumber - laterNumber - case .plus: - result = priorNumber + laterNumber - default: - print("error") + var showingText: String + private(set) var previousNumber: Decimal? { + + didSet { + + guard let previousNumber = previousNumber else { return } + showingText = "\(previousNumber)" + } } - } - - mutating func joinNumbers(with nextElement: Decimal) -> Decimal { - let joinedString = showingText + "\(nextElement)" - guard let joinedNumber = Decimal(string: joinedString) else { return 0 } - return joinedNumber - } - - mutating func changeSign() { - if let priorNumber = previousNumber { - if let afterNumber = nextNumber { - nextNumber = -afterNumber - } else { - previousNumber = -priorNumber - } + private(set) var nextNumber: Decimal? { + + didSet { + + guard let nextNumber = nextNumber else { return } + showingText = "\(nextNumber)" + } } - } - - mutating func percent() { - if let priorNumber = previousNumber { - if let afterNumber = nextNumber { - nextNumber = afterNumber / 100 - } else { - previousNumber = priorNumber / 100 - } + private(set) var result: Decimal { + + didSet { + + showingText = "\(result)" + previousNumber = result + state = .finishInput + } } - } - - mutating func addPoint() { - if !showingText.contains(".") { - showingText = showingText + "." - if showingText.compare("0") == .orderedSame { - state = .ongoingPreviousNumber - } + + enum InputState: Equatable { + + case firstNumber(isStart: Bool) + case secondNumber(isStart: Bool) + case finishInput } - } -} - -extension Calculator { - - enum ArithmeticOperation: Identifiable, Equatable { - case equal - case plus(Bool) - case minus(Bool) - case multiply(Bool) - case divide(Bool) - case percent - case sign - case clear(clearType) - case number(Decimal) - case point - var id: String { return content } + mutating func clickNumber(_ number: Decimal) { + + switch state { + + case .firstNumber(false), .finishInput: + previousNumber = number + state = .firstNumber(isStart: true) + case .secondNumber(isStart: false): + nextNumber = number + state = .secondNumber(isStart: true) + case .firstNumber(isStart: true): + previousNumber = joinNumbers(with: number) + case .secondNumber(isStart: true): + nextNumber = joinNumbers(with: number) + } + } - var content: String { - switch self { - case .equal: - return "=" - case .plus: - return "+" - case .minus: - return "-" - case .multiply: - return "*" - case .divide: - return "/" - case .percent: - return "%" - case .sign: - return "ยฑ" - case .clear(.displayResult): - return "C" - case .clear(.allData): - return "AC" - case .number(let value): - return "\(value)" - case .point: - return "." - } + mutating func calculate() { + + guard let priorNumber = previousNumber, + let laterNumber = nextNumber, + let operation = `operator` else { return } + state = .finishInput + switch operation { + + case .multiply: + result = priorNumber * laterNumber + case .divide: + result = priorNumber / laterNumber + case .minus: + result = priorNumber - laterNumber + case .plus: + result = priorNumber + laterNumber + default: + print("error") + } } - var isActive: Bool { - switch self { - case .plus(let isActive), .multiply(let isActive), .minus(let isActive), .divide(let isActive): - return isActive - default: - return false - } + mutating func joinNumbers(with nextElement: Decimal) -> Decimal { + + let joinedString = showingText + "\(nextElement)" + guard let joinedNumber = Decimal(string: joinedString) else { return 0 } + return joinedNumber } - var backgroundColor: String { - switch self { - case .clear, .percent, .sign: - return "#A0A0A0" - case .number, .point: - return "#323232" - case .plus, .divide, .multiply, .minus, .equal: - return isActive ? "#FFFFFF" : "#E99D39" - } + mutating func changeSign() { + + if let priorNumber = previousNumber { + + if let afterNumber = nextNumber { nextNumber = -afterNumber } + else { previousNumber = -priorNumber} + } } - var textColor: String { - switch self { - case .clear, .percent, .sign: - return "#000000" - case .plus, .divide, .multiply, .minus, .equal, .number, .point: - return isActive ? "#E99D39" : "#FFFFFF" - } + mutating func percent() { + + if let priorNumber = previousNumber { + + if let afterNumber = nextNumber { nextNumber = afterNumber / 100 } + else { previousNumber = priorNumber / 100 } + } } - var buttonSize: Int { - switch self { - case .number(0): - return 2 - default: - return 1 - } + mutating func addPoint() { + + if !showingText.contains(".") { + + showingText = showingText + "." + if showingText.compare("0") == .orderedSame { + + state = .firstNumber(isStart: true) + } + } } +} + +extension Calculator { - mutating func activeButton(active: Bool) { - switch self { - case .divide: - self = .divide(active) - case .multiply: - self = .multiply(active) - case .minus: - self = .minus(active) - case .plus: - self = .plus(active) - default: - break - } + enum ArithmeticOperation: Identifiable, Equatable { + + case equal + case plus + case minus + case multiply + case divide + case percent + case sign + case clear + case number(Decimal) + case point + + var id: String { + switch self { + case .equal: + return "equal" + case .plus: + return "plus" + case .minus: + return "minus" + case .multiply: + return "multiply" + case .divide: + return "divide" + case .percent: + return "percent" + case .sign: + return "sign" + case .clear: + return "clear" + case .number(let decimal): + return "\(decimal)" + case .point: + return "point" + } + } + } - } - - enum clearType { - case allData - case displayResult - } } diff --git a/week4/Calculator/Calculator/View/ContentView.swift b/week4/Calculator/Calculator/View/ContentView.swift index e55c5e3..b13348c 100644 --- a/week4/Calculator/Calculator/View/ContentView.swift +++ b/week4/Calculator/Calculator/View/ContentView.swift @@ -8,27 +8,40 @@ import SwiftUI struct ContentView: View { - - @ObservedObject var calculatorManager: CalculatorManager - - var body: some View { - ZStack{ - Color.black.ignoresSafeArea() - VStack { - Spacer() - ResultView(showingText: calculatorManager.showingText) - .gesture( - DragGesture() - .onEnded { _ in calculatorManager.slideToRemove() } - ) - NumberPadGrid(items: calculatorManager.buttonList , columnsCount: 4) { item in - Button { - calculatorManager.click(item) - } label: { - NumberPad(buttonData: item) - } + + @EnvironmentObject var calculatorManager: CalculatorManager + + var body: some View { + + ZStack{ + + Color.black.ignoresSafeArea() + VStack { + + Spacer() + ResultView(showingText: calculatorManager.showingText) + .gesture( + DragGesture() + .onEnded { _ in calculatorManager.slideToRemove() } + ) + NumberPad(items: ContentView.buttonList , columnsCount: 4) { item in + + Button { calculatorManager.click(item) } + label: { CalculatorButton(buttonData: item) } + } + } } - } } - } +} + +extension ContentView { + + static let buttonList: [Calculator.ArithmeticOperation] = + [ + .clear, .sign, .percent, .divide, + .number(7), .number(8), .number(9), .multiply, + .number(4), .number(5), .number(6), .minus, + .number(1), .number(2), .number(3), .plus, + .number(0), .point, .equal + ] } diff --git a/week4/Calculator/Calculator/View/SubViews/CalculatorButton.swift b/week4/Calculator/Calculator/View/SubViews/CalculatorButton.swift new file mode 100644 index 0000000..81a4bd5 --- /dev/null +++ b/week4/Calculator/Calculator/View/SubViews/CalculatorButton.swift @@ -0,0 +1,108 @@ +// +// NumberPad.swift +// Calculator +// +// Created by changgyo seo on 2022/08/26. +// + +import SwiftUI + +struct CalculatorButton: View { + + @EnvironmentObject var calculatorManager: CalculatorManager + var buttonData: Calculator.ArithmeticOperation + + var body: some View { + + GeometryReader { geometry in + + ZStack { + + RoundedRectangle(cornerRadius: cornerRadius(in: geometry.size)) + .foregroundColor(backGroundColor) + Text(content) + .foregroundColor(textColor) + .font(font(in: geometry.size)) + } + } + } + + private func cornerRadius(in size: CGSize) -> CGFloat { + + size.width * DrawConstans.buttonCornerRadius + } + + private func font(in size: CGSize) -> Font { + + Font.system(size: size.height * DrawConstans.fontSizeScale) + } + + private var textColor: Color { + + switch buttonData { + + case .minus, .plus, .divide, .multiply, .equal, .number, .point: + if calculatorManager.calculateModel.operator == buttonData && + calculatorManager.isRecentedOperator { + + return .init(hex: "#E99D39") + } + else { return .init(hex: "#FFFFFF") } + default: + return .init(hex: "#000000") + } + } + private var backGroundColor: Color { + + switch buttonData { + + case .minus, .plus, .divide, .multiply, .equal: + if calculatorManager.calculateModel.operator == buttonData && + calculatorManager.isRecentedOperator { + + return .init(hex: "#FFFFFF") + } + else { return .init(hex: "#E99D39") } + case .number(_), .point: + return .init(hex: "#323232") + case .clear, .percent, .sign: + return .init(hex: "#A0A0A0") + } + } + var content: String { + + switch buttonData { + + case .equal: + return "=" + case .plus: + return "+" + case .minus: + return "-" + case .multiply: + return "*" + case .divide: + return "/" + case .percent: + return "%" + case .sign: + return "ยฑ" + case .clear: + if calculatorManager.showingText != "0" { return "C" } + return "AC" + case .number(let value): + return "\(value)" + case .point: + return "." + } + } + +} + +extension CalculatorButton { + + private enum DrawConstans { + static let buttonCornerRadius = 0.5 + static let fontSizeScale = 0.4 + } +} diff --git a/week4/Calculator/Calculator/View/SubViews/NumberPad.swift b/week4/Calculator/Calculator/View/SubViews/NumberPad.swift index 29444a8..c0605ea 100644 --- a/week4/Calculator/Calculator/View/SubViews/NumberPad.swift +++ b/week4/Calculator/Calculator/View/SubViews/NumberPad.swift @@ -1,5 +1,5 @@ // -// NumberPad.swift +// NumberPadGrid.swift // Calculator // // Created by changgyo seo on 2022/08/26. @@ -7,35 +7,97 @@ import SwiftUI -struct NumberPad: View { - - var buttonData: Calculator.ArithmeticOperation - - var body: some View { - GeometryReader { geometry in - ZStack { - RoundedRectangle(cornerRadius: cornerRadius(in: geometry.size)) - .foregroundColor(Color(hex: buttonData.backgroundColor)) - Text(buttonData.content) - .foregroundColor(Color(hex: buttonData.textColor)) - .font(font(in: geometry.size)) - } +struct NumberPad: View { + + let buttonDataArray: [ButtonDataArray] + let columnsCount: Int + let content: (Calculator.ArithmeticOperation) -> buttonListView + + var body: some View { + + VStack(spacing: 0) { + + ForEach(buttonDataArray) { items in + + HStack(spacing: 0) { + + ForEach(items.array) { item in + + let width = widthForColumnsCount(in: UIScreen.main.bounds.size, item: item) + let height = width / CGFloat(item == .number(0) ? 2 : 1) + content(item) + .padding(5) + .frame(width: width, height: height, alignment: .center) + } + } + } + } + } + + init(items: [Calculator.ArithmeticOperation], columnsCount: Int, @ViewBuilder content: @escaping (Calculator.ArithmeticOperation) -> buttonListView) { + + self.buttonDataArray = ButtonDataArray.makeTwoDimensionArrayForColumnsCount(items: items, columnsCount: columnsCount) + self.columnsCount = columnsCount + self.content = content + } + + private func widthForColumnsCount(in size: CGSize, item: Calculator.ArithmeticOperation) -> CGFloat { + + let sizeForOne = size.width / CGFloat(columnsCount) + return item == .number(0) ? sizeForOne * 2 : sizeForOne } - } - - private func cornerRadius(in size: CGSize) -> CGFloat { - size.width * DrawConstans.buttonCornerRadius - } - - private func font(in size: CGSize) -> Font { - Font.system(size: size.height * DrawConstans.fontSizeScale) - } } extension NumberPad { - - private enum DrawConstans { - static let buttonCornerRadius = 0.5 - static let fontSizeScale = 0.4 - } + + struct ButtonDataArray: Identifiable { + + var id: Int + var array: [Calculator.ArithmeticOperation] + var totalWidth: Int + + init() { + + array = [Calculator.ArithmeticOperation]() + id = 1 + totalWidth = 0 + } + + mutating func append(_ newItem: Calculator.ArithmeticOperation) { + + array.append(newItem) + } + + mutating func changeId() { + + id += 1 + totalWidth = 0 + array.removeAll() + } + + static func makeTwoDimensionArrayForColumnsCount(items: [Calculator.ArithmeticOperation], columnsCount: Int) -> [ButtonDataArray] { + + var arrayWithColumnsCount = ButtonDataArray() + var TwoDemesionArray = [ButtonDataArray]() + var rowWidth = 0 + items.forEach { item in + + let buttonSize = item == .number(0) ? 2 : 1 + if rowWidth + buttonSize <= columnsCount { + + arrayWithColumnsCount.append(item) + rowWidth += buttonSize + } else { + + arrayWithColumnsCount.totalWidth = rowWidth + TwoDemesionArray.append(arrayWithColumnsCount) + arrayWithColumnsCount.changeId() + arrayWithColumnsCount.append(item) + rowWidth = buttonSize + } + } + TwoDemesionArray.append(arrayWithColumnsCount) + return TwoDemesionArray + } + } } diff --git a/week4/Calculator/Calculator/View/SubViews/NumberPadGrid.swift b/week4/Calculator/Calculator/View/SubViews/NumberPadGrid.swift deleted file mode 100644 index 1bb1db6..0000000 --- a/week4/Calculator/Calculator/View/SubViews/NumberPadGrid.swift +++ /dev/null @@ -1,89 +0,0 @@ -// -// NumberPadGrid.swift -// Calculator -// -// Created by changgyo seo on 2022/08/26. -// - -import SwiftUI - -struct NumberPadGrid: View { - - let buttonDataArray: [ButtonDataArray] - let columnsCount: Int - let content: (Calculator.ArithmeticOperation) -> buttonListView - - var body: some View { - VStack(spacing: 0) { - ForEach(buttonDataArray) { items in - HStack(spacing: 0) { - ForEach(items.array) { item in - let width = widthForColumnsCount(in: UIScreen.main.bounds.size, - buttonWidth: item.buttonSize) - let height = width / CGFloat(item.buttonSize) - content(item) - .padding(5) - .frame(width: width, height: height, alignment: .center) - } - } - } - } - } - - init(items: [Calculator.ArithmeticOperation], columnsCount: Int, @ViewBuilder content: @escaping (Calculator.ArithmeticOperation) -> buttonListView) { - self.buttonDataArray = ButtonDataArray.makeTwoDemsionArrayForColumnsCount(items: items, columnsCount: columnsCount) - self.columnsCount = columnsCount - self.content = content - } - - private func widthForColumnsCount(in size: CGSize, buttonWidth width: Int) -> CGFloat { - let sizeForOne = size.width / CGFloat(columnsCount) - return sizeForOne * CGFloat(width) - } -} - -extension NumberPadGrid { - - struct ButtonDataArray: Identifiable { - - var id: Int - var array: [Calculator.ArithmeticOperation] - var totalWidth: Int - - init() { - array = [Calculator.ArithmeticOperation]() - id = 1 - totalWidth = 0 - } - - mutating func append(_ newItem: Calculator.ArithmeticOperation) { - array.append(newItem) - } - - mutating func changeId() { - id += 1 - totalWidth = 0 - array.removeAll() - } - - static func makeTwoDemsionArrayForColumnsCount(items: [Calculator.ArithmeticOperation], columnsCount: Int) -> [ButtonDataArray] { - var arrayWithColumnsCount = ButtonDataArray() - var TwoDemesionArray = [ButtonDataArray]() - var rowWidth = 0 - items.forEach { item in - if rowWidth + item.buttonSize <= columnsCount { - arrayWithColumnsCount.append(item) - rowWidth += item.buttonSize - } else { - arrayWithColumnsCount.totalWidth = rowWidth - TwoDemesionArray.append(arrayWithColumnsCount) - arrayWithColumnsCount.changeId() - arrayWithColumnsCount.append(item) - rowWidth = item.buttonSize - } - } - TwoDemesionArray.append(arrayWithColumnsCount) - return TwoDemesionArray - } - } -} diff --git a/week4/Calculator/Calculator/View/SubViews/ResultView.swift b/week4/Calculator/Calculator/View/SubViews/ResultView.swift index 6c52efe..26255ed 100644 --- a/week4/Calculator/Calculator/View/SubViews/ResultView.swift +++ b/week4/Calculator/Calculator/View/SubViews/ResultView.swift @@ -8,28 +8,29 @@ import SwiftUI struct ResultView: View { - - let showingText: String - - var body: some View { - HStack { - Spacer() - Text(showingText) - .lineLimit(1) - .foregroundColor(.white) - .font(.system(size: DrawConstans.fontSize)) - .minimumScaleFactor(DrawConstans.fontMinimumSacleFactor) - .padding(.trailing, DrawConstans.textPadding) + + let showingText: String + + var body: some View { + + HStack { + Spacer() + Text(showingText) + .lineLimit(1) + .foregroundColor(.white) + .font(.system(size: DrawConstans.fontSize)) + .minimumScaleFactor(DrawConstans.fontMinimumSacleFactor) + .padding(.trailing, DrawConstans.textPadding) + } + .contentShape(Rectangle()) } - .contentShape(Rectangle()) - } } extension ResultView { - - private enum DrawConstans { - static let fontSize = 80.0 - static let fontMinimumSacleFactor = 0.5 - static let textPadding = 20.0 - } + + private enum DrawConstans { + static let fontSize = 80.0 + static let fontMinimumSacleFactor = 0.5 + static let textPadding = 20.0 + } } diff --git a/week4/Calculator/Calculator/ViewModel/CaculatorManager.swift b/week4/Calculator/Calculator/ViewModel/CaculatorManager.swift index 0181495..bd53630 100644 --- a/week4/Calculator/Calculator/ViewModel/CaculatorManager.swift +++ b/week4/Calculator/Calculator/ViewModel/CaculatorManager.swift @@ -8,107 +8,84 @@ import SwiftUI class CalculatorManager: ObservableObject { - - @Published private var calculateModel = create() - @Published var buttonList: [Calculator.ArithmeticOperation] = - [ - .clear(.allData), .sign, .percent, .divide(false), - .number(7), .number(8), .number(9), .multiply(false), - .number(4), .number(5), .number(6), .minus(false), - .number(1), .number(2), .number(3), .plus(false), - .number(0), .point, .equal - ] - - var showingText: String { - get { - if calculateModel.showingText != "0" { - guard let clearIndex = buttonList.firstIndex(of: .clear(.allData)) else { return calculateModel.showingText } - buttonList[clearIndex] = .clear(.displayResult) - } else { - guard let clearIndex = buttonList.firstIndex(of: .clear(.displayResult)) else { return calculateModel.showingText } - buttonList[clearIndex] = .clear(.allData) - } - return calculateModel.showingText + + @Published private(set) var calculateModel = create() + private(set) var isRecentedOperator: Bool = false + + var showingText: String { + get { calculateModel.showingText } + set { calculateModel.showingText = newValue } } - set { calculateModel.showingText = newValue } - } - - private static func create() -> Calculator { - return Calculator(showingText: "0", result: 0) - } - - // MARK: - Intentions - - func click(_ clickType: Calculator.ArithmeticOperation) { - switch clickType { - case .number(let decimal): - if calculateModel.operation == nil, - calculateModel.state != .ongoingPreviousNumber { - calculateModel.state = .newPreviousNumber - } - for index in buttonList.indices { - if buttonList[index].isActive { - switch buttonList[index] { - case .plus, .minus, .divide, .multiply: - buttonList[index].activeButton(active: false) - default: - print("error") - } + private static func create() -> Calculator { + return Calculator(showingText: "0", result: 0) + } + + // MARK: - Intentions + + func click(_ clickType: Calculator.ArithmeticOperation) { + + isRecentedOperator = false + switch clickType { + + case .number(let decimal): + click(decimal) + case .equal: + calculate() + case .clear: + if showingText != "0" { showingText = "0"} + else { clear() } + case .sign: + changeSign() + case .percent: + percent() + case .point: + addPoint() + default: + isRecentedOperator = true + click(operation: clickType) + } + } + + func click(_ number: Decimal) { + + calculateModel.clickNumber(number) + } + + func click(operation: Calculator.ArithmeticOperation?) { + + calculateModel.`operator` = operation + if calculateModel.state == .finishInput { + + calculateModel.state = .secondNumber(isStart: false) + } + else if calculateModel.state == .firstNumber(isStart: true) { + + calculateModel.state = .secondNumber(isStart: false) } - } - clickNumber(decimal) - case .equal: - calculate() - case .clear(.allData): - clear() - case .clear(.displayResult): - showingText = "0" - case .sign: - changeSign() - case .percent: - percent() - case .point: - addPoint() - default: - for index in buttonList.indices { - buttonList[index] == clickType - ? buttonList[index].activeButton(active: true) - : buttonList[index].activeButton(active: false) - } - clickOperation(clickType) + else { calculateModel.state = .firstNumber(isStart: false) } + } + + func calculate() { + calculateModel.calculate() + } + + func clear() { + calculateModel = CalculatorManager.create() + } + + func changeSign() { + calculateModel.changeSign() + } + + func slideToRemove() { + showingText.removeWithDecimal() + } + + func percent() { + calculateModel.percent() + } + + func addPoint() { + calculateModel.addPoint() } - } - - func clickNumber(_ number: Decimal) { - calculateModel.clickNumber(number) - } - - func clickOperation(_ operation: Calculator.ArithmeticOperation?) { - calculateModel.operation = operation - calculateModel.state = .newNextNumber - } - - func calculate() { - calculateModel.calculate() - } - - func clear() { - calculateModel = CalculatorManager.create() - } - - func changeSign() { - calculateModel.changeSign() - } - - func slideToRemove() { - showingText.removeWithDecimal() - } - - func percent() { - calculateModel.percent() - } - - func addPoint() { - calculateModel.addPoint() - } } diff --git a/week5/NetworkModule/NetworkModule.xcodeproj/project.pbxproj b/week5/NetworkModule/NetworkModule.xcodeproj/project.pbxproj new file mode 100644 index 0000000..4af4867 --- /dev/null +++ b/week5/NetworkModule/NetworkModule.xcodeproj/project.pbxproj @@ -0,0 +1,396 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + D434BDE228BCE54000A2E32B /* NetworkModuleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D434BDE128BCE54000A2E32B /* NetworkModuleApp.swift */; }; + D434BDE428BCE54000A2E32B /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D434BDE328BCE54000A2E32B /* ContentView.swift */; }; + D434BDE628BCE54100A2E32B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D434BDE528BCE54100A2E32B /* Assets.xcassets */; }; + D434BDE928BCE54100A2E32B /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D434BDE828BCE54100A2E32B /* Preview Assets.xcassets */; }; + D434BDF028BCE55400A2E32B /* NetworkModuleAlamofireStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D434BDEF28BCE55400A2E32B /* NetworkModuleAlamofireStyle.swift */; }; + D434BDF428BDDB1600A2E32B /* Finder.swift in Sources */ = {isa = PBXBuildFile; fileRef = D434BDF328BDDB1600A2E32B /* Finder.swift */; }; + D434BDF628BE0C6300A2E32B /* NaverOpenAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = D434BDF528BE0C6300A2E32B /* NaverOpenAPI.swift */; }; + D434BDFB28BE0EEB00A2E32B /* SearchModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D434BDFA28BE0EEB00A2E32B /* SearchModel.swift */; }; + D49D2D1628C64F1A0024E844 /* NetworkModulMoyaStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49D2D1528C64F1A0024E844 /* NetworkModulMoyaStyle.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + D434BDDE28BCE54000A2E32B /* NetworkModule.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NetworkModule.app; sourceTree = BUILT_PRODUCTS_DIR; }; + D434BDE128BCE54000A2E32B /* NetworkModuleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkModuleApp.swift; sourceTree = ""; }; + D434BDE328BCE54000A2E32B /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + D434BDE528BCE54100A2E32B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + D434BDE828BCE54100A2E32B /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + D434BDEF28BCE55400A2E32B /* NetworkModuleAlamofireStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkModuleAlamofireStyle.swift; sourceTree = ""; }; + D434BDF328BDDB1600A2E32B /* Finder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Finder.swift; sourceTree = ""; }; + D434BDF528BE0C6300A2E32B /* NaverOpenAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NaverOpenAPI.swift; sourceTree = ""; }; + D434BDFA28BE0EEB00A2E32B /* SearchModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchModel.swift; sourceTree = ""; }; + D49D2D1528C64F1A0024E844 /* NetworkModulMoyaStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkModulMoyaStyle.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + D434BDDB28BCE54000A2E32B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + D434BDD528BCE54000A2E32B = { + isa = PBXGroup; + children = ( + D434BDE028BCE54000A2E32B /* NetworkModule */, + D434BDDF28BCE54000A2E32B /* Products */, + ); + sourceTree = ""; + }; + D434BDDF28BCE54000A2E32B /* Products */ = { + isa = PBXGroup; + children = ( + D434BDDE28BCE54000A2E32B /* NetworkModule.app */, + ); + name = Products; + sourceTree = ""; + }; + D434BDE028BCE54000A2E32B /* NetworkModule */ = { + isa = PBXGroup; + children = ( + D434BDE128BCE54000A2E32B /* NetworkModuleApp.swift */, + D434BDE528BCE54100A2E32B /* Assets.xcassets */, + D434BDE728BCE54100A2E32B /* Preview Content */, + D434BDF728BE0EC000A2E32B /* Network */, + D434BDFC28BE0EEF00A2E32B /* Model */, + D434BDF828BE0EC800A2E32B /* View */, + D434BDF928BE0ED100A2E32B /* ViewModel */, + ); + path = NetworkModule; + sourceTree = ""; + }; + D434BDE728BCE54100A2E32B /* Preview Content */ = { + isa = PBXGroup; + children = ( + D434BDE828BCE54100A2E32B /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + D434BDF728BE0EC000A2E32B /* Network */ = { + isa = PBXGroup; + children = ( + D434BDEF28BCE55400A2E32B /* NetworkModuleAlamofireStyle.swift */, + D434BDF528BE0C6300A2E32B /* NaverOpenAPI.swift */, + D49D2D1528C64F1A0024E844 /* NetworkModulMoyaStyle.swift */, + ); + path = Network; + sourceTree = ""; + }; + D434BDF828BE0EC800A2E32B /* View */ = { + isa = PBXGroup; + children = ( + D434BDE328BCE54000A2E32B /* ContentView.swift */, + ); + path = View; + sourceTree = ""; + }; + D434BDF928BE0ED100A2E32B /* ViewModel */ = { + isa = PBXGroup; + children = ( + D434BDF328BDDB1600A2E32B /* Finder.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; + D434BDFC28BE0EEF00A2E32B /* Model */ = { + isa = PBXGroup; + children = ( + D434BDFA28BE0EEB00A2E32B /* SearchModel.swift */, + ); + path = Model; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + D434BDDD28BCE54000A2E32B /* NetworkModule */ = { + isa = PBXNativeTarget; + buildConfigurationList = D434BDEC28BCE54100A2E32B /* Build configuration list for PBXNativeTarget "NetworkModule" */; + buildPhases = ( + D434BDDA28BCE54000A2E32B /* Sources */, + D434BDDB28BCE54000A2E32B /* Frameworks */, + D434BDDC28BCE54000A2E32B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = NetworkModule; + productName = NetworkModule; + productReference = D434BDDE28BCE54000A2E32B /* NetworkModule.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D434BDD628BCE54000A2E32B /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1340; + LastUpgradeCheck = 1340; + TargetAttributes = { + D434BDDD28BCE54000A2E32B = { + CreatedOnToolsVersion = 13.4.1; + }; + }; + }; + buildConfigurationList = D434BDD928BCE54000A2E32B /* Build configuration list for PBXProject "NetworkModule" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = D434BDD528BCE54000A2E32B; + productRefGroup = D434BDDF28BCE54000A2E32B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D434BDDD28BCE54000A2E32B /* NetworkModule */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + D434BDDC28BCE54000A2E32B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D434BDE928BCE54100A2E32B /* Preview Assets.xcassets in Resources */, + D434BDE628BCE54100A2E32B /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + D434BDDA28BCE54000A2E32B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D434BDF428BDDB1600A2E32B /* Finder.swift in Sources */, + D434BDF628BE0C6300A2E32B /* NaverOpenAPI.swift in Sources */, + D434BDE428BCE54000A2E32B /* ContentView.swift in Sources */, + D434BDFB28BE0EEB00A2E32B /* SearchModel.swift in Sources */, + D49D2D1628C64F1A0024E844 /* NetworkModulMoyaStyle.swift in Sources */, + D434BDE228BCE54000A2E32B /* NetworkModuleApp.swift in Sources */, + D434BDF028BCE55400A2E32B /* NetworkModuleAlamofireStyle.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + D434BDEA28BCE54100A2E32B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.5; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + D434BDEB28BCE54100A2E32B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.5; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + D434BDED28BCE54100A2E32B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"NetworkModule/Preview Content\""; + DEVELOPMENT_TEAM = VT6KC94KM7; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = pccommen.NetworkModule; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + D434BDEE28BCE54100A2E32B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"NetworkModule/Preview Content\""; + DEVELOPMENT_TEAM = VT6KC94KM7; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = pccommen.NetworkModule; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + D434BDD928BCE54000A2E32B /* Build configuration list for PBXProject "NetworkModule" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D434BDEA28BCE54100A2E32B /* Debug */, + D434BDEB28BCE54100A2E32B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D434BDEC28BCE54100A2E32B /* Build configuration list for PBXNativeTarget "NetworkModule" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D434BDED28BCE54100A2E32B /* Debug */, + D434BDEE28BCE54100A2E32B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D434BDD628BCE54000A2E32B /* Project object */; +} diff --git a/week5/NetworkModule/NetworkModule.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/week5/NetworkModule/NetworkModule.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/week5/NetworkModule/NetworkModule.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/week5/NetworkModule/NetworkModule.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/week5/NetworkModule/NetworkModule.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/week5/NetworkModule/NetworkModule.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/week5/NetworkModule/NetworkModule/Assets.xcassets/AccentColor.colorset/Contents.json b/week5/NetworkModule/NetworkModule/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/week5/NetworkModule/NetworkModule/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/week5/NetworkModule/NetworkModule/Assets.xcassets/AppIcon.appiconset/Contents.json b/week5/NetworkModule/NetworkModule/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..9221b9b --- /dev/null +++ b/week5/NetworkModule/NetworkModule/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/week5/NetworkModule/NetworkModule/Assets.xcassets/Contents.json b/week5/NetworkModule/NetworkModule/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/week5/NetworkModule/NetworkModule/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/week5/NetworkModule/NetworkModule/Assets.xcassets/tempImage.imageset/Contents.json b/week5/NetworkModule/NetworkModule/Assets.xcassets/tempImage.imageset/Contents.json new file mode 100644 index 0000000..a01a527 --- /dev/null +++ b/week5/NetworkModule/NetworkModule/Assets.xcassets/tempImage.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "แ„†แ…ตแ„†แ…ฉแ„แ…ตแ„แ…ฉแ†ซ-แ„†แ…ขแ†จแ„‡แ…ฎแ†จ.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/week5/NetworkModule/NetworkModule/Assets.xcassets/tempImage.imageset/\353\257\270\353\252\250\355\213\260\354\275\230-\353\247\245\353\266\201.png" "b/week5/NetworkModule/NetworkModule/Assets.xcassets/tempImage.imageset/\353\257\270\353\252\250\355\213\260\354\275\230-\353\247\245\353\266\201.png" new file mode 100644 index 0000000..59e5b00 Binary files /dev/null and "b/week5/NetworkModule/NetworkModule/Assets.xcassets/tempImage.imageset/\353\257\270\353\252\250\355\213\260\354\275\230-\353\247\245\353\266\201.png" differ diff --git a/week5/NetworkModule/NetworkModule/Model/SearchModel.swift b/week5/NetworkModule/NetworkModule/Model/SearchModel.swift new file mode 100644 index 0000000..ad96e68 --- /dev/null +++ b/week5/NetworkModule/NetworkModule/Model/SearchModel.swift @@ -0,0 +1,73 @@ +// +// SearchModel.swift +// NetworkModule +// +// Created by changgyo seo on 2022/08/30. +// + +struct Movie: Codable { + + let title: String + let link: String + let image: String + let subtitle: String + let pubDate: String + let director: String + let actor: String + let userRating: String + + enum Request: RequestEnum { + + case query(String) + case display(Int) + case start(Int) + case genre(String) + case country(String) + case yearFrom(Int) + case yearTo(Int) + + var keyText: String { + + switch self { + + case .query: + return "query" + case .display: + return "display" + case .start: + return "start" + case .genre: + return "genre" + case .country: + return "country" + case .yearFrom: + return "yearFrom" + case .yearTo: + return "yearTo" + } + } + + var valueText: String { + + switch self { + + case .query(let value): + return value + case .display(let value): + return String(value) + case .start(let value): + return String(value) + case .genre(let value): + return value + case .country(let value): + return value + case .yearFrom(let value): + return String(value) + case .yearTo(let value): + return String(value) + } + + } + } + +} diff --git a/week5/NetworkModule/NetworkModule/Network/NaverOpenAPI.swift b/week5/NetworkModule/NetworkModule/Network/NaverOpenAPI.swift new file mode 100644 index 0000000..29c7cdd --- /dev/null +++ b/week5/NetworkModule/NetworkModule/Network/NaverOpenAPI.swift @@ -0,0 +1,31 @@ +// +// APIConstants.swift +// NetworkModule +// +// Created by changgyo seo on 2022/08/30. +// + +import Foundation + +struct NaverOpenAPI { + + static let baseURL = "https://openapi.naver.com/v1" + static let searchURL = baseURL + "/search" + static let movieJsonURL = searchURL + "/movie.json" + static let ClientID = "SjK7VjRrkujvwETKupas" + static let ClientSecret = "u77U1Pv2Vt" + static let header = + [ + "X-Naver-Client-Id" : ClientID, + "X-Naver-Client-Secret" : ClientSecret + ] +} + +struct NaverOpneAPICommonResponse: Codable { + + let lastBuildDate: String + let total: Int + let start: Int + let display: Int + let items: [T] +} diff --git a/week5/NetworkModule/NetworkModule/Network/NetworkModulMoyaStyle.swift b/week5/NetworkModule/NetworkModule/Network/NetworkModulMoyaStyle.swift new file mode 100644 index 0000000..87946c6 --- /dev/null +++ b/week5/NetworkModule/NetworkModule/Network/NetworkModulMoyaStyle.swift @@ -0,0 +1,139 @@ +// +// NetworkModulMoyaStyle.swift +// NetworkModule +// +// Created by changgyo seo on 2022/09/06. +// +import Foundation + +protocol RequestType { + + var url: String { get } + var method: HttpMethod { get } + var entity: Any { get } + var parameters: Parameters? { get } + var header: [String: String]? { get } +} + +enum MovieAPI: RequestType { + + case movieRequest(parameters: [String: String]?) + + var url: String { + switch self { + case .movieRequest: + return NaverOpenAPI.movieJsonURL + } + } + + var method: HttpMethod { + switch self { + case .movieRequest: + return .get + } + } + + var entity: Any { + switch self { + case .movieRequest: + return NaverOpneAPICommonResponse.self + } + } + + var parameters: Parameters? { + switch self { + case .movieRequest(let parameters): + return .urlString(parameters ?? [:]) + } + } + + var header: [String : String]? { + switch self { + case .movieRequest: + return NaverOpenAPI.header + } + } +} + +enum Parameters { + case urlString([String: String]) + case bodyString([String: String]) +} + +struct NetworkHost { + + func request(_ request: requestAPI, completion: @escaping () -> Void) { + + let t = String.self + let k = type + var urlComponent = URLComponents(string: request.url) + var urlRequest = URLRequest(url: URL(string: request.url)!) + + + switch request.parameters { + case .urlString(let parameters): + var queryItems = [URLQueryItem]() + parameters.forEach { key, value in + queryItems.append(URLQueryItem(name: key, value: value)) + } + urlComponent?.queryItems = queryItems + urlRequest.url = urlComponent!.url + + case .bodyString(let parameters): + let paramData = try! JSONSerialization.data(withJSONObject: parameters, options: []) + urlRequest.url = URL(string: request.url) + urlRequest.httpBody = paramData + urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type") + urlRequest.setValue(String(paramData.count), forHTTPHeaderField: "Content-Length") + case .none: + break; + } + + urlRequest.httpMethod = request.method.rawValue + request.header?.forEach { urlRequest.addValue($1, forHTTPHeaderField: $0) } + + //guard let urlRequest = urlRequest else { return } + URLSession.shared.dataTask(with: urlRequest, completionHandler: { data, urlResponse, error in + + guard error == nil else { + completion() + return + } + + guard let httpURLResponse = urlResponse as? HTTPURLResponse, + let data = data else { return } + + var networkResult = type(of: request.entity) + let decoder = JSONDecoder() + guard let reponseData = try? decoder.decode(EntityType.self, from: data) + else { return } + + switch httpURLResponse.statusCode { + + case (200 ..< 300): + networkResult = .success(reponseData) + case (400 ..< 500): + networkResult = .clientError + case (300 ..< 400): + networkResult = .serverError + default: + networkResult = .error + } + + completion(networkResult) + }).resume() + } + + +} + +extension NetworkHost { + + enum NetworkResult { + + case success(T) + case serverError + case clientError + case error + } +} diff --git a/week5/NetworkModule/NetworkModule/Network/NetworkModuleAlamofireStyle.swift b/week5/NetworkModule/NetworkModule/Network/NetworkModuleAlamofireStyle.swift new file mode 100644 index 0000000..1cc25ac --- /dev/null +++ b/week5/NetworkModule/NetworkModule/Network/NetworkModuleAlamofireStyle.swift @@ -0,0 +1,132 @@ +// +// NetworkModule.swift +// NetworkModule +// +// Created by changgyo seo on 2022/08/29. +// + +import Foundation + +struct NetworkModuleAlamofireStyle { + + private init() {} + + static let shared = NetworkModuleAlamofireStyle() + + var defaultHeadr = [String: String]() + + /// fetchData๋Š” ์›ํ•˜๋Š” ์ข…๋ฅ˜์˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ œ๋„ค๋ฆญ์˜ ์ž…๋ ฅํ›„ ํ•„์š”ํ•œ prameter๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. + /// + /// - Parameters: + /// - method: HttpMethod๋ผ๋Š” ์—ด๊ฑฐํ˜•์ด๊ฑฐ, get, put, post, delete๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. + /// - url: url์€ string ํ˜•ํƒœ๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ œ๊ฑฐํ•œ ํ˜•ํƒœ์˜ url์„ ์ž…๋ ฅํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. + /// - entity: ์›ํ•˜๋Š” reposne์˜ ๋ชจ๋ธ ๊ทธ ์ค‘ naver์˜ ๊ฒฝ์šฐ items์˜ ํƒ€์ž…์„ ๊ธฐ์ž…ํ•˜๋ฉด ํ•ด๋‹น๋˜๋Š” ๋ชจ๋ธ๋กœ ํด๋กœ์ €์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด ๋ฐฉ์ถœํ•ฉ๋‹ˆ๋‹ค. + /// - paramaters: ์›ํ•˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋„ฃ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด๋•Œ. value๋Š” ๋ฐ˜๋“œ์‹œ string protocol์„ ๋”ฐ๋ผ์•ผํ•ฉ๋‹ˆ๋‹ค. + /// - header: ํ† ํฐ์ด๋‚˜ ํ•„์ˆ˜ ์š”์†Œ๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋„ฃ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. + /// - completion: ์ œ๋„ค๋ฆญ์˜ ๋„ฃ์€ ๋ชจ๋ธ์„ ๋ฐ”ํƒ•์œผ๋กœ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ณด๋‚ด์ค๋‹ˆ๋‹ค. + func fetchData(_ url: String, + entity: EntityType.Type, + httpMethod: HttpMethod, + paramaters: [String: String]? = nil, + header: [String: String]? = nil, + completion: @escaping (NetworkResult?) -> Void) { + + var urlComponent = URLComponents(string: url) + var urlRequest = URLRequest(url: URL(string: url)!) + + switch httpMethod { + case .get: + var queryItems = [URLQueryItem]() + paramaters?.forEach { key, value in + queryItems.append(URLQueryItem(name: key, value: value)) + } + urlComponent?.queryItems = queryItems + urlRequest.url = urlComponent!.url + case .post, .put, .delete: + guard let paramaters = paramaters else { return } + let paramData = try! JSONSerialization.data(withJSONObject: paramaters, options: []) + urlRequest.url = URL(string: url) + urlRequest.httpBody = paramData + urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type") + urlRequest.setValue(String(paramData.count), forHTTPHeaderField: "Content-Length") + } + + urlRequest.httpMethod = httpMethod.rawValue + header?.forEach { urlRequest.addValue($1, forHTTPHeaderField: $0) } + + //guard let urlRequest = urlRequest else { return } + URLSession.shared.dataTask(with: urlRequest, completionHandler: { data, urlResponse, error in + + guard error == nil else { + completion(.error) + return + } + + guard let httpURLResponse = urlResponse as? HTTPURLResponse, + let data = data else { return } + + var networkResult: NetworkResult? + let decoder = JSONDecoder() + guard let reponseData = try? decoder.decode(EntityType.self, from: data) + else { return } + + switch httpURLResponse.statusCode { + + case (200 ..< 300): + networkResult = .success(reponseData) + case (400 ..< 500): + networkResult = .clientError + case (300 ..< 400): + networkResult = .serverError + default: + networkResult = .error + } + + completion(networkResult) + }).resume() + } + + func makeParameter(_ parameters: [Parameter]) -> [String: String] { + + var urlParameters = [String: String]() + parameters.forEach { parameter in + urlParameters.updateValue(parameter.valueText, forKey: parameter.keyText) + } + + return urlParameters + } +} + +extension NetworkModuleAlamofireStyle { + + enum NetworkResult { + + case success(T) + case serverError + case clientError + case error + } + + struct FetchParameter { + + var url: String + var entity: T + var httpMethod: HttpMethod + var parameters: [String: String]? + var header: [String: String]? + } +} + +protocol RequestEnum { + + var keyText: String { get } + var valueText: String { get } +} + +enum HttpMethod: String { + + case get = "GET" + case post = "POST" + case put = "PUT" + case delete = "DELETE" +} diff --git a/week5/NetworkModule/NetworkModule/NetworkModuleApp.swift b/week5/NetworkModule/NetworkModule/NetworkModuleApp.swift new file mode 100644 index 0000000..2aa0dd9 --- /dev/null +++ b/week5/NetworkModule/NetworkModule/NetworkModuleApp.swift @@ -0,0 +1,20 @@ +// +// NetworkModuleApp.swift +// NetworkModule +// +// Created by changgyo seo on 2022/08/29. +// + +import SwiftUI + +@main +struct NetworkModuleApp: App { + + let movieFetcher = Finder() + var body: some Scene { + WindowGroup { + ContentView(viewModel: movieFetcher) + } + } + +} diff --git a/week5/NetworkModule/NetworkModule/Preview Content/Preview Assets.xcassets/Contents.json b/week5/NetworkModule/NetworkModule/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/week5/NetworkModule/NetworkModule/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/week5/NetworkModule/NetworkModule/View/ContentView.swift b/week5/NetworkModule/NetworkModule/View/ContentView.swift new file mode 100644 index 0000000..8833189 --- /dev/null +++ b/week5/NetworkModule/NetworkModule/View/ContentView.swift @@ -0,0 +1,37 @@ +// +// ContentView.swift +// NetworkModule +// +// Created by changgyo seo on 2022/08/29. +// + +import SwiftUI + +struct ContentView: View { + + @ObservedObject var viewModel: Finder + @State private var movieTitle: String = "" + + var body: some View { + + VStack { + Spacer() + Image(uiImage: viewModel.testResult) + .frame(width: 300, height: 500, alignment: .center) + Button { + + let parameters: [Movie.Request] = [.query(movieTitle)] + viewModel.fetchMovieList(parameterList: parameters) + } label: { + + Circle() + .foregroundColor(.blue) + .frame(width: 50, height: 50, alignment: .center) + } + TextField("", text: $movieTitle) + .border(.blue, width: 3) + .frame(width: 200, height: 70, alignment: .center) + Spacer() + } + } +} diff --git a/week5/NetworkModule/NetworkModule/ViewModel/Finder.swift b/week5/NetworkModule/NetworkModule/ViewModel/Finder.swift new file mode 100644 index 0000000..8359ff7 --- /dev/null +++ b/week5/NetworkModule/NetworkModule/ViewModel/Finder.swift @@ -0,0 +1,47 @@ +// +// MovieFinder.swift +// NetworkModule +// +// Created by changgyo seo on 2022/08/30. +// + +import UIKit + +class Finder: ObservableObject { + + @Published var movieList: [Movie]? + @Published var testResult: UIImage = UIImage(named: "tempImage")! + + func fetchMovieList(parameterList: [Movie.Request]) { + + NetworkModuleAlamofireStyle.shared.fetchData(NaverOpenAPI.movieJsonURL, + entity: NaverOpneAPICommonResponse.self, + httpMethod: .get, + paramaters: NetworkModuleAlamofireStyle.shared.makeParameter(parameterList), + header: NaverOpenAPI.header) { [weak self] response in + + guard let self = self, + let response = response else { return } + + switch response { + + case .success(let data): + DispatchQueue.main.async { [weak self] in + print(data) + guard let self = self else { return } + self.movieList = data.items + guard let data = try? Data(contentsOf: URL(string: data.items.first?.image ?? "")!), + let image = UIImage(data: data) else { return } + self.testResult = image + } + case .serverError: + print("server error") + case .clientError: + print("client error") + case .error: + print("unknown error") + } + } + } +} +