Skip to content

Commit

Permalink
Merge pull request #16 from DO-SOPT-iOS-Part/Assignment/#15
Browse files Browse the repository at this point in the history
[Assignment] 4주차 과제
  • Loading branch information
HELLOHIDI authored Nov 22, 2023
2 parents fd0f1f8 + c437279 commit fde14b2
Show file tree
Hide file tree
Showing 46 changed files with 1,217 additions and 366 deletions.
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

0 comments on commit fde14b2

Please sign in to comment.