Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GWL-229]운동 매칭 이후 운동 session에 관한 데이터 넘겨주는 기능 구현 #238

Merged
merged 18 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions iOS/Projects/App/WeTri/Sources/Application/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,11 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
guard let windowScene = scene as? UIWindowScene else { return }
window = UIWindow(windowScene: windowScene)
let navigationController = UINavigationController()
let viewController = SignUpContainerViewController(
signUpGenderBirthViewController: SignUpGenderBirthViewController(viewModel: SignUpGenderBirthViewModel(dateFormatUseCase: DateFormatUseCase())),
signUpProfileViewController: SignUpProfileViewController()
)
window?.rootViewController = viewController
// let coordinator = AppCoordinator(navigationController: navigationController)
// coordinating = coordinator
// coordinator.start()
window = UIWindow(windowScene: windowScene)
let coordinator = AppCoordinator(navigationController: navigationController)
coordinating = coordinator
coordinator.start()
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ final class AppCoordinator: AppCoordinating {
}

func start() {
showSplashFlow()
showTabBarFlow()
}

private func showSplashFlow() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"code": 200,
"code": null,
"errorMessage": null,
"data": null
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
{
"code": 201,
"code": null,
"errorMessage": null,
"data": null
"data": {
"matched": true,
"liveWorkoutStartTime": "2023-12-05 16:33:00",
"roomId": "uuid",
"publicId": "someStringss",
"peers": [
{
"nickname": "나는 1번 타자",
"publicId": "someString",
"profileImage": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/74/Cat-eating-prey.jpg/220px-Cat-eating-prey.jpg",
"etc": "그 외 나머지 모든 컬럼"
},
{
"nickname": "나는 2번타자",
"publicId": "someStringw",
"profileImage": "https://www.telegraph.co.uk/content/dam/pets/2017/01/06/1-JS117202740-yana-two-face-cat-news_trans_NvBQzQNjv4BqJNqHJA5DVIMqgv_1zKR2kxRY9bnFVTp4QZlQjJfe6H0.jpg?imwidth=450",
"etc": "그 외 나머지 모든 컬럼"
}
]
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"code": 200,
"code": null,
"errorMessage": null,
"data": null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// IsMatchedRandomPeersRequest.swift
// RecordFeature
//
// Created by MaraMincho on 12/5/23.
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved.
//

import Foundation

/// randomMatching API의 requst에 활용합니다.
///
/// 어떤 운동과, 얼마나 randomMatching을 기다렸는지 알려주는 객체 입니다.
struct IsMatchedRandomPeersRequest: Encodable {
/// 어떤 운동을 랜덤 매칭 하는지 알려줍니다.
///
/// 1번 : 달리기
/// 2번 : 사이클
/// 3번 : 수영
let workoutID: Int
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3: workoutID는 enum으로 빼주면 사용할 때 가독성에 더 좋을 것 같아요!

enum WorkoutKind: Int: Codable {
  case running = 1
  case cycling
  case swimming
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

서버에서 내려주는 이벤트성 경기 때문에 일단 Int로 처리했습니다. 추가로 WorkoutType을 통해서 어떤 운동을 할 것인지 명확한 구분이 없어서, Sports Enum을 추가했습니다.

public enum Sports: Int {
  case running = 1
  case cycling
  case swimming
}


/// 몇초를 대기방에서 기다렸는지 알려줍니다.
let waitingTime: Int
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// IsMatchedRandomPeersResponse.swift
// RecordFeature
//
// Created by MaraMincho on 12/5/23.
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved.
//

import Foundation

// MARK: - IsMatchedRandomPeersResponse

struct IsMatchedRandomPeersResponse: Decodable {
let matched: Bool
let liveWorkoutStartTime: String?
let roomID: String?
let publicID: String?
let peers: [IsMatchedRandomPeersForPeerResponse]?

enum CodingKeys: String, CodingKey {
case matched
case liveWorkoutStartTime
case roomID = "roomId"
case publicID = "publicId"
case peers
}
}

// MARK: - IsMatchedRandomPeersForPeerResponse

struct IsMatchedRandomPeersForPeerResponse: Decodable {
let nickname: String
let publicID: String
let profileImage: String
let etc: String?

enum CodingKeys: String, CodingKey {
case nickname
case publicID = "publicId"
case profileImage
case etc
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// MatchStartRequest.swift
// RecordFeature
//
// Created by MaraMincho on 12/5/23.
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved.
//

import Foundation

/// 매칭이 시작 될 떄 사용하는 Request Body입니다.
struct MatchStartRequest: Encodable {
/// workoutId는 운동 번호를 의미합니다.
let workoutID: Int
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,6 @@ private extension WorkoutEnvironmentSetupNetworkRepository {
case exerciseTypes
case peer

// TODO: API에 맞게 수정 예정
var baseURL: String {
switch self {
case .exerciseTypes:
return "https://www.naver.com"
case .peer:
return "https://www.naver.com"
}
}

var path: String {
switch self {
case .exerciseTypes:
Expand All @@ -100,7 +90,7 @@ private extension WorkoutEnvironmentSetupNetworkRepository {
var method: TNMethod { return .get }
var query: Encodable? { nil }
var body: Encodable? { nil }
var headers: Trinet.TNHeaders { .init(headers: []) }
var headers: TNHeaders { .default }
}

enum PersistencyProperty {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import Combine
import CommonNetworkingKeyManager
import Foundation
import Trinet

Expand All @@ -27,15 +28,12 @@ extension WorkoutPeerRandomMatchingRepository: WorkoutPeerRandomMatchingReposito
return Future<Result<Void, Error>, Never> { promise in
Task {
do {
let data = try await provider.request(.matchStart(workoutTypeCode: workoutTypeCode))
let response = try decoder.decode(GWResponse<NullDTO>.self, from: data)
// 200번대 REsponse인지 확인, 보통 서버에서 코드를 보내주지만, 안보내줄 경우 자동적으로 동작 안하게 작성)
if response.code == 200 {
promise(.success(.success(())))
} else {
// TODO: ERROR Handling
promise(.success(.failure(RepositoryError.serverError)))
}
let data = try await provider.request(
.matchStart(matchStartRequest: .init(workoutID: workoutTypeCode)),
interceptor: TNKeychainInterceptor.shared
)
_ = try decoder.decode(GWResponse<NullDTO>.self, from: data)
promise(.success(.success(())))
} catch {
promise(.success(.failure(error)))
}
Expand All @@ -53,21 +51,20 @@ extension WorkoutPeerRandomMatchingRepository: WorkoutPeerRandomMatchingReposito
}
}

func isMatchedRandomPeer(workoutTypeCode: Int) -> AnyPublisher<Result<PeerMatchResponseDTO?, Error>, Never> {
return Future<Result<PeerMatchResponseDTO?, Error>, Never> { promise in
func isMatchedRandomPeer(
isMatchedRandomPeersRequest: IsMatchedRandomPeersRequest
) -> AnyPublisher<Result<IsMatchedRandomPeersResponse?, Error>, Never> {
return Future<Result<IsMatchedRandomPeersResponse?, Error>, Never> { promise in
Task {
do {
let data = try await provider.request(.isMatchedRandomPeer(workoutTypeCode: workoutTypeCode))
let response = try decoder.decode(GWResponse<PeerMatchResponseDTO>.self, from: data)
if response.code == 201 {
promise(.success(.success(nil)))
} else if response.code == 200 {
promise(.success(.success(response.data)))
} else {
promise(.success(.failure(RepositoryError.serverError)))
let data = try await provider.request(.isMatchedRandomPeer(isMatchedRandomPeersRequest: isMatchedRandomPeersRequest))
guard
let responseData = try decoder.decode(GWResponse<IsMatchedRandomPeersResponse>.self, from: data).data
else {
throw RepositoryError.serverError
}
promise(.success(.success(responseData)))
} catch {
// TODO: ERROR Handling
promise(.success(.failure(error)))
}
}
Expand All @@ -86,20 +83,20 @@ enum RepositoryError: LocalizedError {

extension WorkoutPeerRandomMatchingRepository {
enum WorkoutPeerRandomMatchingRepositoryEndPoint: TNEndPoint {
/// Proeprty
case matchStart(workoutTypeCode: Int)
/// Property
case matchStart(matchStartRequest: MatchStartRequest)
case matchCancel
case isMatchedRandomPeer(workoutTypeCode: Int)
case isMatchedRandomPeer(isMatchedRandomPeersRequest: IsMatchedRandomPeersRequest)

/// TNEndPoint
var path: String {
switch self {
case .matchStart:
return "matches/start"
return "api/v1/matches/start"
case .matchCancel:
return "matches/cancle"
return "api/v1/matches/cancel"
case .isMatchedRandomPeer:
return "matches/random"
return "api/v1/matches/random"
}
}

Expand All @@ -109,7 +106,7 @@ extension WorkoutPeerRandomMatchingRepository {
.matchStart:
return .post
case .matchCancel:
return .get
return .delete
}
}

Expand All @@ -119,12 +116,9 @@ extension WorkoutPeerRandomMatchingRepository {

var body: Encodable? {
switch self {
case let .matchStart(workoutTypeCode):
return workoutTypeCode
case let .isMatchedRandomPeer(workoutTypeCode):
return workoutTypeCode
case .matchCancel:
return nil
case let .matchStart(matchStartRequest): return matchStartRequest
case let .isMatchedRandomPeer(isMatchedRandomPeersRequest): return isMatchedRandomPeersRequest
case .matchCancel: return nil
}
}

Expand Down
14 changes: 14 additions & 0 deletions iOS/Projects/Features/Record/Sources/Domain/Entities/Peer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// Peer.swift
// RecordFeature
//
// Created by MaraMincho on 12/5/23.
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved.
//

import Foundation

struct Peer {
let nickname: String
let imageURL: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ struct SessionPeerType: Identifiable {
let id: String

/// 사용자의 프로필 이미지 주소
let profileImageURL: URL
let profileImageURL: URL?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3: URL 옵셔널인 이유가 있을까요? 회원가입 시 사용자 이미지가 없으면 회원가입이 안 돼서 URL 그대로 받아도 좋을 것 같아요.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 String을 통한 URL생성자가 항상 Optional입니다. 그래서 URL을 직접 생성하게 된다면 optional이 생성된다는 문제가 있습니다. 이 Optional을 벗길 방법은 사실 사용하는 쪽에서밖에 없어서 이런 선택을 하게 되었습니다.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// WorkoutSessionElement.swift
// RecordFeature
//
// Created by MaraMincho on 12/5/23.
// Copyright © 2023 kr.codesquad.boostcamp8. All rights reserved.
//

import Foundation

/// RandomMatching에서 WorkoutSession으로 화면전환 할 때 넘겨주는 데이터 입니다.
struct WorkoutSessionElement {
let startDate: Date
let peers: [Peer]
let roomID: String

private let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:SS"
return formatter
}()

/// 스트링으로 데이터를 받았을 때 서버에서 내려준 값이
/// 현재 시간보다 과거거나, 서버에서 내려준 시간이 잘못되었을 경우
/// 현재시간 + 4 초 후에 운동을 시작하는 것으로 세팅했습니다.
init(startDateString: String, peers: [Peer], roomID: String) {
var date = formatter.date(from: startDateString) ?? .now + 4
if Date.now > date {
date = Date.now + 4
}
Comment on lines +27 to +30
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2

비즈니스로직은 UseCase에서 진행해야된다고 생각합니다 ㅎㅎ

startDate = date
self.peers = peers
self.roomID = roomID
}

init(startDate: Date, peers: [Peer], roomID: String) {
self.startDate = startDate
self.peers = peers
self.roomID = roomID
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ import Foundation

// MARK: - WorkoutSetting

/// 어떤 운동을 할지와, 어떻게 운동을 할지 알려주는 객체 입니다.
struct WorkoutSetting {
let workoutType: WorkoutType

let workoutPeerType: PeerType

let isWorkoutAlone: Bool

init(workoutType: WorkoutType, workoutPeerType: PeerType, isWorkoutAlone: Bool = true) {
self.workoutType = workoutType
self.workoutPeerType = workoutPeerType
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import Combine
import Foundation
import Log

// MARK: - OneSecondsTimerUseCaseRepresentable

Expand All @@ -20,14 +21,14 @@ protocol OneSecondsTimerUseCaseRepresentable: TimerUseCaseRepresentable {
final class OneSecondsTimerUseCase: TimerUseCase {
override init(initDate: Date, timerPeriod: Double = 1) {
super.init(initDate: initDate, timerPeriod: timerPeriod)
startTimer()
}
}

// MARK: OneSecondsTimerUseCaseRepresentable

extension OneSecondsTimerUseCase: OneSecondsTimerUseCaseRepresentable {
func oneSecondsTimerPublisher() -> AnyPublisher<Int, Never> {
startTimer()
return intervalCurrentAndInitEverySecondsPublisher()
.map { abs($0) }
.eraseToAnyPublisher()
Expand Down
Loading