Skip to content

Commit

Permalink
Merge pull request #345 from boostcampwm2023/iOS/task/Background-Task
Browse files Browse the repository at this point in the history
[iOS] ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์—…๋ฐ์ดํŠธ
  • Loading branch information
SwiftyJunnos authored Jan 8, 2024
2 parents 302ba8c + e6adaaf commit c5fe526
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Created by ์ด์ฐฝ์ค€ on 2023.12.01.
//

import ActivityKit
import Combine
import UIKit

Expand Down Expand Up @@ -33,6 +34,7 @@ public final class HomeViewController: HomeBottomSheetViewController {
private enum Metric {

static let startButtonBottomInset: CGFloat = 16.0
static let recordJourneyButtonBottomInset: CGFloat = 50.0

enum RefreshButton {
static let topSpacing: CGFloat = 80.0
Expand Down Expand Up @@ -133,7 +135,7 @@ public final class HomeViewController: HomeBottomSheetViewController {
self.viewModel.state.startedJourney
.receive(on: DispatchQueue.main)
.sink { [weak self] startedJourney in
self?.contentViewController.journeyShouldStarted(startedJourney)
self?.contentViewController.recordingShouldStart(startedJourney)
}
.store(in: &self.cancellables)

Expand All @@ -146,13 +148,14 @@ public final class HomeViewController: HomeBottomSheetViewController {

self.viewModel.state.isRecording
.removeDuplicates()
.dropFirst()
.receive(on: DispatchQueue.main)
.sink { [weak self] isRecording in
if isRecording {
self?.hideBottomSheet()
} else {
self?.showBottomSheet()
self?.contentViewController.journeyShouldStopped(isCancelling: false)
self?.contentViewController.recordingShouldStop(isCancelling: false)
}
self?.updateButtonMode(isRecording: isRecording)
}
Expand Down Expand Up @@ -187,22 +190,14 @@ public final class HomeViewController: HomeBottomSheetViewController {
private func updateButtonMode(isRecording: Bool) {
UIView.transition(with: startButton, duration: 0.5,
options: .transitionCrossDissolve,
animations: {
self.startButton.isHidden = isRecording
animations: { [weak self] in
self?.startButton.isHidden = isRecording
})
UIView.transition(with: recordJourneyButtonStackView, duration: 0.5,
options: .transitionCrossDissolve,
animations: {
self.recordJourneyButtonStackView.isHidden = !isRecording
animations: { [weak self] in
self?.recordJourneyButtonStackView.isHidden = !isRecording
})

if isRecording {
self.setUserLocationToCenter()
}
}

private func setUserLocationToCenter() {

}

}
Expand All @@ -213,27 +208,34 @@ extension HomeViewController: RecordJourneyButtonViewDelegate {

private func configureAction() {
let startButtonAction = UIAction { [weak self] _ in
guard let userLocation = self?.contentViewController.userLocation else { return }

let coordinate = Coordinate(latitude: userLocation.coordinate.latitude,
longitude: userLocation.coordinate.longitude)
self?.viewModel.trigger(.startButtonDidTap(coordinate))
self?.startButtonDidTap()
}
self.startButton.addAction(startButtonAction, for: .touchUpInside)

let refreshButtonAction = UIAction { [weak self] _ in
guard let coordinates = self?.contentViewController.visibleCoordinates else { return }

self?.viewModel.trigger(.refreshButtonDidTap(visibleCoordinates: coordinates))
self?.refreshButtonDidTap()
}
self.refreshButton.addAction(refreshButtonAction, for: .touchUpInside)
}

private func startButtonDidTap() {
guard let userLocation = self.contentViewController.userLocation else { return }

let coordinate = Coordinate(latitude: userLocation.coordinate.latitude,
longitude: userLocation.coordinate.longitude)
self.viewModel.trigger(.startButtonDidTap(coordinate))
}

private func refreshButtonDidTap() {
let coordinates = self.contentViewController.visibleCoordinates
self.viewModel.trigger(.refreshButtonDidTap(visibleCoordinates: coordinates))
}

public func backButtonDidTap(_ button: MSRectButton) {
guard self.viewModel.state.isRecording.value == true else { return }

self.viewModel.trigger(.backButtonDidTap)
self.contentViewController.journeyShouldStopped(isCancelling: true)
self.contentViewController.recordingShouldStop(isCancelling: true)
}

public func spotButtonDidTap(_ button: MSRectButton) {
Expand Down Expand Up @@ -289,7 +291,7 @@ private extension HomeViewController {
NSLayoutConstraint.activate([
self.recordJourneyButtonStackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
self.recordJourneyButtonStackView.bottomAnchor.constraint(equalTo: safeAreaBottomAnchor,
constant: -Metric.startButtonBottomInset)
constant: -Metric.recordJourneyButtonBottomInset)
])

self.view.insertSubview(self.refreshButton, belowSubview: self.bottomSheetViewController.view)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Created by ์ด์ฐฝ์ค€ on 2023.12.06.
//

import ActivityKit
import Combine
import Foundation

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extension MapViewController {

extension MapViewController {

public func journeyShouldStarted(_ startedJourney: RecordingJourney) {
public func recordingShouldStart(_ startedJourney: RecordingJourney) {
guard self.viewModel is NavigateMapViewModel else {
MSLogger.make(category: .home).error("์—ฌ์ •์ด ์‹œ์ž‘๋˜์–ด์•ผ ํ•˜์ง€๋งŒ ์ด๋ฏธ Map์—์„œ RecordJourneyViewModel์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.")
return
Expand All @@ -39,9 +39,16 @@ extension MapViewController {
userRepository: userRepository,
journeyRepository: journeyRepository)
self.swapViewModel(to: recordJourneyViewModel)

self.locationManager.startUpdatingLocation()
self.locationManager.allowsBackgroundLocationUpdates = true

#if DEBUG
MSLogger.make(category: .home).debug("์—ฌ์ • ๊ธฐ๋ก์ด ์‹œ์ž‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
#endif
}

public func journeyShouldStopped(isCancelling: Bool) {
public func recordingShouldStop(isCancelling: Bool) {
guard let viewModel = self.viewModel as? RecordJourneyViewModel else {
MSLogger.make(category: .home).error("์—ฌ์ •์ด ์ข…๋ฃŒ๋˜์–ด์•ผ ํ•˜์ง€๋งŒ ์ด๋ฏธ Map์—์„œ NavigateMapViewModel์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.")
return
Expand All @@ -54,6 +61,13 @@ extension MapViewController {
let journeyRepository = JourneyRepositoryImplementation()
let navigateMapViewModel = NavigateMapViewModel(repository: journeyRepository)
self.swapViewModel(to: navigateMapViewModel)

self.locationManager.stopUpdatingLocation()
self.locationManager.allowsBackgroundLocationUpdates = false

#if DEBUG
MSLogger.make(category: .home).debug("์—ฌ์ • ๊ธฐ๋ก์ด ์ข…๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
#endif
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public final class MapViewController: UIViewController {

private enum Typo {

static let locationAlertTitle = "์œ„์น˜ ๊ถŒํ•œ"
static let locationAlertMessage = "์œ„์น˜ ๊ถŒํ•œ์„ ํ—ˆ์šฉํ•˜์‹œ์ง€ ์•Š์•„์„œ ์œ„์น˜ ์ ‘๊ทผ์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."
static let locationAlertTitle = "์œ„์น˜ ๊ถŒํ•œ์ด ํ—ˆ์šฉ๋˜์ง€ ์•Š์Œ"
static let locationAlertMessage = "MusicSpot์€ ์œ„์น˜ ๊ถŒํ•œ์„ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์„ค์ •์—์„œ \"์•ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๋™์•ˆ\" ์ด์ƒ์˜ ๊ถŒํ•œ์„ ํ—ˆ์šฉํ•ด์ฃผ์„ธ์š”."
static let locationAlertCancel = "์ทจ์†Œ"
static let locationAlertSettings = "์„ค์ •"

Expand Down Expand Up @@ -65,7 +65,7 @@ public final class MapViewController: UIViewController {
public weak var delegate: MapViewControllerDelegate?
var viewModel: (any MapViewModel)?

private let locationManager = CLLocationManager()
internal let locationManager = CLLocationManager()

private var cancellables: Set<AnyCancellable> = []

Expand Down Expand Up @@ -118,7 +118,7 @@ public final class MapViewController: UIViewController {

self.configureLayout()
self.configureCoreLocation()
self.bind(viewModel)
self.bind(self.viewModel)
}

// MARK: - Combine Binding
Expand Down Expand Up @@ -169,6 +169,7 @@ public final class MapViewController: UIViewController {
}
return (previousCoordinate, currentCoordinate)
}
.receive(on: DispatchQueue.main)
.sink { [weak self] previousCoordinate, currentCoordinate in
let points = [previousCoordinate, currentCoordinate]
self?.drawPolylineToMap(using: points)
Expand Down Expand Up @@ -294,10 +295,17 @@ private extension MapViewController {
])
}

func configureCoreLocation() {
private func configureCoreLocation() {
self.locationManager.delegate = self
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
switch self.locationManager.authorizationStatus {
case .restricted, .denied:
self.presentLocationAuthorizationAlert()
case .notDetermined:
self.locationManager.requestWhenInUseAuthorization()
default:
return
}
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
}

}
Expand Down Expand Up @@ -341,21 +349,8 @@ extension MapViewController: CLLocationManagerDelegate {
case .notDetermined:
manager.requestWhenInUseAuthorization()
case .restricted, .denied:
let sheet = UIAlertController(title: Typo.locationAlertTitle,
message: Typo.locationAlertMessage,
preferredStyle: .alert)
let cancelAction = UIAlertAction(title: Typo.locationAlertCancel, style: .cancel)
let settingsAction = UIAlertAction(title: Typo.locationAlertSettings, style: .default) { _ in
guard let url = URL(string: UIApplication.openSettingsURLString) else { return }
UIApplication.shared.open(url)
}
sheet.addAction(cancelAction)
sheet.addAction(settingsAction)
DispatchQueue.main.async {
self.present(sheet, animated: true)
}
self.presentLocationAuthorizationAlert()
case .authorizedAlways, .authorizedWhenInUse:
manager.startUpdatingLocation()
self.checkAccuracyAuthorizationStatus(manager)
@unknown default:
MSLogger.make(category: .home).error("์ž˜๋ชป๋œ ์œ„์น˜ ๊ถŒํ•œ์ž…๋‹ˆ๋‹ค.")
Expand All @@ -382,6 +377,22 @@ extension MapViewController: CLLocationManagerDelegate {
return 5 <= location1.distance(from: location2) && location1.distance(from: location2) <= 50
}

private func presentLocationAuthorizationAlert() {
let sheet = UIAlertController(title: Typo.locationAlertTitle,
message: Typo.locationAlertMessage,
preferredStyle: .alert)
let cancelAction = UIAlertAction(title: Typo.locationAlertCancel, style: .cancel)
let settingsAction = UIAlertAction(title: Typo.locationAlertSettings, style: .default) { _ in
guard let url = URL(string: UIApplication.openSettingsURLString) else { return }
UIApplication.shared.open(url)
}
sheet.addAction(cancelAction)
sheet.addAction(settingsAction)
DispatchQueue.main.async {
self.present(sheet, animated: true)
}
}

}

// MARK: - MKMapView
Expand Down
Loading

0 comments on commit c5fe526

Please sign in to comment.