Skip to content

Commit

Permalink
feat: GamePlayView 엔티티, 네트워크, 유즈케이스, 뷰모델 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
Jun Ho JANG authored and Jun Ho JANG committed May 12, 2021
1 parent a4c9090 commit e62041d
Show file tree
Hide file tree
Showing 13 changed files with 294 additions and 13 deletions.
20 changes: 20 additions & 0 deletions Baseball/Baseball.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
A05951C9264A69F1002B759A /* GameScoreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05951C8264A69F1002B759A /* GameScoreViewController.swift */; };
A05951CE264A7921002B759A /* GameScoreTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05951CD264A7921002B759A /* GameScoreTableViewCell.swift */; };
A06524AB2643B7C700CF375D /* PitchHistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A06524AA2643B7C700CF375D /* PitchHistoryView.swift */; };
A0907C2F264BB7F1007ABB1F /* GamePlayRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0907C2E264BB7F1007ABB1F /* GamePlayRepository.swift */; };
A0907C31264BB8F9007ABB1F /* GamePlayDTO+Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0907C30264BB8F9007ABB1F /* GamePlayDTO+Mapping.swift */; };
A0907C33264BBE70007ABB1F /* GamePlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0907C32264BBE70007ABB1F /* GamePlay.swift */; };
A0907C35264BC06A007ABB1F /* FetchGamePlayUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0907C34264BC06A007ABB1F /* FetchGamePlayUseCase.swift */; };
A0907C37264BC1B1007ABB1F /* GamePlayViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0907C36264BC1B1007ABB1F /* GamePlayViewModel.swift */; };
A098D28C264383D700950F8F /* GamePlayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A098D28B264383D700950F8F /* GamePlayViewController.swift */; };
A09F9F2C26490CD700A78969 /* FetchGameListUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = A09F9F2B26490CD700A78969 /* FetchGameListUseCase.swift */; };
A09F9F3126490F4B00A78969 /* GameListRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = A09F9F3026490F4B00A78969 /* GameListRepository.swift */; };
Expand Down Expand Up @@ -56,6 +61,11 @@
A05951C8264A69F1002B759A /* GameScoreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameScoreViewController.swift; sourceTree = "<group>"; };
A05951CD264A7921002B759A /* GameScoreTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameScoreTableViewCell.swift; sourceTree = "<group>"; };
A06524AA2643B7C700CF375D /* PitchHistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PitchHistoryView.swift; sourceTree = "<group>"; };
A0907C2E264BB7F1007ABB1F /* GamePlayRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GamePlayRepository.swift; sourceTree = "<group>"; };
A0907C30264BB8F9007ABB1F /* GamePlayDTO+Mapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GamePlayDTO+Mapping.swift"; sourceTree = "<group>"; };
A0907C32264BBE70007ABB1F /* GamePlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GamePlay.swift; sourceTree = "<group>"; };
A0907C34264BC06A007ABB1F /* FetchGamePlayUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchGamePlayUseCase.swift; sourceTree = "<group>"; };
A0907C36264BC1B1007ABB1F /* GamePlayViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GamePlayViewModel.swift; sourceTree = "<group>"; };
A098D28B264383D700950F8F /* GamePlayViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GamePlayViewController.swift; sourceTree = "<group>"; };
A09F9F2B26490CD700A78969 /* FetchGameListUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchGameListUseCase.swift; sourceTree = "<group>"; };
A09F9F3026490F4B00A78969 /* GameListRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameListRepository.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -184,6 +194,7 @@
A025C3482641160F00C9B8C7 /* ViewModel */ = {
isa = PBXGroup;
children = (
A0907C36264BC1B1007ABB1F /* GamePlayViewModel.swift */,
);
path = ViewModel;
sourceTree = "<group>";
Expand Down Expand Up @@ -221,6 +232,7 @@
isa = PBXGroup;
children = (
A09F9F2B26490CD700A78969 /* FetchGameListUseCase.swift */,
A0907C34264BC06A007ABB1F /* FetchGamePlayUseCase.swift */,
);
path = UseCase;
sourceTree = "<group>";
Expand All @@ -238,6 +250,7 @@
isa = PBXGroup;
children = (
A09F9F3026490F4B00A78969 /* GameListRepository.swift */,
A0907C2E264BB7F1007ABB1F /* GamePlayRepository.swift */,
);
path = Repository;
sourceTree = "<group>";
Expand All @@ -256,6 +269,7 @@
isa = PBXGroup;
children = (
A09F9F3726491ECE00A78969 /* GameListDTO+Mapping.swift */,
A0907C30264BB8F9007ABB1F /* GamePlayDTO+Mapping.swift */,
);
path = DataMapping;
sourceTree = "<group>";
Expand Down Expand Up @@ -300,6 +314,7 @@
isa = PBXGroup;
children = (
FFDD3A8F264138800037622A /* MatchUp.swift */,
A0907C32264BBE70007ABB1F /* GamePlay.swift */,
);
path = Entity;
sourceTree = "<group>";
Expand Down Expand Up @@ -376,6 +391,8 @@
buildActionMask = 2147483647;
files = (
A05951CE264A7921002B759A /* GameScoreTableViewCell.swift in Sources */,
A0907C2F264BB7F1007ABB1F /* GamePlayRepository.swift in Sources */,
A0907C37264BC1B1007ABB1F /* GamePlayViewModel.swift in Sources */,
FF57667E2649324200F46A43 /* Alertable.swift in Sources */,
FFDD3A92264138F40037622A /* GameListViewModel.swift in Sources */,
FFDD3A90264138800037622A /* MatchUp.swift in Sources */,
Expand All @@ -387,6 +404,7 @@
A05951C1264A27FC002B759A /* BaseballSceneDIContainer.swift in Sources */,
A09F9F3826491ECE00A78969 /* GameListDTO+Mapping.swift in Sources */,
A025C34C2641164000C9B8C7 /* GroundView.swift in Sources */,
A0907C33264BBE70007ABB1F /* GamePlay.swift in Sources */,
A09F9F2C26490CD700A78969 /* FetchGameListUseCase.swift in Sources */,
A025C32A2640E8E700C9B8C7 /* AppDelegate.swift in Sources */,
A05951C3264A2AB5002B759A /* AppFlowCoordinator.swift in Sources */,
Expand All @@ -399,7 +417,9 @@
FFDD3A9E2643C3960037622A /* PitchHistoryCell.swift in Sources */,
A05951BF264A27EC002B759A /* AppDIContainer.swift in Sources */,
FFDD3AA62644FD9B0037622A /* CALayer+Extension.swift in Sources */,
A0907C35264BC06A007ABB1F /* FetchGamePlayUseCase.swift in Sources */,
A09F9F3126490F4B00A78969 /* GameListRepository.swift in Sources */,
A0907C31264BB8F9007ABB1F /* GamePlayDTO+Mapping.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class BaseballSceneDIContainer: BaseballFlowCoordinatorDependencies {
self.dependencies = dependencies
}

//MARK: - GameListView
private func makeGameListRepository() -> GameListRepository {
return DefaultGameListRepository(networkService: dependencies.apiNetwork)
}
Expand All @@ -26,14 +27,32 @@ class BaseballSceneDIContainer: BaseballFlowCoordinatorDependencies {
return DefaultFetchGameListUseCase(gameListRepository: makeGameListRepository())
}

private func makeGameListViewModel() -> GameListViewModel {
return GameListViewModel(fetchGameListUseCase: makeFetchGameListUseCase())
private func makeGameListViewModel(action: GameListViewModelAction) -> GameListViewModel {
return GameListViewModel(fetchGameListUseCase: makeFetchGameListUseCase(), action: action)
}

func makeGameListViewController() -> GameListViewController {
return GameListViewController.create(with: makeGameListViewModel())
func makeGameListViewController(action: GameListViewModelAction) -> GameListViewController {
return GameListViewController.create(with: makeGameListViewModel(action: action))
}

//MARK: - GamePlayView
private func makeGamePlayRepository() -> GamePlayRepository {
return DefaultGamePlayRepository(networkService: dependencies.apiNetwork)
}

private func makeFetchGamePlayUseCase() -> FetchGamePlayUseCase {
return DefaultFetchGamePlayUseCase(gamePlayRepository: makeGamePlayRepository())
}

private func makeGamePlayViewModel(matchId: Int) -> GamePlayViewModel {
return GamePlayViewModel(matchId: matchId, fetchGamePlayUseCase: makeFetchGamePlayUseCase())
}

func makeGamePlayViewController(matchId: Int) -> GamePlayViewController {
return GamePlayViewController.create(with: makeGamePlayViewModel(matchId: matchId))
}

//MARK: - Coordinator
func makeBaseballSceneCoordinator(navigationController: UINavigationController) -> BaseballSceneFlowCoordinator {
return BaseballSceneFlowCoordinator(navigationController: navigationController, dependencies: self)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//
// GamePlayDTO+Mapping.swift
// Baseball
//
// Created by Jun Ho JANG on 2021/05/12.
//

import Foundation

/*
{"matchId":13,
"away":"awayteam to string",
"home":"hometeam to string",
"inning":1,
"offenseTeam":"offenseTeam to String"
"firstBase":[],
"secondBase":[],
"thirdBase":[],
"pitcher":"kim",
"batter":"dong",
"strike":0,
"ball":0,
"out":0,
"homePoint":0,
"awayPoint":0}
*/



struct GamePlayDTO: Decodable {
private let matchId: Int
private let away: String
private let home: String
private let inning: Int
private let offenseTeam: String
private let firstBase: [String]
private let secondBase: [String]
private let thirdBase: [String]
private let pitcher: String
private let batter: String
private let strike: Int
private let ball: Int
private let out: Int
private let homePoint: Int
private let awayPoint: Int

func toDomain() -> GamePlay {
return .init(matchId: matchId, away: away, home: home, inning: inning, offenseTeam: offenseTeam, firstBase: firstBase, secondBase: secondBase, thirdBase: thirdBase, pitcher: pitcher, batter: batter, strike: strike, ball: ball, out: out, homePoint: homePoint, awayPoint: awayPoint)
}
}
15 changes: 15 additions & 0 deletions Baseball/Baseball/Data/Network/NetworkEndpoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@ struct GameListEndpoint: Requestable {
}
}

struct GamePlayEndPoint: Requestable {
var baseUrl = "http://3.35.226.74/games/offense/"
var path: String
var httpMethod: HTTPMethod

init(httpMethod: HTTPMethod, path: String) {
self.httpMethod = httpMethod
self.path = path
}

func url() -> URL? {
return URL(string: baseUrl + path)
}
}

enum HTTPMethod: String {
case get = "GET"
case post = "POST"
Expand Down
42 changes: 42 additions & 0 deletions Baseball/Baseball/Data/Repository/GamePlayRepository.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// GamePlayRepository.swift
// Baseball
//
// Created by Jun Ho JANG on 2021/05/12.
//

import Foundation
import Combine

protocol GamePlayRepository {
func fetchGamePlayData(matchId: Int, completion: @escaping (Result<GamePlay, NetworkError>) -> Void)
}

class DefaultGamePlayRepository: GamePlayRepository {

private let networkService: NetworkService
private var subscriptions = Set<AnyCancellable>()

init(networkService: NetworkService) {
self.networkService = networkService
}

func fetchGamePlayData(matchId: Int, completion: @escaping (Result<GamePlay, NetworkError>) -> Void) {
let path = String(matchId)
let endpoint = GamePlayEndPoint(httpMethod: .get, path: path)

self.networkService.request(with: endpoint, dataType: GamePlayDTO.self)
.sink { result in
switch result {
case .failure(let error):
completion(.failure(error))
case .finished:
break
}
} receiveValue: { gamePlayDTO in
let gamePlayData = gamePlayDTO.toDomain()
completion(.success(gamePlayData))
}
.store(in: &self.subscriptions)
}
}
26 changes: 26 additions & 0 deletions Baseball/Baseball/Domain/Entity/GamePlay.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// GamePlay.swift
// Baseball
//
// Created by Jun Ho JANG on 2021/05/12.
//

import Foundation

struct GamePlay {
var matchId: Int
var away: String
var home: String
var inning: Int
var offenseTeam: String
var firstBase: [String]
var secondBase: [String]
var thirdBase: [String]
var pitcher: String
var batter: String
var strike: Int
var ball: Int
var out: Int
var homePoint: Int
var awayPoint: Int
}
26 changes: 26 additions & 0 deletions Baseball/Baseball/Domain/UseCase/FetchGamePlayUseCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// FetchGamePlayUseCase.swift
// Baseball
//
// Created by Jun Ho JANG on 2021/05/12.
//

import Foundation

protocol FetchGamePlayUseCase {
func execute(matchId: Int, completion: @escaping(Result<GamePlay,NetworkError>) -> Void)
}

class DefaultFetchGamePlayUseCase: FetchGamePlayUseCase {
private let gamePlayRepository: GamePlayRepository

init(gamePlayRepository: GamePlayRepository) {
self.gamePlayRepository = gamePlayRepository
}

func execute(matchId : Int, completion: @escaping (Result<GamePlay,NetworkError>) -> Void) {
gamePlayRepository.fetchGamePlayData(matchId: matchId) { result in
completion(result)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
import UIKit

protocol BaseballFlowCoordinatorDependencies {
func makeGameListViewController() -> GameListViewController
func makeGameListViewController(action: GameListViewModelAction) -> GameListViewController
func makeGamePlayViewController(matchId: Int) -> GamePlayViewController
}

class BaseballSceneFlowCoordinator {
Expand All @@ -22,8 +23,15 @@ class BaseballSceneFlowCoordinator {
}

func start() {
let vc = dependencies.makeGameListViewController()
let action = GameListViewModelAction(showGamePlayView: showGamePlayView(matchUp:))
let vc = dependencies.makeGameListViewController(action: action)
navigationController?.pushViewController(vc, animated: true)
gameListVC = vc
}

// let showGamePlayView: ((Int)-> Void)
func showGamePlayView(matchUp: Int) {
let vc = dependencies.makeGamePlayViewController(matchId: matchUp)
self.navigationController?.pushViewController(vc, animated: true)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ extension GameListViewController: UICollectionViewDataSource {
}
}

extension GameListViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
viewModel.didSelectItem(indexPath: indexPath)
}
}

extension GameListViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 40
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@
import Foundation
import Combine

struct GameListViewModelAction {
typealias MatchUpID = Int
let showGamePlayView: ((MatchUpID) -> Void)
}

class GameListViewModel {
@Published private (set) var matchUpGames: [MatchUp]
@Published private (set) var error: String

private var fetchGameListUseCase: FetchGameListUseCase
private var action: GameListViewModelAction

init(fetchGameListUseCase: FetchGameListUseCase) {
init(fetchGameListUseCase: FetchGameListUseCase, action: GameListViewModelAction) {
self.matchUpGames = []
self.error = ""
self.fetchGameListUseCase = fetchGameListUseCase

self.action = action
fetchGameList()
}

Expand All @@ -41,4 +47,8 @@ class GameListViewModel {
self.error = des
}
}

func didSelectItem(indexPath: IndexPath) {
action.showGamePlayView(indexPath.item + 1)
}
}
Loading

0 comments on commit e62041d

Please sign in to comment.