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
3 changes: 3 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
## 📸 스크린샷

<!-- 작업한 화면이 있다면 스크린 샷으로 첨부해주세요. -->
<!-- 큰 이미지, png 짜를때 재사용하세요.
<img src = "이미지주소" width = "50%" height = "50%">
-->

| 구현 내용 | 스크린샷 |
| :-------------: | :----------: |
Expand Down
1 change: 1 addition & 0 deletions Runnect-iOS/.swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ excluded:
# AppDelegate, SceneDelegate file 무시
- Runnect-iOS/Global/Supports/AppDelegate.swift
- Runnect-iOS/Global/Supports/SceneDelegate.swift
- Runnect-iOS/Global/UIComponents/MapView/RNMapView.swift

force_cast: warning
4 changes: 2 additions & 2 deletions Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1703,7 +1703,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2024.0312.0041;
CURRENT_PROJECT_VERSION = 2024.0319.2120;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 8Q4H7X3Q58;
GENERATE_INFOPLIST_FILE = NO;
Expand Down Expand Up @@ -1747,7 +1747,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2024.0312.0041;
CURRENT_PROJECT_VERSION = 2024.0319.2120;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 8Q4H7X3Q58;
GENERATE_INFOPLIST_FILE = NO;
Expand Down
3 changes: 2 additions & 1 deletion Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ enum ImageLiterals {
static var icTime: UIImage { .load(named: "ic_time") }
static var icLocationPoint: UIImage { .load(named: "ic_location_point") }
static var icAlert: UIImage { .load(named: "ic_alert") }
static var icLocationOverlay: UIImage { .load(named: "ic_location_overlay") }
static var icLocationOverlayDirection: UIImage { .load(named: "ic_location_overlay_direction") }
static var icLocationOverlayNormal: UIImage { .load(named: "ic_location_overlay_normal") }
static var icLogoCircle: UIImage { .load(named: "ic_logo_circle") }
static var icMore: UIImage { .load(named: "ic_more") }
static var icPlus: UIImage { .load(named: "ic_plus") }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "Group 9581.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group 9581@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group 9581@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
118 changes: 77 additions & 41 deletions Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNMapView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ final class RNMapView: UIView {
private let screenHeight = UIScreen.main.bounds.height

let pathImage = PassthroughSubject<UIImage?, Never>()
private var cancelBag = Set<AnyCancellable>()
private var cancelBag = CancelBag()

private let locationManager = CLLocationManager()
private var isDrawMode: Bool = false
Expand All @@ -40,7 +40,8 @@ final class RNMapView: UIView {
[self.startMarker.position] + self.markers.map { $0.position }
}
private var bottomPadding: CGFloat = 0
private let locationOverlayIcon = NMFOverlayImage(image: ImageLiterals.icLocationOverlay)
private let locationOverlayIconDirection = NMFOverlayImage(image: ImageLiterals.icLocationOverlayDirection)
private let locationOverlayIconNormal = NMFOverlayImage(image: ImageLiterals.icLocationOverlayNormal)

// MARK: - UI Components

Expand All @@ -59,16 +60,17 @@ final class RNMapView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
self.mapInit()
setLocationOverlay()
}

private func mapInit() {
setUI()
setLayout()
setBind()
setDelegate()
setMap()
getLocationAuth()
setPathOverlay()
observePositionModeChanges()
}

required init?(coder: NSCoder) {
Expand All @@ -90,7 +92,12 @@ extension RNMapView {
@discardableResult
func setPositionMode(mode: NMFMyPositionMode) -> Self {
map.mapView.positionMode = mode
setLocationOverlay()
switch mode {
case .direction:
setDirectionModeLocationOverlay()
default:
setNormalModeLocationOverLay()
}
return self
}

Expand Down Expand Up @@ -154,26 +161,6 @@ extension RNMapView {
return self
}

/// 캡처를 위한 좌표 설정 및 카메라 이동
func makeCameraMoveForCapture(at locations: [NMGLatLng]) {
map.mapView.contentInset = UIEdgeInsets(top: screenHeight/4, left: 0, bottom: screenHeight/4, right: 0)
let bounds = makeMBR(at: locations)
let cameraUpdate = NMFCameraUpdate(fit: bounds, padding: 100)
cameraUpdate.animation = .none
LoadingIndicator.showLoading()
map.mapView.moveCamera(cameraUpdate) { isCancelled in
if isCancelled {
print("카메라 이동 취소")
LoadingIndicator.hideLoading()
} else {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.makePathImage()
LoadingIndicator.hideLoading()
}
}
}
}

/// 사용자 위치로 카메라 이동
@discardableResult
func moveToUserLocation() -> Self {
Expand Down Expand Up @@ -285,6 +272,26 @@ extension RNMapView {
}
}

/// 캡처를 위한 좌표 설정 및 카메라 이동
private func makeCameraMoveForCapture(at locations: [NMGLatLng]) {
map.mapView.contentInset = UIEdgeInsets(top: screenHeight/4, left: 0, bottom: screenHeight/4, right: 0)
let bounds = makeMBR(at: locations)
let cameraUpdate = NMFCameraUpdate(fit: bounds, padding: 100)
cameraUpdate.animation = .none
LoadingIndicator.showLoading()
map.mapView.moveCamera(cameraUpdate) { isCancelled in
if isCancelled {
print("카메라 이동 취소")
LoadingIndicator.hideLoading()
} else {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.makePathImage()
LoadingIndicator.hideLoading()
}
}
}
}

// 두 지점 사이의 거리(m) 추가
private func addDistance(with newLocation: NMGLatLng) {
let lastCLLoc = markersLatLngs.last?.toCLLocation()
Expand Down Expand Up @@ -331,29 +338,62 @@ extension RNMapView {
map.mapView.touchDelegate = self
}

private func setPathOverlay() {
private func setPathOverlay() { // 코스 path UI 설정
pathOverlay.width = 4
pathOverlay.outlineWidth = 0
pathOverlay.color = .m1
}

private func setLocationOverlay() {
private func setDirectionModeLocationOverlay() {
let locationOverlay = map.mapView.locationOverlay
locationOverlay.icon = locationOverlayIconDirection
}

private func setNormalModeLocationOverLay() {
let locationOverlay = map.mapView.locationOverlay
locationOverlay.icon = locationOverlayIcon
locationOverlay.icon = locationOverlayIconNormal
}

private func observePositionModeChanges() {
map.mapView.addObserver(self, forKeyPath: "positionMode", options: [.new, .old], context: nil)
Copy link
Collaborator

Choose a reason for hiding this comment

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

요 부분 어떤건지 설명해줄 수 있나용 ?!?

Copy link
Collaborator Author

@thingineeer thingineeer Mar 18, 2024

Choose a reason for hiding this comment

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

addObserver로 이벤트 전달을 위에 override 한 observeValue 함수로 전달하는 거예요!
observePositionModeChanges() 함수에서 keyPath "positionMode"를 해놓아서 저게 관찰이 될 때, observeValue() 함수가 호출되는 구조에요!

이 부분 참고하면 많은 도움이 될 것 같아요!
https://github.com/navermaps/ios-map-sdk/blob/117017002b9a25d39bcfc2084843ee523e4bb2d9/NaverMapDemo/LocationTrackingViewController.swift#L31

Copy link
Collaborator

Choose a reason for hiding this comment

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

확인했습니다 ~~ 답장이 늦었지만 감사합니다 명진센세 !!!

}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
// positionMode가 변경될 때 호출됩니다.
if keyPath == "positionMode", object is NMFMapView {
DispatchQueue.main.async { [weak self] in
self?.updateStateName()
}
}
}
Comment on lines +361 to +368
Copy link
Collaborator

Choose a reason for hiding this comment

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

이 함수는 positionMode에 변경이 생기면 자동으로 호출되는 함수이고
변경된 positionMode에 따라서 setNormalModeLocationOverLay() 혹은 setDirectionModeLocationOverlay()를 호출하는 것으로 이해하면 될까요 ?!

Copy link
Collaborator Author

@thingineeer thingineeer Mar 18, 2024

Choose a reason for hiding this comment

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

네 맞습니다! 아래 observePositionModeChanges() 함수 부분 설명도 들어주시면 감사할 것 같아요!


private func updateStateName() {
let stateStr: String
switch map.mapView.positionMode {
case .normal:
stateStr = "NoFollow"
setNormalModeLocationOverLay()
case .direction:
stateStr = "Follow"
setDirectionModeLocationOverlay()
default:
stateStr = "otherAction"
}

print("Position Mode: \(stateStr)")
}
}

// MARK: - UI & Layout

extension RNMapView {
private func setUI() {
private func setUI() { // 현재 위치를 찍는 아이콘의 UI 구현
self.backgroundColor = .white
self.locationButton.setImage(ImageLiterals.icMapLocation, for: .normal)
self.locationButton.isHidden = true
self.locationButton.addTarget(self, action: #selector(locationButtonDidTap), for: .touchUpInside)
}

private func setLayout() {
private func setLayout() { // 지도와 현재위치 이동 버튼 의 레이아웃 구성
addSubviews(map, locationButton)

map.snp.makeConstraints {
Expand All @@ -373,13 +413,11 @@ extension RNMapView {
}
}
}
}

// MARK: - @objc Function

extension RNMapView {
@objc func locationButtonDidTap() {
self.setPositionMode(mode: .direction)

private func setBind() {
locationButton.tapPublisher.sink { [weak self] _ in
self?.setPositionMode(mode: .direction)
}.store(in: cancelBag)
}
}

Expand All @@ -388,11 +426,9 @@ extension RNMapView {
extension RNMapView: NMFMapViewCameraDelegate, NMFMapViewTouchDelegate {
// 지도 탭 이벤트
func mapView(_ mapView: NMFMapView, didTapMap latlng: NMGLatLng, point: CGPoint) {
guard isDrawMode && markers.count < 19 else { return }
guard isDrawMode && markers.count < 25 else { return }
self.makeMarker(at: latlng)
}

func mapView(_ mapView: NMFMapView, cameraWillChangeByReason reason: Int, animated: Bool) {

}

// 지도 이동 멈췄을 때 호출되는 메서드
Expand Down
8 changes: 4 additions & 4 deletions Runnect-iOS/Runnect-iOS/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,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>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>CFBundleIconName</key>
<string>AppIcon</string>
<key>CFBundleDevelopmentRegion</key>
Expand All @@ -19,9 +21,7 @@
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>2.0.1</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<string>2.0.2</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
Expand All @@ -46,7 +46,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>2024.0312.0041</string>
<string>2024.0319.2120</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>kakaokompassauth</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,30 @@
import Foundation

// MARK: - TmapAddressSearchingResponseDto

struct TmapAddressSearchingResponseDto: Codable {
let addressInfo: AddressInfo

func toDepartureLocationModel(latitude: Double, longitude: Double) -> DepartureLocationModel {
let buildingName = self.addressInfo.buildingName.isEmpty ? "내가 설정한 출발지" : self.addressInfo.buildingName
let buildingName = self.addressInfo.buildingName.isEmpty ? "주소를 알 수 없는 출발지" : self.addressInfo.buildingName
Copy link
Collaborator

Choose a reason for hiding this comment

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

문구 변경 확인했습니다 ~


return DepartureLocationModel(departureName: buildingName, departureAddress: addressInfo.fullAddress, latitude: String(latitude), longitude: String(longitude))
return DepartureLocationModel(
departureName: buildingName,
departureAddress: addressInfo.fullAddress,
latitude: String(latitude),
longitude: String(longitude)
)
}
}

// MARK: - AddressInfo

struct AddressInfo: Codable {
let fullAddress, addressType, cityDo, guGun: String
let eupMyun, adminDong, adminDongCode, legalDong: String
let legalDongCode, ri, bunji, roadName: String
let buildingIndex, buildingName, mappingDistance, roadCode: String

enum CodingKeys: String, CodingKey {
case fullAddress, addressType
case cityDo = "city_do"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ extension DepartureSearchingRouter: TargetType {
switch self {
case .getAddress(let keyword):
return .requestParameters(parameters: ["query": keyword], encoding: URLEncoding.default)
case .getLocationAddress(let latitude, let longitude):
case .getLocationAddress(let latitude, let longitude): // 사용하지 않습니다.
return .requestParameters(parameters: ["x": longitude, "y": latitude], encoding: URLEncoding.default)
case .getLocationTmapAddress(let latitude, let longitude):
return .requestParameters(parameters: ["lat": latitude, "lon": longitude, "addressType": "A04", "appKey": Config.tmapAPIKey], encoding: URLEncoding.default)
Expand Down
Loading