Skip to content
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
25 changes: 25 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
## 🌱 작업한 내용

<!-- 아래 리스트를 지우고, 작업 내용을 적어주세요. -->

- 작업 내용 1

## 🌱 PR Point

<!-- 피드백을 받고 싶은 부분이나, 공유하고 싶은 부분을 적어주세요. -->

- PR Point 1

## 📸 스크린샷

<!-- 작업한 화면이 있다면 스크린 샷으로 첨부해주세요. -->

| 구현 내용 | 스크린샷 |
| :-------------: | :----------: |
| ex. 로그인 화면 | 파일첨부바람 |

## 📮 관련 이슈

<!-- 작업한 이슈번호를 # 뒤에 붙여주세요. -->

- Resolved: #이슈번호
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,5 @@ iOSInjectionProject/
/*.gcno
**/xcshareddata/WorkspaceSettings.xcsettings

# End of https://www.toptal.com/developers/gitignore/api/xcode,swift,cocoapods
# End of https://www.toptal.com/developers/gitignore/api/xcode,swift,cocoapods
.DS_Store
16 changes: 16 additions & 0 deletions Runnect-iOS/.swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
disabled_rules:
- trailing_whitespace
- identifier_name
- line_length
- type_name
- legacy_constructor
- unused_setter_value

included:
- Runnect-iOS
excluded:
# AppDelegate, SceneDelegate file 무시
- Runnect-iOS/Global/Supports/AppDelegate.swift
- Runnect-iOS/Global/Supports/SceneDelegate.swift

force_cast: warning
16 changes: 16 additions & 0 deletions Runnect-iOS/Podfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Uncomment the next line to define a global platform for your project
platform :ios, '14.0'

target 'Runnect-iOS' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!

pod 'NMapsMap'
pod 'Kingfisher', '~> 7.0'
pod 'SnapKit', '~> 5.6.0'
pod 'Moya', '~> 15.0'


# Pods for Runnect-iOS

end
38 changes: 38 additions & 0 deletions Runnect-iOS/Podfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
PODS:
- Alamofire (5.6.4)
- Kingfisher (7.4.1)
- Moya (15.0.0):
- Moya/Core (= 15.0.0)
- Moya/Core (15.0.0):
- Alamofire (~> 5.0)
- NMapsGeometry (1.0.1)
- NMapsMap (3.16.1):
- NMapsGeometry
- SnapKit (5.6.0)

DEPENDENCIES:
- Kingfisher (~> 7.0)
- Moya (~> 15.0)
- NMapsMap
- SnapKit (~> 5.6.0)

SPEC REPOS:
trunk:
- Alamofire
- Kingfisher
- Moya
- NMapsGeometry
- NMapsMap
- SnapKit

SPEC CHECKSUMS:
Alamofire: 4e95d97098eacb88856099c4fc79b526a299e48c
Kingfisher: cd762a593a61b2fbecf7645c00f9a801a3ebfc9c
Moya: 138f0573e53411fb3dc17016add0b748dfbd78ee
NMapsGeometry: 53c573ead66466681cf123f99f698dc8071a4b83
NMapsMap: 926c3a303d381a24bec8da3cd6e198f50af93ae9
SnapKit: e01d52ebb8ddbc333eefe2132acf85c8227d9c25

PODFILE CHECKSUM: f23513cb80e72754bbf29355e1160abe4b35c783

COCOAPODS: 1.11.3
778 changes: 778 additions & 0 deletions Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
10 changes: 10 additions & 0 deletions Runnect-iOS/Runnect-iOS.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
25 changes: 25 additions & 0 deletions Runnect-iOS/Runnect-iOS/Global/Extension/Combine+/CancelBag.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// CancelBag.swift
// Runnect-iOS
//
// Created by sejin on 2022/12/29.
//

import Combine

class CancelBag {
var subscriptions = Set<AnyCancellable>()

func cancel() {
subscriptions.forEach { $0.cancel() }
subscriptions.removeAll()
}

init() { }
}

extension AnyCancellable {
func store(in cancelBag: CancelBag) {
cancelBag.subscriptions.insert(self)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// Publisher+Driver.swift
// Runnect-iOS
//
// Created by sejin on 2022/12/29.
//

import Combine
import Foundation

public typealias Driver<T> = AnyPublisher<T, Never>

public extension Publisher {
func asDriver() -> Driver<Output> {
return self.catch { _ in Empty() }
.receive(on: RunLoop.main)
.eraseToAnyPublisher()
}

static func just(_ output: Output) -> Driver<Output> {
return Just(output).eraseToAnyPublisher()
}

static func empty() -> Driver<Output> {
return Empty().eraseToAnyPublisher()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// Publisher+UIControl.swift
// Runnect-iOS
//
// Created by sejin on 2022/12/29.
//

import UIKit
import Combine

protocol CombineCompatible { }

extension UIControl: CombineCompatible { }

extension CombineCompatible where Self: UIControl {
func publisher(for events: UIControl.Event) -> UIControlPublisher<Self> {
return UIControlPublisher(control: self, events: events)
}
}

final class UIControlSubscription<SubscriberType: Subscriber, Control: UIControl>: Subscription where SubscriberType.Input == Control {
private var subscriber: SubscriberType?
private let control: Control

init(subscriber: SubscriberType, control: Control, event: UIControl.Event) {
self.subscriber = subscriber
self.control = control
control.addTarget(self, action: #selector(eventHandler), for: event)
}

func request(_ demand: Subscribers.Demand) {

}

func cancel() {
subscriber = nil
}

@objc private func eventHandler() {
_ = subscriber?.receive(control)
}
}

struct UIControlPublisher<Control: UIControl>: Publisher {

public typealias Output = Control
public typealias Failure = Never

let control: Control
let controlEvents: UIControl.Event

init(control: Control, events: UIControl.Event) {
self.control = control
self.controlEvents = events
}

func receive<S>(subscriber: S) where S: Subscriber,
S.Failure == UIControlPublisher.Failure,
S.Input == UIControlPublisher.Output {
let subscription = UIControlSubscription(subscriber: subscriber, control: control, event: controlEvents)
subscriber.receive(subscription: subscription)
}
}
26 changes: 26 additions & 0 deletions Runnect-iOS/Runnect-iOS/Global/Extension/Foundation+/Result+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// Result+.swift
// Runnect-iOS
//
// Created by sejin on 2022/12/29.
//

import Foundation

extension Result {
@discardableResult
func success(_ successHandler: (Success) -> Void) -> Result<Success, Failure> {
if case .success(let value) = self {
successHandler(value)
}
return self
}

@discardableResult
func `catch`(_ failureHandler: (Failure) -> Void) -> Result<Success, Failure> {
if case .failure(let error) = self {
failureHandler(error)
}
return self
}
}
67 changes: 67 additions & 0 deletions Runnect-iOS/Runnect-iOS/Global/Extension/Foundation+/String+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// String+.swift
// Runnect-iOS
//
// Created by sejin on 2022/12/29.
//

import UIKit

extension String {

/// String을 UIImage로 반환하는 메서드
func makeImage() -> UIImage? {
if let data = Data(base64Encoded: self, options: .ignoreUnknownCharacters) {
return UIImage(data: data)
}
return nil
}

/// 서버에서 들어온 Date String을 Date 타입으로 반환하는 메서드
private func toDate() -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
dateFormatter.timeZone = TimeZone(identifier: "KST")
if let date = dateFormatter.date(from: self) {
return date
} else {
print("toDate() convert error")
return Date()
}
}

/// serverTimeToString의 용도 정의
enum TimeStringCase {
case forNotification
case forDefault
}

/// 서버에서 들어온 Date String을 UI에 적용 가능한 String 타입으로 반환하는 메서드
func serverTimeToString(forUse: TimeStringCase) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yy/MM/dd"

let currentTime = Int(Date().timeIntervalSince1970)

switch forUse {
case .forNotification:
let getTime = self.toDate().timeIntervalSince1970
let displaySec = currentTime - Int(getTime)
let displayMin = displaySec / 60
let displayHour = displayMin / 60
let displayDay = displayHour / 24

if displayDay >= 1 {
return dateFormatter.string(from: self.toDate())
} else if displayHour >= 1 {
return "\(displayHour)시간 전"
} else if displayMin >= 1 {
return "\(displayMin)분 전"
} else {
return "1분 전"
}
case .forDefault:
return dateFormatter.string(from: self.toDate())
}
}
}
20 changes: 20 additions & 0 deletions Runnect-iOS/Runnect-iOS/Global/Extension/Foundation+/URL+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// URL+.swift
// Runnect-iOS
//
// Created by sejin on 2022/12/29.
//

import Foundation

extension URL {
/// - Description: URL에 한국어가 있는 경우, 퍼센트 문자로 치환합니다
static func decodeURL(urlString: String) -> URL? {
if let url = URL(string: urlString) {
return url
} else {
let encodedString = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? urlString
return URL(string: encodedString)
}
}
}
Loading