Skip to content

Commit

Permalink
Adding PokemonWorld
Browse files Browse the repository at this point in the history
  • Loading branch information
xramos committed May 27, 2022
1 parent 0e10364 commit f44e6be
Show file tree
Hide file tree
Showing 7 changed files with 436 additions and 3 deletions.
90 changes: 88 additions & 2 deletions Pokemon/Pokemon.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
DAD0D38B2840C7C600436272 /* SavePokemonUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D38A2840C7C600436272 /* SavePokemonUseCase.swift */; };
DAD0D38D2840C7FE00436272 /* ExistsPokemonUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D38C2840C7FE00436272 /* ExistsPokemonUseCase.swift */; };
DAD0D38F2840C83100436272 /* GetPokemonsUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D38E2840C83100436272 /* GetPokemonsUseCase.swift */; };
DAD0D3982840CC6400436272 /* PokemonWorldViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D3972840CC6400436272 /* PokemonWorldViewModel.swift */; };
DAD0D39A2840CC7800436272 /* PokemonWorldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D3992840CC7800436272 /* PokemonWorldView.swift */; };
DAE242F02840D33E00AD4FE1 /* PokemonWorldViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE242EF2840D33E00AD4FE1 /* PokemonWorldViewState.swift */; };
DAE242F42840DA5600AD4FE1 /* ButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE242F32840DA5600AD4FE1 /* ButtonView.swift */; };
DAE242F82840DD0D00AD4FE1 /* PokemonCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE242F72840DD0D00AD4FE1 /* PokemonCardView.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -90,6 +95,12 @@
DAD0D38A2840C7C600436272 /* SavePokemonUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavePokemonUseCase.swift; sourceTree = "<group>"; };
DAD0D38C2840C7FE00436272 /* ExistsPokemonUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExistsPokemonUseCase.swift; sourceTree = "<group>"; };
DAD0D38E2840C83100436272 /* GetPokemonsUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetPokemonsUseCase.swift; sourceTree = "<group>"; };
DAD0D3942840CC2900436272 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
DAD0D3972840CC6400436272 /* PokemonWorldViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokemonWorldViewModel.swift; sourceTree = "<group>"; };
DAD0D3992840CC7800436272 /* PokemonWorldView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokemonWorldView.swift; sourceTree = "<group>"; };
DAE242EF2840D33E00AD4FE1 /* PokemonWorldViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokemonWorldViewState.swift; sourceTree = "<group>"; };
DAE242F32840DA5600AD4FE1 /* ButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonView.swift; sourceTree = "<group>"; };
DAE242F72840DD0D00AD4FE1 /* PokemonCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokemonCardView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -140,6 +151,8 @@
DAD0D31A283FC74100436272 /* Pokemon */ = {
isa = PBXGroup;
children = (
DAE242F12840DA4500AD4FE1 /* Views */,
DAD0D3942840CC2900436272 /* Info.plist */,
DAD0D37D2840BE7300436272 /* Extensions */,
DAD0D354283FCD2B00436272 /* API */,
DAD0D35A283FCD2B00436272 /* DataBase */,
Expand Down Expand Up @@ -264,6 +277,10 @@
DAD0D35B283FCD2B00436272 /* Scenes */ = {
isa = PBXGroup;
children = (
DAD0D3902840C92200436272 /* Backpack */,
DAD0D3922840C92200436272 /* PokemonDetail */,
DAD0D3912840C92200436272 /* PokemonWorld */,
DAD0D3932840C92200436272 /* TabBar */,
);
path = Scenes;
sourceTree = "<group>";
Expand All @@ -276,6 +293,70 @@
path = Extensions;
sourceTree = "<group>";
};
DAD0D3902840C92200436272 /* Backpack */ = {
isa = PBXGroup;
children = (
);
path = Backpack;
sourceTree = "<group>";
};
DAD0D3912840C92200436272 /* PokemonWorld */ = {
isa = PBXGroup;
children = (
DAD0D3972840CC6400436272 /* PokemonWorldViewModel.swift */,
DAD0D3992840CC7800436272 /* PokemonWorldView.swift */,
DAE242EF2840D33E00AD4FE1 /* PokemonWorldViewState.swift */,
);
path = PokemonWorld;
sourceTree = "<group>";
};
DAD0D3922840C92200436272 /* PokemonDetail */ = {
isa = PBXGroup;
children = (
);
path = PokemonDetail;
sourceTree = "<group>";
};
DAD0D3932840C92200436272 /* TabBar */ = {
isa = PBXGroup;
children = (
);
path = TabBar;
sourceTree = "<group>";
};
DAE242F12840DA4500AD4FE1 /* Views */ = {
isa = PBXGroup;
children = (
DAE242F52840DD0200AD4FE1 /* BackPackCardView */,
DAE242F62840DD0200AD4FE1 /* PokemonCardView */,
DAE242F22840DA4500AD4FE1 /* ButtonView */,
);
path = Views;
sourceTree = "<group>";
};
DAE242F22840DA4500AD4FE1 /* ButtonView */ = {
isa = PBXGroup;
children = (
DAE242F32840DA5600AD4FE1 /* ButtonView.swift */,
);
path = ButtonView;
sourceTree = "<group>";
};
DAE242F52840DD0200AD4FE1 /* BackPackCardView */ = {
isa = PBXGroup;
children = (
);
path = BackPackCardView;
sourceTree = "<group>";
};
DAE242F62840DD0200AD4FE1 /* PokemonCardView */ = {
isa = PBXGroup;
children = (
DAE242F72840DD0D00AD4FE1 /* PokemonCardView.swift */,
);
path = PokemonCardView;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -410,10 +491,13 @@
DAD0D3782840B7A000436272 /* ServerSprite.swift in Sources */,
DAD0D37F2840BEAA00436272 /* DateFormatter+Pokemon.swift in Sources */,
DAD0D36D283FD40100436272 /* HTTPError.swift in Sources */,
DAD0D3982840CC6400436272 /* PokemonWorldViewModel.swift in Sources */,
DAE242F42840DA5600AD4FE1 /* ButtonView.swift in Sources */,
DAD0D3852840C4C800436272 /* RemotePokemonDataSource.swift in Sources */,
DAD0D3762840B6D800436272 /* Model.xcdatamodeld in Sources */,
DAD0D3832840C45300436272 /* LocalPokemonDataSource.swift in Sources */,
DAD0D38D2840C7FE00436272 /* ExistsPokemonUseCase.swift in Sources */,
DAD0D39A2840CC7800436272 /* PokemonWorldView.swift in Sources */,
DAD0D3812840C29900436272 /* PokemonRepository.swift in Sources */,
DAD0D35F283FCF1500436272 /* ServerTypes.swift in Sources */,
DAD0D36B283FD3B300436272 /* APIManager.swift in Sources */,
Expand All @@ -423,11 +507,13 @@
DAD0D3712840B50200436272 /* CoreDataStack.swift in Sources */,
DAD0D3872840C65D00436272 /* PokemonRepositoryImplementation.swift in Sources */,
DAD0D369283FD1A600436272 /* Pokemon.swift in Sources */,
DAE242F02840D33E00AD4FE1 /* PokemonWorldViewState.swift in Sources */,
DAD0D37A2840B82F00436272 /* DBPokemon.swift in Sources */,
DAD0D35D283FCD3A00436272 /* ServerPokemon.swift in Sources */,
DAD0D36F283FDA2F00436272 /* Persistence.swift in Sources */,
DAD0D38B2840C7C600436272 /* SavePokemonUseCase.swift in Sources */,
DAD0D367283FD0B400436272 /* PokemonType.swift in Sources */,
DAE242F82840DD0D00AD4FE1 /* PokemonCardView.swift in Sources */,
DAD0D38F2840C83100436272 /* GetPokemonsUseCase.swift in Sources */,
DAD0D3732840B60F00436272 /* DBManager.swift in Sources */,
DAD0D37C2840B85100436272 /* DBPokemonType.swift in Sources */,
Expand Down Expand Up @@ -591,9 +677,9 @@
DEVELOPMENT_ASSET_PATHS = "\"Pokemon/Preview Content\"";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = Pokemon/Info.plist;
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 = (
Expand All @@ -619,9 +705,9 @@
DEVELOPMENT_ASSET_PATHS = "\"Pokemon/Preview Content\"";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = Pokemon/Info.plist;
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 = (
Expand Down
3 changes: 2 additions & 1 deletion Pokemon/Pokemon/PokemonApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ struct PokemonApp: App {
var body: some Scene {

WindowGroup {
//ContentView()

PokemonWorldView()
}
}
}
151 changes: 151 additions & 0 deletions Pokemon/Pokemon/Scenes/PokemonWorld/PokemonWorldView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
//
// PokemonWorldView.swift
// Pokemon
//
// Created by Xavier Ramos on 27/5/22.
//

import SwiftUI

struct PokemonWorldView: View {

@StateObject var viewModel = PokemonWorldViewModel()

var body: some View {

VStack {

content
}
}

@ViewBuilder
private var content: some View {

switch viewModel.state {
case .empty:
emptyView()
case .loading:
loadingView()
case .failed(let errorMessage):
failedView(errorMessage: errorMessage)
case .loaded:
loadedView()
}
}

private func emptyView() -> some View {

VStack {

Text("""
\"Hello there!
Welcome to the world of Pokémon!
My name is Oak!
People call me the Pokémon Prof!
This world is inhabited by creatures called Pokémon! For some people, Pokémon are pets. Other use them for fights. Myself… I study Pokémon as a profession.
Your very own Pokémon legend is about to unfold!
A world of dreams and adventures with Pokémon awaits! Let's go!\"
""")

Spacer()

ButtonView(imageName: "pokeball",
text: "Find Pokémon") {

self.viewModel.getPokemon()
}

Spacer()
}
.padding(16)
}

private func loadingView() -> some View {

VStack {

Spacer()

HStack {

Spacer()

ProgressView("Finding Pokémon")

Spacer()
}

Spacer()
}
}

private func failedView(errorMessage: String) -> some View {

VStack {

Spacer()

Text(errorMessage)

Spacer().frame(height: 16)

ButtonView(imageName: "pokeball",
text: "Find Pokémon") {

self.viewModel.getPokemon()
}

Spacer()
}
.padding(16)
}

private func loadedView() -> some View {

VStack {

Spacer()

PokemonCardView(name: viewModel.pokemon?.name ?? "",
image: viewModel.pokemon?.url ?? "",
weight: viewModel.pokemon?.weight ?? 0,
height: viewModel.pokemon?.height ?? 0)

Spacer()

HStack {

ButtonView(imageName: "pokeball",
text: "Find Pokémon",
width: 60) {

self.viewModel.getPokemon()
}

Spacer().frame(width: 10)

ButtonView(imageName: "pokedex",
text: "Catch Pokémon",
width: 60) {

self.viewModel.caughtPokemon()
}
.disabled(viewModel.isCatched ? true : false)
.blur(radius: viewModel.isCatched ? 4 : 0)
}

Spacer()
}
.padding(16)
}
}

struct PokemonWorldView_Previews: PreviewProvider {

static var previews: some View {

PokemonWorldView()
}
}
70 changes: 70 additions & 0 deletions Pokemon/Pokemon/Scenes/PokemonWorld/PokemonWorldViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// PokemonWorldViewModel.swift
// Pokemon
//
// Created by Xavier Ramos on 27/5/22.
//

import Foundation
import SwiftUI
import Combine

class PokemonWorldViewModel: ObservableObject {

// MARK: - Properties

@Published var state: PokemonWorldViewState = .empty
@Published public private(set) var pokemon: Pokemon?
@Published public private(set) var isCatched: Bool = false

private var cancellable: AnyCancellable?

// MARK: - Methods

init() {

if pokemon != nil {

state = .loaded
}
}

func getPokemon() {

state = .loading

cancellable = GetPokemonUseCase().execute()
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { completion in

switch completion {
case .finished:
self.state = .loaded
self.isPokemonCatched()
case .failure(let error):
self.state = .failed("Get Pokémon Failed!")
print("Get Pokemon failed \(error), \(error.localizedDescription)")
}

}, receiveValue: { (pokemon: Pokemon) in

self.pokemon = pokemon
})
}

func isPokemonCatched() {

isCatched = ExistsPokemonUseCase().execute(pokemon: pokemon!)
}

func caughtPokemon() {

if !isCatched {

SavePokemonUseCase().execute(pokemon: pokemon!)

// Show message pokemon caught!

}
}
}
Loading

0 comments on commit f44e6be

Please sign in to comment.