Skip to content

Commit 9a9db00

Browse files
authored
Merge pull request #35 from YAPP-Github/feat/#34-TravelTool
Feat/#34 travel tool
2 parents 726967c + 1be36e0 commit 9a9db00

69 files changed

Lines changed: 2674 additions & 273 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Plugins/DependencyPlugin/ProjectDescriptionHelpers/Dependency+Project.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public extension TargetDependency {
1717
public struct Search {}
1818
public struct Setting {}
1919
public struct PopularTravel {}
20+
public struct TravelTool {}
2021
}
2122

2223
struct Modules {}
@@ -88,6 +89,12 @@ public extension TargetDependency.Features.Main {
8889

8990
public extension TargetDependency.Features.PopularTravel {
9091
static let group = "PopularTravel"
91-
92+
93+
static let feature = TargetDependency.Features.project(name: "Feature", group: group)
94+
}
95+
96+
public extension TargetDependency.Features.TravelTool {
97+
static let group = "TravelTool"
98+
9299
static let feature = TargetDependency.Features.project(name: "Feature", group: group)
93100
}

Plugins/EnvPlugin/ProjectDescriptionHelpers/InfoPlist.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ public extension Project {
3333
]),
3434
"ITSAppUsesNonExemptEncryption": .boolean(false),
3535
"BASE_URL": .string("$(BASE_URL)"),
36-
"X_API_KEY": .string("$(X_API_KEY)")
36+
"X_API_KEY": .string("$(X_API_KEY)"),
37+
"GOOGLE_WEATHER_API_KEY": .string("$(GOOGLE_WEATHER_API_KEY)")
3738
]
3839

3940
static let demoInfoPlist: [String: Plist.Value] = [
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<!-- 사용자 행동 추적 여부 -->
6+
<key>NSPrivacyTracking</key>
7+
<false/>
8+
9+
<!-- 추적에 사용되는 도메인 (추적 없으므로 빈 배열) -->
10+
<key>NSPrivacyTrackingDomains</key>
11+
<array/>
12+
13+
<!-- 수집하는 데이터 유형 (직접 수집 없으므로 빈 배열) -->
14+
<key>NSPrivacyCollectedDataTypes</key>
15+
<array/>
16+
17+
<!-- Required Reason API 사용 목적 선언 -->
18+
<key>NSPrivacyAccessedAPITypes</key>
19+
<array>
20+
<!-- UserDefaults: uuid, nickname 등 앱 상태 관리용으로만 사용 -->
21+
<dict>
22+
<key>NSPrivacyAccessedAPIType</key>
23+
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
24+
<key>NSPrivacyAccessedAPITypeReasons</key>
25+
<array>
26+
<string>CA92.1</string>
27+
</array>
28+
</dict>
29+
</array>
30+
</dict>
31+
</plist>

Projects/App/Sources/Application/AppComponent.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ final class AppComponent: Component<EmptyDependency>, RootDependency {
4141
}
4242
}
4343

44+
var weatherRepository: WeatherRepositoryInterface {
45+
shared {
46+
let service = makeWeatherService()
47+
return WeatherRepository(service: service)
48+
}
49+
}
50+
4451
var homeUsecase: HomeUsecaseProtocol {
4552
shared {
4653
HomeUsecase(
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//
2+
// WeatherServiceFactory.swift
3+
// Data
4+
//
5+
// Created by kimnahun on 2026-02-21.
6+
// Copyright © 2026 NDGL-iOS. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import Networks
11+
import Moya
12+
13+
public func makeWeatherService() -> WeatherServiceProtocol {
14+
let provider = MoyaProvider<WeatherAPI>()
15+
return WeatherService(provider: provider)
16+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//
2+
// WeatherRepository.swift
3+
// Data
4+
//
5+
// Created by kimnahun on 2026-02-21.
6+
// Copyright © 2026 NDGL-iOS. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import Domain
11+
import Networks
12+
13+
public final class WeatherRepository: WeatherRepositoryInterface {
14+
private let service: WeatherServiceProtocol
15+
16+
public init(service: WeatherServiceProtocol) {
17+
self.service = service
18+
}
19+
20+
public func fetchForecast(
21+
latitude: Double,
22+
longitude: Double,
23+
days: Int
24+
) async throws -> [DailyWeatherInfo] {
25+
do {
26+
let response = try await service.getForecast(
27+
latitude: latitude,
28+
longitude: longitude,
29+
days: days
30+
)
31+
return response.forecastDays.compactMap { $0.toDomain() }
32+
} catch {
33+
throw error.toNDGLError()
34+
}
35+
}
36+
}

Projects/Data/Sources/Transform/UserTravelTransform.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ extension UpcomingResponse {
1717
return .init(
1818
id: self.userTravelId,
1919
title: self.title,
20+
city: self.city,
21+
country: self.country,
2022
startDay: self.startDate.toDate() ?? .now,
2123
endDay: self.endDate.toDate() ?? .now,
2224
tripSchedule: .init(
@@ -25,7 +27,9 @@ extension UpcomingResponse {
2527
placeName: self.upcomingUserTravelPlace.place.name,
2628
thumbnailUrl: self.upcomingUserTravelPlace.place.thumbnail ?? "",
2729
transport: self.upcomingUserTravelPlace.place.category,
28-
estimatedDuration: self.upcomingUserTravelPlace.estimatedDuration
30+
estimatedDuration: self.upcomingUserTravelPlace.estimatedDuration,
31+
latitude: self.upcomingUserTravelPlace.place.latitude,
32+
longitude: self.upcomingUserTravelPlace.place.longitude
2933
)
3034
)
3135
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//
2+
// WeatherTransform.swift
3+
// Data
4+
//
5+
// Created by kimnahun on 2026-02-21.
6+
// Copyright © 2026 NDGL-iOS. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import Domain
11+
import Networks
12+
13+
extension ForecastDayResponse {
14+
func toDomain() -> DailyWeatherInfo? {
15+
var components = DateComponents()
16+
components.year = displayDate.year
17+
components.month = displayDate.month
18+
components.day = displayDate.day
19+
20+
guard let date = Calendar.current.date(from: components) else { return nil }
21+
22+
return DailyWeatherInfo(
23+
date: date,
24+
maxTemperature: maxTemperature?.degrees ?? 0,
25+
minTemperature: minTemperature?.degrees ?? 0,
26+
weatherType: daytimeForecast?.weatherCondition.type ?? "CLOUDY"
27+
)
28+
}
29+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// WeatherRepositoryInterface.swift
3+
// Domain
4+
//
5+
// Created by kimnahun on 2026-02-21.
6+
// Copyright © 2026 NDGL-iOS. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public protocol WeatherRepositoryInterface {
12+
func fetchForecast(
13+
latitude: Double,
14+
longitude: Double,
15+
days: Int
16+
) async throws -> [DailyWeatherInfo]
17+
}

Projects/Domain/Sources/Model/Home/MyTripSummary.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,17 @@ import Foundation
1212
public struct MyTripSummary {
1313
public let id: Int
1414
public let title: String
15+
public let city: String
16+
public let country: String
1517
public let startDay: Date
1618
public let endDay: Date
1719
public let tripSchedule: Schedule
18-
19-
public init(id: Int, title: String, startDay: Date, endDay: Date, tripSchedule: Schedule) {
20+
21+
public init(id: Int, title: String, city: String, country: String, startDay: Date, endDay: Date, tripSchedule: Schedule) {
2022
self.id = id
2123
self.title = title
24+
self.city = city
25+
self.country = country
2226
self.startDay = startDay
2327
self.endDay = endDay
2428
self.tripSchedule = tripSchedule
@@ -33,20 +37,26 @@ public struct Schedule {
3337
public let thumbnailUrl: String
3438
public let transport: String
3539
public let estimatedDuration: Int
36-
40+
public let latitude: Double
41+
public let longitude: Double
42+
3743
public init(
3844
id: Int,
3945
day: Int,
4046
placeName: String,
4147
thumbnailUrl: String,
4248
transport: String,
43-
estimatedDuration: Int
49+
estimatedDuration: Int,
50+
latitude: Double,
51+
longitude: Double
4452
) {
4553
self.id = id
4654
self.day = day
4755
self.placeName = placeName
4856
self.thumbnailUrl = thumbnailUrl
4957
self.transport = transport
5058
self.estimatedDuration = estimatedDuration
59+
self.latitude = latitude
60+
self.longitude = longitude
5161
}
5262
}

0 commit comments

Comments
 (0)