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

[Assignment] 4주차 과제 #16

Merged
merged 14 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions Plugins/EnvPlugin/ProjectDescriptionHelpers/InfoPlist.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import ProjectDescription

public extension Project {
static let appInfoPlist: [String: InfoPlist.Value] = [
"BASE_URL": "https://api.openweathermap.org/data/2.5",
"API_KEY": "7618d35ff394f5dd39212928a3a4692f",
"CFBundleShortVersionString": "1.0.0",
"CFBundleDevelopmentRegion": "ko",
"CFBundleVersion": "1",
Expand Down
19 changes: 19 additions & 0 deletions Projects/Core/Sources/Configuration/Config.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// Config.swift
// Core
//
// Created by 류희재 on 2023/11/17.
// Copyright © 2023 hellohidi. All rights reserved.
//

import Foundation

import Foundation

import Foundation

public struct Config {
public static let apiKey = Bundle.main.infoDictionary?["API_KEY"] as! String
public static let baseURL = Bundle.main.infoDictionary?["BASE_URL"] as! String
}

13 changes: 13 additions & 0 deletions Projects/Core/Sources/Configuration/Config.xcconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// Config.xcconfig
// Core
//
// Created by 류희재 on 2023/11/17.
// Copyright © 2023 hellohidi. All rights reserved.
//

// Configuration settings file format documentation can be found at:
// https://help.apple.com/xcode/#/dev745c5c974

BASE_URL = https:/$()/api.openweathermap.org/data/2.5
API_KEY = 7618d35ff394f5dd39212928a3a4692f
13 changes: 6 additions & 7 deletions Projects/Core/Sources/Extension/Foundation+/String+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ extension String {
return self.count > length
}

// func transform() -> AppVersion {
// self.split(separator: ".").map { Int($0) ?? 0 }
// }
// func transform() -> AppVersion {
// self.split(separator: ".").map { Int($0) ?? 0 }
// }

// MARK: - 휴대폰 번호 검증
// MARK: - 휴대폰 번호 검증
public func validatePhone(number: String) -> Bool {
let regex = "^01([0|1|6|7|8|9])-?([0-9]{3,4})-?([0-9]{4})$"
return NSPredicate(format: "SELF MATCHES %@", regex).evaluate(with: number)
Expand All @@ -35,8 +35,7 @@ extension String {
stringWithHypen.insert("-", at: stringWithHypen.index(stringWithHypen.endIndex, offsetBy: -4))

return stringWithHypen
}

}
}


4 changes: 1 addition & 3 deletions Projects/Core/Sources/Extension/UIKit+/UIImageView+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,11 @@ import UIKit
import Kingfisher

extension UIImageView{
func kfSetImage(url : String?, defaultImage: UIImage?){

public func kfSetImage(url : String?, defaultImage: UIImage? = nil){
guard let url = url else {
self.image = defaultImage
return
}

if let url = URL(string: url) {
kf.indicatorType = .activity
kf.setImage(with: url,
Expand Down
52 changes: 42 additions & 10 deletions Projects/Core/Sources/Extension/UIKit+/UIView+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,48 @@ extension UIView {
layer.borderColor = borderColor.cgColor
}

// func showToast(_ message: String,
// type: Toast.ToastType,
// view: UIView? = UIApplication.shared.firstWindow,
// bottomInset: CGFloat = 86) {
// guard let view else { return }
// Toast().show(message: message,
// type: type,
// view: view,
// bottomInset: bottomInset)
// }
/// UIView에 MaskLayer를 추가하는 함수
/// - Parameter rect rect만큼의 범위만 보여지고 나머지는 mask됨
public func roundedMask(rect: CGRect) {
let path = CGMutablePath()
path.addRoundedRect(in: rect, cornerWidth: 2, cornerHeight: 2)

let shapeLayer = CAShapeLayer()
shapeLayer.path = path

layer.mask = shapeLayer
}

public func setRoundCorners(corners: UIRectCorner, radius: CGFloat) {
self.clipsToBounds = true
self.layer.cornerRadius = radius
var masked = CACornerMask()
if corners.contains(.topLeft) { masked.insert(.layerMinXMinYCorner) }
if corners.contains(.topRight) { masked.insert(.layerMaxXMinYCorner) }
if corners.contains(.bottomLeft) { masked.insert(.layerMinXMaxYCorner) }
if corners.contains(.bottomRight) { masked.insert(.layerMaxXMaxYCorner) }

if corners.contains(.allCorners) {
masked = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner]
}
self.layer.maskedCorners = masked
}

/// UIView를 UIImage로 변환해주는 함수
/// - Parameter rect rect만큼의 범위만 UIImage로 변환, 지정해주지 않을 시 모든 범위를 변환
public func asImage(rect: CGRect? = nil) -> UIImage {
if let rect {
let renderer = UIGraphicsImageRenderer(bounds: rect)
return renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
} else {
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
}
}
}


13 changes: 13 additions & 0 deletions Projects/Core/Sources/MockData/City.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// City.swift
// Core
//
// Created by 류희재 on 2023/11/16.
// Copyright © 2023 hellohidi. All rights reserved.
//

import Foundation

public class City {
public static let cityList = ["gongju", "gwangju", "gumi", "gunsan", "daegu", "daejeon", "mokpo", "busan", "seosan", "seoul", "sokcho", "suwon", "suncheon", "ulsan", "iksan", "jeonju", "jeju", "cheonan", "cheongju", "chuncheon"]
}
34 changes: 34 additions & 0 deletions Projects/Core/Sources/Utils/Weather+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// Weather+.swift
// Core
//
// Created by 류희재 on 2023/11/16.
// Copyright © 2023 hellohidi. All rights reserved.
//

import Foundation

final public class WeatherUtil {
public static func makeTimeZoneToTime(timeZone: Int) -> String {
let today = Date()
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(secondsFromGMT: timeZone)
dateFormatter.dateFormat = "HH:mm"
return dateFormatter.string(from: today)
}

public static func makedtTextToTime(_ dtText: String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
guard let date = dateFormatter.date(from: dtText) else { return ""}
let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "HH"
let timeString = timeFormatter.string(from: date)
return timeString
}

public static func weatherIconToUrl(_ icon: String) -> String {
return "http://openweathermap.org/img/wn/\(icon).png"
}
}

58 changes: 58 additions & 0 deletions Projects/Data/Sources/Repository/DefaultWeatherRepository.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// DefaultWeatherRepository.swift
// ProjectDescriptionHelpers
//
// Created by 류희재 on 2023/11/14.
//

import Foundation

import RxSwift

import Domain
import Networks

public class DefaultWeatherRepository: WeatherRepository {

typealias Error = URLSessionNetworkServiceError
public let urlSessionService: URLSessionNetworkService
private let disposeBag = DisposeBag()

public init(urlSessionService: URLSessionNetworkService) {
self.urlSessionService = urlSessionService
}

public func getCityWeatherData(city: String) -> Observable<CurrentWeatherModel> {
return urlSessionService.request(target: WeatherAPI.getCurrentWeatherData(city: city))
.map({ result in
switch result {
case .success(let data):
guard let dto = self.decode(data: data, to: CurrentWeatherEntity.self) else { throw Error.responseDecodingError }
return dto.toDomain()
case .failure(let error):
throw error
}
})
}

public func getHourlyWeatherData(city: String) -> Observable<[HourlyWeatherModel]> {
return urlSessionService.request(target: WeatherAPI.getHourlyWeatherData(city: city)).map({ result in
switch result {
case .success(let data):
guard let dto = self.decode(data: data, to: HourlyWeatherEntity.self) else { throw Error.responseDecodingError }
return dto.toDomain()
case .failure(let error):
throw error
}
})
}



private func decode<T: Decodable>(data: Data, to target: T.Type) -> T? {
return try? JSONDecoder().decode(target, from: data)
}


}

25 changes: 25 additions & 0 deletions Projects/Data/Sources/Transform/CurrentWeatherTransform.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// transform.swift
// ProjectDescriptionHelpers
//
// Created by 류희재 on 2023/11/14.
//

import Foundation

import Core
import Networks
import Domain

extension CurrentWeatherEntity {
public func toDomain() -> CurrentWeatherModel {
return CurrentWeatherModel(
time: WeatherUtil.makeTimeZoneToTime(timeZone: timezone),
place: name,
weather: weather[0].main,
temparature: main.temp,
maxTemparature: main.tempMax,
minTemparature: main.tempMin
)
}
}
29 changes: 29 additions & 0 deletions Projects/Data/Sources/Transform/HourlyWeatherTransform.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// HourlyWeatherTransform.swift
// Data
//
// Created by 류희재 on 2023/11/16.
// Copyright © 2023 hellohidi. All rights reserved.
//

import Foundation

import Core
import Networks
import Domain

extension HourlyWeatherEntity {
public func toDomain() -> [HourlyWeatherModel] {
var hourlyWeatherData: [HourlyWeatherModel] = []
for hourlyWeather in list {
hourlyWeatherData.append(
HourlyWeatherModel(
time: WeatherUtil.makedtTextToTime(hourlyWeather.dtTxt),
temparature: hourlyWeather.main.temp,
weatherImage: WeatherUtil.weatherIconToUrl(hourlyWeather.weather[0].icon)
)
)
}
return hourlyWeatherData
}
}
31 changes: 31 additions & 0 deletions Projects/Domain/Sources/Model/CurrentWeatherModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// WeatherModel.swift
// Domain
//
// Created by 류희재 on 2023/10/24.
// Copyright © 2023 hellohidi. All rights reserved.
//

import RxSwift
import RxCocoa

public struct CurrentWeatherModel {
public let time, place, weather: String
public let temparature, maxTemparature, minTemparature: Double

public init(
time: String,
place: String,
weather: String,
temparature: Double,
maxTemparature: Double,
minTemparature: Double
) {
self.time = time
self.place = place
self.weather = weather
self.temparature = temparature
self.maxTemparature = maxTemparature
self.minTemparature = minTemparature
}
}
22 changes: 22 additions & 0 deletions Projects/Domain/Sources/Model/HourlyWeatherModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// WeatherHourlyModel.swift
// Domain
//
// Created by 류희재 on 2023/10/25.
// Copyright © 2023 hellohidi. All rights reserved.
//

import UIKit

import DSKit

public struct HourlyWeatherModel {
public let time, weatherImage: String
public let temparature: Double

public init(time: String, temparature: Double, weatherImage: String) {
self.time = time
self.temparature = temparature
self.weatherImage = weatherImage
}
}
Loading