From 4ff360d44acc85093bfb39bacb3d793149da655f Mon Sep 17 00:00:00 2001 From: swg99 <87419041+swg99@users.noreply.github.com> Date: Mon, 2 Aug 2021 15:02:16 +0100 Subject: [PATCH 1/4] Implemented CharactersViewModel Built the CharactersViewModel which is injected into the CharactersView from the ContentView. --- .../Rick And Morty.xcodeproj/project.pbxproj | 12 +++++ .../ViewModels/CharactersViewModel.swift | 48 +++++++++++++++++++ .../Rick And Morty/Views/CharactersView.swift | 16 +++---- .../Rick And Morty/Views/ContentView.swift | 4 +- 4 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 Rick-and-Morty/Rick And Morty/ViewModels/CharactersViewModel.swift diff --git a/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj b/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj index 0bc78fd..7e78bae 100644 --- a/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj +++ b/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 1711B39C26B16D6200BE935B /* CharactersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1711B39B26B16D6200BE935B /* CharactersView.swift */; }; 1711B39E26B1898100BE935B /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1711B39D26B1898100BE935B /* ContentView.swift */; }; 171752C126B3FD50007B1A60 /* CharacterDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171752C026B3FD50007B1A60 /* CharacterDetailView.swift */; }; + 171FE19626B8251000D31075 /* CharactersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171FE19526B8251000D31075 /* CharactersViewModel.swift */; }; 17CAB4FA26A824470048F2F1 /* CharacterCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17CAB4F926A824470048F2F1 /* CharacterCell.swift */; }; 17F1E38626A1AF6A009C1CDB /* Character.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17F1E38526A1AF6A009C1CDB /* Character.swift */; }; 17F1E38D26A1DCF0009C1CDB /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17F1E38C26A1DCF0009C1CDB /* Data.swift */; }; @@ -35,6 +36,7 @@ 1711B39B26B16D6200BE935B /* CharactersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharactersView.swift; sourceTree = ""; }; 1711B39D26B1898100BE935B /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 171752C026B3FD50007B1A60 /* CharacterDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterDetailView.swift; sourceTree = ""; }; + 171FE19526B8251000D31075 /* CharactersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharactersViewModel.swift; sourceTree = ""; }; 17CAB4F926A824470048F2F1 /* CharacterCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCell.swift; sourceTree = ""; }; 17F1E38526A1AF6A009C1CDB /* Character.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Character.swift; sourceTree = ""; }; 17F1E38C26A1DCF0009C1CDB /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = ""; }; @@ -68,6 +70,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 171FE19426B8233600D31075 /* ViewModels */ = { + isa = PBXGroup; + children = ( + 171FE19526B8251000D31075 /* CharactersViewModel.swift */, + ); + path = ViewModels; + sourceTree = ""; + }; 17F1E38026A184F3009C1CDB /* Models */ = { isa = PBXGroup; children = ( @@ -111,6 +121,7 @@ B811686B1CFF1C9900301A0A /* Rick And Morty */ = { isa = PBXGroup; children = ( + 171FE19426B8233600D31075 /* ViewModels */, 17F1E38E26A5724A009C1CDB /* Views */, 17F1E38026A184F3009C1CDB /* Models */, B811686C1CFF1C9900301A0A /* AppDelegate.swift */, @@ -238,6 +249,7 @@ 17F1E38D26A1DCF0009C1CDB /* Data.swift in Sources */, 1711B39E26B1898100BE935B /* ContentView.swift in Sources */, B811686D1CFF1C9900301A0A /* AppDelegate.swift in Sources */, + 171FE19626B8251000D31075 /* CharactersViewModel.swift in Sources */, 17CAB4FA26A824470048F2F1 /* CharacterCell.swift in Sources */, B81168931CFF234900301A0A /* Rick.swift in Sources */, 1711B39C26B16D6200BE935B /* CharactersView.swift in Sources */, diff --git a/Rick-and-Morty/Rick And Morty/ViewModels/CharactersViewModel.swift b/Rick-and-Morty/Rick And Morty/ViewModels/CharactersViewModel.swift new file mode 100644 index 0000000..bce18f8 --- /dev/null +++ b/Rick-and-Morty/Rick And Morty/ViewModels/CharactersViewModel.swift @@ -0,0 +1,48 @@ +import Foundation + +final class CharactersViewModel: ObservableObject { + let characterType: CharacterType + + @Published var characters: [Character] = [] + var title: String = "" + var imagePosition: CharacterImagePosition = .right + + init(characterType: CharacterType) { + self.characterType = characterType + self.title = getTitle() + self.imagePosition = getImagePosition() + + fetchCharacters() + } + + private func fetchCharacters() { + if characterType == .rick { + characters = ricks + } else { + characters = morties + } + } + + private func getTitle() -> String { + if characterType == .rick { + return "Ricks" + } else { + return "Morties" + } + } + + private func getImagePosition() -> CharacterImagePosition { + if characterType == .rick { + return .right + } else { + return .left + } + } +} + +extension CharactersViewModel { + enum CharacterType { + case rick + case morty + } +} diff --git a/Rick-and-Morty/Rick And Morty/Views/CharactersView.swift b/Rick-and-Morty/Rick And Morty/Views/CharactersView.swift index a4bbf3a..196cf08 100644 --- a/Rick-and-Morty/Rick And Morty/Views/CharactersView.swift +++ b/Rick-and-Morty/Rick And Morty/Views/CharactersView.swift @@ -1,30 +1,26 @@ import SwiftUI struct CharactersView: View { - let characters: [Character] - let title: String + @ObservedObject var viewModel: CharactersViewModel var body: some View { NavigationView { ScrollView(.vertical) { VStack(alignment: .leading) { - ForEach(characters, id: \.id) { character in - CharacterCell(character: character, imagePosition: getImagePosition(character: character)) + ForEach(viewModel.characters, id: \.id) { character in + CharacterCell(character: character, imagePosition: viewModel.imagePosition) .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 120) } } } - .navigationBarTitle(title) + .navigationBarTitle(viewModel.title) } } - - func getImagePosition(character: Character) -> CharacterImagePosition { - character is Rick ? .right : .left - } } struct CharactersView_Previews: PreviewProvider { static var previews: some View { - CharactersView(characters: ricks, title: "Ricks") + CharactersView(viewModel: CharactersViewModel(characterType: .rick)) + CharactersView(viewModel: CharactersViewModel(characterType: .morty)) } } diff --git a/Rick-and-Morty/Rick And Morty/Views/ContentView.swift b/Rick-and-Morty/Rick And Morty/Views/ContentView.swift index 3501bbe..49412b1 100644 --- a/Rick-and-Morty/Rick And Morty/Views/ContentView.swift +++ b/Rick-and-Morty/Rick And Morty/Views/ContentView.swift @@ -12,11 +12,11 @@ struct ContentView: View { var body: some View { TabView { - CharactersView(characters: ricks, title: "Ricks") + CharactersView(viewModel: CharactersViewModel(characterType: .rick)) .tabItem { Label("Ricks", image: "rick-icon") } - CharactersView(characters: morties, title: "Morties") + CharactersView(viewModel: CharactersViewModel(characterType: .morty)) .tabItem { Label("Morties", image: "morty-icon") } From b0afe667d12242b89feb146b5f979f9d89f1a185 Mon Sep 17 00:00:00 2001 From: swg99 <87419041+swg99@users.noreply.github.com> Date: Wed, 4 Aug 2021 15:46:39 +0100 Subject: [PATCH 2/4] Created ContentViewModel ContentViewModel is now used instead of CharactersViewModel. The ContentViewModel produces CharactersViewStates. The ContentViewModel follows the open-closed principal, however the CharactersManager, CharacterViewStateFactory and CharactersViewStateFactory do not. All these classes and struct will need to be refactored into different files, as of now the ViewState structs, factory classes and CharactersManager are all in the ContentViewModel file. --- .../Rick And Morty.xcodeproj/project.pbxproj | 4 + .../ViewModels/CharactersViewModel.swift | 22 +--- .../ViewModels/ContentViewModel.swift | 112 ++++++++++++++++++ .../Rick And Morty/Views/CharacterCell.swift | 25 ++-- .../Rick And Morty/Views/CharactersView.swift | 14 ++- .../Rick And Morty/Views/ContentView.swift | 15 ++- 6 files changed, 148 insertions(+), 44 deletions(-) create mode 100644 Rick-and-Morty/Rick And Morty/ViewModels/ContentViewModel.swift diff --git a/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj b/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj index 7e78bae..7b136cb 100644 --- a/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj +++ b/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 1711B39E26B1898100BE935B /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1711B39D26B1898100BE935B /* ContentView.swift */; }; 171752C126B3FD50007B1A60 /* CharacterDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171752C026B3FD50007B1A60 /* CharacterDetailView.swift */; }; 171FE19626B8251000D31075 /* CharactersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171FE19526B8251000D31075 /* CharactersViewModel.swift */; }; + 178A555626BACB2A00D25282 /* ContentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 178A555526BACB2A00D25282 /* ContentViewModel.swift */; }; 17CAB4FA26A824470048F2F1 /* CharacterCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17CAB4F926A824470048F2F1 /* CharacterCell.swift */; }; 17F1E38626A1AF6A009C1CDB /* Character.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17F1E38526A1AF6A009C1CDB /* Character.swift */; }; 17F1E38D26A1DCF0009C1CDB /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17F1E38C26A1DCF0009C1CDB /* Data.swift */; }; @@ -37,6 +38,7 @@ 1711B39D26B1898100BE935B /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 171752C026B3FD50007B1A60 /* CharacterDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterDetailView.swift; sourceTree = ""; }; 171FE19526B8251000D31075 /* CharactersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharactersViewModel.swift; sourceTree = ""; }; + 178A555526BACB2A00D25282 /* ContentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentViewModel.swift; sourceTree = ""; }; 17CAB4F926A824470048F2F1 /* CharacterCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCell.swift; sourceTree = ""; }; 17F1E38526A1AF6A009C1CDB /* Character.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Character.swift; sourceTree = ""; }; 17F1E38C26A1DCF0009C1CDB /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = ""; }; @@ -74,6 +76,7 @@ isa = PBXGroup; children = ( 171FE19526B8251000D31075 /* CharactersViewModel.swift */, + 178A555526BACB2A00D25282 /* ContentViewModel.swift */, ); path = ViewModels; sourceTree = ""; @@ -252,6 +255,7 @@ 171FE19626B8251000D31075 /* CharactersViewModel.swift in Sources */, 17CAB4FA26A824470048F2F1 /* CharacterCell.swift in Sources */, B81168931CFF234900301A0A /* Rick.swift in Sources */, + 178A555626BACB2A00D25282 /* ContentViewModel.swift in Sources */, 1711B39C26B16D6200BE935B /* CharactersView.swift in Sources */, 17F1E38626A1AF6A009C1CDB /* Character.swift in Sources */, B81168951CFF235600301A0A /* Morty.swift in Sources */, diff --git a/Rick-and-Morty/Rick And Morty/ViewModels/CharactersViewModel.swift b/Rick-and-Morty/Rick And Morty/ViewModels/CharactersViewModel.swift index bce18f8..54ed847 100644 --- a/Rick-and-Morty/Rick And Morty/ViewModels/CharactersViewModel.swift +++ b/Rick-and-Morty/Rick And Morty/ViewModels/CharactersViewModel.swift @@ -12,31 +12,19 @@ final class CharactersViewModel: ObservableObject { self.title = getTitle() self.imagePosition = getImagePosition() - fetchCharacters() + self.characters = fetchCharacters() } - private func fetchCharacters() { - if characterType == .rick { - characters = ricks - } else { - characters = morties - } + private func fetchCharacters() -> [Character] { + return characterType == .rick ? ricks : morties } private func getTitle() -> String { - if characterType == .rick { - return "Ricks" - } else { - return "Morties" - } + return characterType == .rick ? "Ricks" : "Morties" } private func getImagePosition() -> CharacterImagePosition { - if characterType == .rick { - return .right - } else { - return .left - } + return characterType == .rick ? .right : .left } } diff --git a/Rick-and-Morty/Rick And Morty/ViewModels/ContentViewModel.swift b/Rick-and-Morty/Rick And Morty/ViewModels/ContentViewModel.swift new file mode 100644 index 0000000..a0431d6 --- /dev/null +++ b/Rick-and-Morty/Rick And Morty/ViewModels/ContentViewModel.swift @@ -0,0 +1,112 @@ +import Foundation + +final class ContentViewModel: ObservableObject { + @Published var charatersViewStates: [CharactersViewState] = [] + + private let charactersManager = CharactersManager() + private let characterViewStateFactory = CharacterViewStateFactory() + private let charactersViewStateFactory = CharactersViewStateFactory() + + init() { + self.charatersViewStates = getCharactersViewStates() + } + + private func getCharactersViewStates() -> [CharactersViewState] { + var charactersViewStates: [CharactersViewState] = [] + + for characterType in CharacterType.allCases { + let characters = charactersManager.fetchCharacters(characterType: characterType) + let characterViewStates = getCharacterViewStates(from: characters) + + let charactersViewState = charactersViewStateFactory.createCharactersViewState(characterType: characterType, characterViewStates: characterViewStates) + + charactersViewStates.append(charactersViewState) + } + + return charactersViewStates + } + + private func getCharacterViewStates(from characters: [Character]) -> [CharacterViewState] { + var characterViewStates: [CharacterViewState] = [] + + for character in characters { + let characterViewState = characterViewStateFactory.createViewState(from: character) + characterViewStates.append(characterViewState) + } + + return characterViewStates + } +} + + +final class CharactersManager { + func fetchCharacters(characterType: CharacterType) -> [Character] { + return characterType == .rick ? ricks : morties + } +} + +final class CharacterViewStateFactory { + func createViewState(from character: Character) -> CharacterViewState { + let shortDescription = getShortDescription(for: character) + let imagePosition = getImagePosition(for: character) + + return CharacterViewState(name: character.name, description: character.description, shortDescription: shortDescription, imageName: character.image, imagePosition: imagePosition) + } + + private func getShortDescription(for character: Character) -> String? { + if let character = character as? Morty { + return character.shortDescription + } + + return nil + } + + private func getImagePosition(for character: Character) -> CharacterImagePosition { + if character is Morty { + return .left + } else { + return .right + } + } +} + + + +final class CharactersViewStateFactory { + func createCharactersViewState(characterType: CharacterType, characterViewStates: [CharacterViewState]) -> CharactersViewState { + let title = getTitle(for: characterType) + let iconName = getIconName(for: characterType) + + return CharactersViewState(title: title, iconName: iconName, characterViewStates: characterViewStates) + } + + private func getTitle(for characterType: CharacterType) -> String { + return characterType == .rick ? "Ricks" : "Morties" + } + + private func getIconName(for characterType: CharacterType) -> String { + return characterType == .rick ? "rick-icon" : "morty-icon" + } +} + + +struct CharactersViewState: Identifiable { + let id = UUID() + let title: String + let iconName: String + let characterViewStates: [CharacterViewState] +} + +struct CharacterViewState: Identifiable { + let id = UUID() + let name: String + let description: String + let shortDescription: String? + let imageName: String + let imagePosition: CharacterImagePosition +} + +enum CharacterType: CaseIterable { + case rick + case morty +} diff --git a/Rick-and-Morty/Rick And Morty/Views/CharacterCell.swift b/Rick-and-Morty/Rick And Morty/Views/CharacterCell.swift index c48844b..fd2004c 100644 --- a/Rick-and-Morty/Rick And Morty/Views/CharacterCell.swift +++ b/Rick-and-Morty/Rick And Morty/Views/CharacterCell.swift @@ -14,23 +14,21 @@ enum CharacterImagePosition { } struct CharacterCell: View { - let character: Character - let imagePosition: CharacterImagePosition + let characterViewState: CharacterViewState var body: some View { HStack(spacing: 8) { - // left handside images for morties - if imagePosition == .left { - CharacterCellImage(character: character) + if characterViewState.imagePosition == .left { + CharacterCellImage(imageName: characterViewState.imageName) } VStack(alignment: .leading, spacing: 8) { - Text(character.name) - Text(character.description) + Text(characterViewState.name) + Text(characterViewState.description) } - // right handside images for ricks - if imagePosition == .right { - CharacterCellImage(character: character) + + if characterViewState.imagePosition == .right { + CharacterCellImage(imageName: characterViewState.imageName) } } .padding() @@ -38,18 +36,19 @@ struct CharacterCell: View { } struct CharacterCellImage: View { - let character: Character + let imageName: String var body: some View { - Image(character.image) + Image(imageName) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 70, height: 70) } } - +/* struct CharacterCell_Previews: PreviewProvider { static var previews: some View { CharacterCell(character: ricks[0], imagePosition: .left) } } +*/ diff --git a/Rick-and-Morty/Rick And Morty/Views/CharactersView.swift b/Rick-and-Morty/Rick And Morty/Views/CharactersView.swift index 196cf08..42f48da 100644 --- a/Rick-and-Morty/Rick And Morty/Views/CharactersView.swift +++ b/Rick-and-Morty/Rick And Morty/Views/CharactersView.swift @@ -1,26 +1,28 @@ import SwiftUI struct CharactersView: View { - @ObservedObject var viewModel: CharactersViewModel + let charactersViewState: CharactersViewState var body: some View { NavigationView { ScrollView(.vertical) { VStack(alignment: .leading) { - ForEach(viewModel.characters, id: \.id) { character in - CharacterCell(character: character, imagePosition: viewModel.imagePosition) + ForEach(charactersViewState.characterViewStates) { characterViewState in + CharacterCell(characterViewState: characterViewState) .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 120) } } } - .navigationBarTitle(viewModel.title) + .navigationBarTitle(charactersViewState.title) } } } +/* struct CharactersView_Previews: PreviewProvider { static var previews: some View { - CharactersView(viewModel: CharactersViewModel(characterType: .rick)) - CharactersView(viewModel: CharactersViewModel(characterType: .morty)) + //CharactersView(viewModel: CharactersViewModel(characterType: .rick)) + //CharactersView(viewModel: CharactersViewModel(characterType: .morty)) } } +*/ diff --git a/Rick-and-Morty/Rick And Morty/Views/ContentView.swift b/Rick-and-Morty/Rick And Morty/Views/ContentView.swift index 49412b1..865dd67 100644 --- a/Rick-and-Morty/Rick And Morty/Views/ContentView.swift +++ b/Rick-and-Morty/Rick And Morty/Views/ContentView.swift @@ -9,17 +9,16 @@ import SwiftUI struct ContentView: View { + @ObservedObject var contentViewModel = ContentViewModel() var body: some View { TabView { - CharactersView(viewModel: CharactersViewModel(characterType: .rick)) - .tabItem { - Label("Ricks", image: "rick-icon") - } - CharactersView(viewModel: CharactersViewModel(characterType: .morty)) - .tabItem { - Label("Morties", image: "morty-icon") - } + ForEach(contentViewModel.charatersViewStates) { charactersViewState in + CharactersView(charactersViewState: charactersViewState) + .tabItem { + Label(charactersViewState.title, image: charactersViewState.iconName) + } + } } } } From 96f8de819a1952d52d7177d741eb3dc174400441 Mon Sep 17 00:00:00 2001 From: swg99 <87419041+swg99@users.noreply.github.com> Date: Thu, 5 Aug 2021 11:06:49 +0100 Subject: [PATCH 3/4] Refactored ContentViewModel file Moved factories into a dedicated folder and moved CharactersManager into misc folder. --- .../Rick And Morty.xcodeproj/project.pbxproj | 28 ++++++++++ .../Factories/CharacterViewStateFactory.swift | 26 +++++++++ .../CharactersViewStateFactory.swift | 18 +++++++ .../ViewModels/ContentViewModel.swift | 54 +------------------ .../misc/CharactersManager.swift | 7 +++ 5 files changed, 80 insertions(+), 53 deletions(-) create mode 100644 Rick-and-Morty/Rick And Morty/Factories/CharacterViewStateFactory.swift create mode 100644 Rick-and-Morty/Rick And Morty/Factories/CharactersViewStateFactory.swift create mode 100644 Rick-and-Morty/Rick And Morty/misc/CharactersManager.swift diff --git a/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj b/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj index 7b136cb..7a64722 100644 --- a/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj +++ b/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj @@ -11,6 +11,9 @@ 1711B39E26B1898100BE935B /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1711B39D26B1898100BE935B /* ContentView.swift */; }; 171752C126B3FD50007B1A60 /* CharacterDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171752C026B3FD50007B1A60 /* CharacterDetailView.swift */; }; 171FE19626B8251000D31075 /* CharactersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171FE19526B8251000D31075 /* CharactersViewModel.swift */; }; + 1758BFE226BBEEB900C18BC2 /* CharacterViewStateFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1758BFE126BBEEB900C18BC2 /* CharacterViewStateFactory.swift */; }; + 1758BFE426BBEECC00C18BC2 /* CharactersViewStateFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1758BFE326BBEECC00C18BC2 /* CharactersViewStateFactory.swift */; }; + 1758BFE726BBEF2C00C18BC2 /* CharactersManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1758BFE626BBEF2C00C18BC2 /* CharactersManager.swift */; }; 178A555626BACB2A00D25282 /* ContentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 178A555526BACB2A00D25282 /* ContentViewModel.swift */; }; 17CAB4FA26A824470048F2F1 /* CharacterCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17CAB4F926A824470048F2F1 /* CharacterCell.swift */; }; 17F1E38626A1AF6A009C1CDB /* Character.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17F1E38526A1AF6A009C1CDB /* Character.swift */; }; @@ -38,6 +41,9 @@ 1711B39D26B1898100BE935B /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 171752C026B3FD50007B1A60 /* CharacterDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterDetailView.swift; sourceTree = ""; }; 171FE19526B8251000D31075 /* CharactersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharactersViewModel.swift; sourceTree = ""; }; + 1758BFE126BBEEB900C18BC2 /* CharacterViewStateFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterViewStateFactory.swift; sourceTree = ""; }; + 1758BFE326BBEECC00C18BC2 /* CharactersViewStateFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharactersViewStateFactory.swift; sourceTree = ""; }; + 1758BFE626BBEF2C00C18BC2 /* CharactersManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharactersManager.swift; sourceTree = ""; }; 178A555526BACB2A00D25282 /* ContentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentViewModel.swift; sourceTree = ""; }; 17CAB4F926A824470048F2F1 /* CharacterCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCell.swift; sourceTree = ""; }; 17F1E38526A1AF6A009C1CDB /* Character.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Character.swift; sourceTree = ""; }; @@ -81,6 +87,23 @@ path = ViewModels; sourceTree = ""; }; + 1758BFE026BBEE7D00C18BC2 /* Factories */ = { + isa = PBXGroup; + children = ( + 1758BFE126BBEEB900C18BC2 /* CharacterViewStateFactory.swift */, + 1758BFE326BBEECC00C18BC2 /* CharactersViewStateFactory.swift */, + ); + path = Factories; + sourceTree = ""; + }; + 1758BFE526BBEF1700C18BC2 /* misc */ = { + isa = PBXGroup; + children = ( + 1758BFE626BBEF2C00C18BC2 /* CharactersManager.swift */, + ); + path = misc; + sourceTree = ""; + }; 17F1E38026A184F3009C1CDB /* Models */ = { isa = PBXGroup; children = ( @@ -127,6 +150,8 @@ 171FE19426B8233600D31075 /* ViewModels */, 17F1E38E26A5724A009C1CDB /* Views */, 17F1E38026A184F3009C1CDB /* Models */, + 1758BFE026BBEE7D00C18BC2 /* Factories */, + 1758BFE526BBEF1700C18BC2 /* misc */, B811686C1CFF1C9900301A0A /* AppDelegate.swift */, B81168751CFF1C9900301A0A /* Assets.xcassets */, B81168771CFF1C9900301A0A /* LaunchScreen.storyboard */, @@ -249,16 +274,19 @@ buildActionMask = 2147483647; files = ( 171752C126B3FD50007B1A60 /* CharacterDetailView.swift in Sources */, + 1758BFE726BBEF2C00C18BC2 /* CharactersManager.swift in Sources */, 17F1E38D26A1DCF0009C1CDB /* Data.swift in Sources */, 1711B39E26B1898100BE935B /* ContentView.swift in Sources */, B811686D1CFF1C9900301A0A /* AppDelegate.swift in Sources */, 171FE19626B8251000D31075 /* CharactersViewModel.swift in Sources */, 17CAB4FA26A824470048F2F1 /* CharacterCell.swift in Sources */, B81168931CFF234900301A0A /* Rick.swift in Sources */, + 1758BFE426BBEECC00C18BC2 /* CharactersViewStateFactory.swift in Sources */, 178A555626BACB2A00D25282 /* ContentViewModel.swift in Sources */, 1711B39C26B16D6200BE935B /* CharactersView.swift in Sources */, 17F1E38626A1AF6A009C1CDB /* Character.swift in Sources */, B81168951CFF235600301A0A /* Morty.swift in Sources */, + 1758BFE226BBEEB900C18BC2 /* CharacterViewStateFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Rick-and-Morty/Rick And Morty/Factories/CharacterViewStateFactory.swift b/Rick-and-Morty/Rick And Morty/Factories/CharacterViewStateFactory.swift new file mode 100644 index 0000000..ff0084c --- /dev/null +++ b/Rick-and-Morty/Rick And Morty/Factories/CharacterViewStateFactory.swift @@ -0,0 +1,26 @@ +import Foundation + +final class CharacterViewStateFactory { + func createCharacterViewState(from character: Character) -> CharacterViewState { + let shortDescription = getShortDescription(for: character) + let imagePosition = getImagePosition(for: character) + + return CharacterViewState(name: character.name, description: character.description, shortDescription: shortDescription, imageName: character.image, imagePosition: imagePosition) + } + + private func getShortDescription(for character: Character) -> String? { + if let character = character as? Morty { + return character.shortDescription + } + + return nil + } + + private func getImagePosition(for character: Character) -> CharacterImagePosition { + if character is Morty { + return .left + } else { + return .right + } + } +} diff --git a/Rick-and-Morty/Rick And Morty/Factories/CharactersViewStateFactory.swift b/Rick-and-Morty/Rick And Morty/Factories/CharactersViewStateFactory.swift new file mode 100644 index 0000000..067f102 --- /dev/null +++ b/Rick-and-Morty/Rick And Morty/Factories/CharactersViewStateFactory.swift @@ -0,0 +1,18 @@ +import Foundation + +final class CharactersViewStateFactory { + func createCharactersViewState(characterType: CharacterType, characterViewStates: [CharacterViewState]) -> CharactersViewState { + let title = getTitle(for: characterType) + let iconName = getIconName(for: characterType) + + return CharactersViewState(title: title, iconName: iconName, characterViewStates: characterViewStates) + } + + private func getTitle(for characterType: CharacterType) -> String { + return characterType == .rick ? "Ricks" : "Morties" + } + + private func getIconName(for characterType: CharacterType) -> String { + return characterType == .rick ? "rick-icon" : "morty-icon" + } +} diff --git a/Rick-and-Morty/Rick And Morty/ViewModels/ContentViewModel.swift b/Rick-and-Morty/Rick And Morty/ViewModels/ContentViewModel.swift index a0431d6..a6416a7 100644 --- a/Rick-and-Morty/Rick And Morty/ViewModels/ContentViewModel.swift +++ b/Rick-and-Morty/Rick And Morty/ViewModels/ContentViewModel.swift @@ -30,7 +30,7 @@ final class ContentViewModel: ObservableObject { var characterViewStates: [CharacterViewState] = [] for character in characters { - let characterViewState = characterViewStateFactory.createViewState(from: character) + let characterViewState = characterViewStateFactory.createCharacterViewState(from: character) characterViewStates.append(characterViewState) } @@ -38,58 +38,6 @@ final class ContentViewModel: ObservableObject { } } - -final class CharactersManager { - func fetchCharacters(characterType: CharacterType) -> [Character] { - return characterType == .rick ? ricks : morties - } -} - -final class CharacterViewStateFactory { - func createViewState(from character: Character) -> CharacterViewState { - let shortDescription = getShortDescription(for: character) - let imagePosition = getImagePosition(for: character) - - return CharacterViewState(name: character.name, description: character.description, shortDescription: shortDescription, imageName: character.image, imagePosition: imagePosition) - } - - private func getShortDescription(for character: Character) -> String? { - if let character = character as? Morty { - return character.shortDescription - } - - return nil - } - - private func getImagePosition(for character: Character) -> CharacterImagePosition { - if character is Morty { - return .left - } else { - return .right - } - } -} - - - -final class CharactersViewStateFactory { - func createCharactersViewState(characterType: CharacterType, characterViewStates: [CharacterViewState]) -> CharactersViewState { - let title = getTitle(for: characterType) - let iconName = getIconName(for: characterType) - - return CharactersViewState(title: title, iconName: iconName, characterViewStates: characterViewStates) - } - - private func getTitle(for characterType: CharacterType) -> String { - return characterType == .rick ? "Ricks" : "Morties" - } - - private func getIconName(for characterType: CharacterType) -> String { - return characterType == .rick ? "rick-icon" : "morty-icon" - } -} - - struct CharactersViewState: Identifiable { let id = UUID() let title: String diff --git a/Rick-and-Morty/Rick And Morty/misc/CharactersManager.swift b/Rick-and-Morty/Rick And Morty/misc/CharactersManager.swift new file mode 100644 index 0000000..58f5bcf --- /dev/null +++ b/Rick-and-Morty/Rick And Morty/misc/CharactersManager.swift @@ -0,0 +1,7 @@ +import Foundation + +final class CharactersManager { + func fetchCharacters(characterType: CharacterType) -> [Character] { + return characterType == .rick ? ricks : morties + } +} From 29899cd80f71d42a9add55b970ace8e444a84023 Mon Sep 17 00:00:00 2001 From: swg99 <87419041+swg99@users.noreply.github.com> Date: Mon, 9 Aug 2021 14:27:03 +0100 Subject: [PATCH 4/4] Refactored characterviewstate --- .../Factories/CharacterViewStateFactory.swift | 2 +- .../Rick And Morty/ViewModels/ContentViewModel.swift | 1 + Rick-and-Morty/Rick And Morty/Views/CharacterCell.swift | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Rick-and-Morty/Rick And Morty/Factories/CharacterViewStateFactory.swift b/Rick-and-Morty/Rick And Morty/Factories/CharacterViewStateFactory.swift index ff0084c..79e719f 100644 --- a/Rick-and-Morty/Rick And Morty/Factories/CharacterViewStateFactory.swift +++ b/Rick-and-Morty/Rick And Morty/Factories/CharacterViewStateFactory.swift @@ -5,7 +5,7 @@ final class CharacterViewStateFactory { let shortDescription = getShortDescription(for: character) let imagePosition = getImagePosition(for: character) - return CharacterViewState(name: character.name, description: character.description, shortDescription: shortDescription, imageName: character.image, imagePosition: imagePosition) + return CharacterViewState(character: character, name: character.name, description: character.description, shortDescription: shortDescription, imageName: character.image, imagePosition: imagePosition) } private func getShortDescription(for character: Character) -> String? { diff --git a/Rick-and-Morty/Rick And Morty/ViewModels/ContentViewModel.swift b/Rick-and-Morty/Rick And Morty/ViewModels/ContentViewModel.swift index a6416a7..2fe0437 100644 --- a/Rick-and-Morty/Rick And Morty/ViewModels/ContentViewModel.swift +++ b/Rick-and-Morty/Rick And Morty/ViewModels/ContentViewModel.swift @@ -47,6 +47,7 @@ struct CharactersViewState: Identifiable { struct CharacterViewState: Identifiable { let id = UUID() + let character: Character let name: String let description: String let shortDescription: String? diff --git a/Rick-and-Morty/Rick And Morty/Views/CharacterCell.swift b/Rick-and-Morty/Rick And Morty/Views/CharacterCell.swift index fd2004c..93351e9 100644 --- a/Rick-and-Morty/Rick And Morty/Views/CharacterCell.swift +++ b/Rick-and-Morty/Rick And Morty/Views/CharacterCell.swift @@ -19,16 +19,16 @@ struct CharacterCell: View { var body: some View { HStack(spacing: 8) { if characterViewState.imagePosition == .left { - CharacterCellImage(imageName: characterViewState.imageName) + CharacterCellImage(imageName: characterViewState.character.image) } VStack(alignment: .leading, spacing: 8) { - Text(characterViewState.name) - Text(characterViewState.description) + Text(characterViewState.character.name) + Text(characterViewState.character.description) } if characterViewState.imagePosition == .right { - CharacterCellImage(imageName: characterViewState.imageName) + CharacterCellImage(imageName: characterViewState.character.image) } } .padding()