Skip to content

Commit

Permalink
Merge pull request #126 from depromeet/feat/#122-watch-workout
Browse files Browse the repository at this point in the history
[Feat/#122] watchOS 기능 구현
  • Loading branch information
mooyoung2309 committed Jul 7, 2023
2 parents b5942ca + 4c96a87 commit 7589819
Show file tree
Hide file tree
Showing 105 changed files with 3,847 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public extension ModulePath {

public extension ModulePath {
enum WatchShared: String, CaseIterable {
case Util
case DesignSystem
case ThirdPartyLib

Expand Down
33 changes: 8 additions & 25 deletions Projects/App/WatchExtension/Sources/App/RootApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,24 @@
//

import SwiftUI

import ComposableArchitecture

import WatchSharedDesignSystem

@main
struct RootApp: App {
@StateObject private var workoutDelegate = WorkoutDelegate()
@StateObject private var watchConnectivityDelegate = WatchConnectivityDelegate()
private var workoutDelegate = WorkoutDelegate()
private var watchConnectivityDelegate = WatchConnectivityDelegate()

@SceneBuilder var body: some Scene {
WindowGroup {
RootView(store: .init(initialState: RootStore.State(), reducer: RootStore()._printChanges()))
.environmentObject(workoutDelegate)
.environmentObject(watchConnectivityDelegate)
.onAppear {
WatchSharedDesignSystemFontFamily.registerAllCustomFonts()
}
}
}
}

//TODO: workout session 으로 마이그레이션 후 주석 제거

//@main
//struct RootApp: App {
// @StateObject private var workoutManager = WorkoutManager()
//
// @SceneBuilder var body: some Scene {
// WindowGroup {
// NavigationStack {
// StartView()
// }
// .onAppear {
// workoutManager.requestAuthorization()
// }
// .sheet(isPresented: $workoutManager.showingSummaryView) {
// SummaryView()
// }
// .environmentObject(workoutManager)
// }
// }
//}
//
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import ComposableArchitecture
public class WatchConnectivityDelegate: NSObject, ObservableObject, WCSessionDelegate {
public weak var session: WCSession?

@Published public var pumpingTimerData: PumpingTimerData = .init(timers: [], updatedTime: Date().timeIntervalSince1970)

init(session: WCSession = .default) {
self.session = session

Expand All @@ -23,14 +25,34 @@ public class WatchConnectivityDelegate: NSObject, ObservableObject, WCSessionDel
}

public func sendMessage(key: String, value: Double) {
self.session?.sendMessage([key: value], replyHandler: nil)
DispatchQueue.main.async {
self.session?.sendMessage([key: value], replyHandler: nil)
debugPrint("watchOS send key: \(key) value: \(value)")
}
}

public func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
public func sendPumpingTimerData() {

}

public func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
}

public func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
debugPrint("watchOS recieved \(message)")
DispatchQueue.main.async {
debugPrint("watchOS recieved \(message)")
}
}

public func session(_ session: WCSession, didReceiveMessageData messageData: Data) {
DispatchQueue.main.async {
do {
let pumpingTimerData = try JSONDecoder().decode(PumpingTimerData.self, from: messageData)
self.pumpingTimerData = pumpingTimerData
debugPrint("watchOS recieved \(pumpingTimerData)")
} catch {
debugPrint(error)
}
}
}
}
17 changes: 2 additions & 15 deletions Projects/App/WatchExtension/Sources/App/WorkoutDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,30 +62,17 @@ public class WorkoutDelegate: NSObject, ObservableObject {
}
}

func requestAuth() {
func requestAuthorization(completion: @escaping (Bool, Error?) -> Void) {
let typesToShare: Set = [
HKQuantityType.workoutType()
]

let typesToRead: Set = [
HKQuantityType.quantityType(forIdentifier: .heartRate)!,
HKQuantityType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKObjectType.activitySummaryType()
]

healthStore.requestAuthorization(toShare: typesToShare, read: typesToRead) { (success, error) in
DispatchQueue.main.async {
if error != nil {
print(error.debugDescription)
} else {
if success {
print("권한이 허락되었습니다")
} else {
print("권한이 없습니다")
}
}
}
}
healthStore.requestAuthorization(toShare: typesToShare, read: typesToRead, completion: completion)
}
}

Expand Down
9 changes: 0 additions & 9 deletions Projects/App/WatchExtension/Sources/Domain/HealthClient.swift

This file was deleted.

41 changes: 41 additions & 0 deletions Projects/App/WatchExtension/Sources/Domain/PumpingTimer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// PumpingTimer.swift
// AppWatchExtension
//
// Created by 송영모 on 2023/07/04.
//

import Foundation

public struct PumpingTimer: Codable, Equatable {
public let id: UUID
public let workoutCategoryIdentifier: WorkoutCategoryIdentifier
public var time: Int

public var heartRateSum: Double
public var heartRateCount: Int
public var calorie: Double

public var pinTime: Int
public var isActive: Bool

public init(
id: UUID,
workoutCategoryIdentifier: WorkoutCategoryIdentifier,
time: Int = 0,
heartRateSum: Double = 0.0,
heartRateCount: Int = 0,
calorie: Double = 0,
pinTime: Int = 0,
isActive: Bool = false
) {
self.id = id
self.workoutCategoryIdentifier = workoutCategoryIdentifier
self.time = time
self.heartRateSum = heartRateSum
self.heartRateCount = heartRateCount
self.calorie = calorie
self.pinTime = pinTime
self.isActive = isActive
}
}
23 changes: 23 additions & 0 deletions Projects/App/WatchExtension/Sources/Domain/PumpingTimerData.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// PumpingTimerData.swift
// AppWatchExtension
//
// Created by 송영모 on 2023/07/04.
//

import Foundation

public struct PumpingTimerData: Codable, Equatable {
public let timers: [PumpingTimer]
public let updatedTime: Double
public let isHardPush: Bool

public init(
timers: [PumpingTimer],
updatedTime: Double,
isHardPush: Bool = false) {
self.timers = timers
self.updatedTime = updatedTime
self.isHardPush = isHardPush
}
}
51 changes: 51 additions & 0 deletions Projects/App/WatchExtension/Sources/Domain/WorkoutCategory.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// WorkoutCategory.swift
// AppWatchExtension
//
// Created by 송영모 on 2023/07/04.
//

import Foundation

//MARK: WorkoutCategoryIdentifierType
public enum WorkoutCategoryIdentifierType: String, CaseIterable {
case whole = "전신"
case upper = "상체"
case lower = "하체"
}

public extension WorkoutCategoryIdentifierType {
var identifiers: [WorkoutCategoryIdentifier] {
switch self {
case .whole:
return [.aerobic]
case .upper:
return [.shoulder, .chest, .arms, .back]
case .lower:
return [.butt]
}
}
}

//MARK: WorkoutCategoryIdentifier
public enum WorkoutCategoryIdentifier: String, Codable, CaseIterable, Equatable {
case aerobic = "유산소"
case shoulder = "어깨"
case chest = "가슴"
case arms = ""
case back = ""
case butt = "엉덩이"
}

public extension WorkoutCategoryIdentifier {
var type: WorkoutCategoryIdentifierType {
switch self {
case .aerobic:
return .whole
case .shoulder, .chest, .arms, .back:
return .upper
case .butt:
return .lower
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//
// TimerCellStore.swift
// Pumping
//
// Created by 송영모 on 2023/07/05.
//

import SwiftUI

import ComposableArchitecture

import WatchSharedDesignSystem
import WatchSharedUtil

public struct TimerCellStore: ReducerProtocol {
public enum ResultType {
case time, heatRate, calorie

public var title: String {
switch self {
case .time: return "총 시간"
case .heatRate: return "심박수"
case .calorie: return "총 칼로리"
}
}

public var image: Image {
switch self {
case .time: return PumpingImages.iconTimer.swiftUIImage
case .heatRate: return PumpingImages.iconHeartbeat.swiftUIImage
case .calorie: return PumpingImages.iconFire.swiftUIImage
}
}

public func toSyntax(value: Double) -> String {
switch self {
case .time:
return DateManager.toClockString(from: Int(value))

case .heatRate:
if value == 0 {
return "-"
} else {
return String(describing: "\(Int(value))bpm")
}

case .calorie:
if value == 0 {
return "-"
} else {
return String(describing: "\(Int(value))Kcal")
}
}
}
}

public struct State: Equatable, Identifiable {
public let id: UUID
public let timer: PumpingTimer

public init(id: UUID, timer: PumpingTimer) {
self.id = id
self.timer = timer
}
}

public enum Action: Equatable {
case tapped
}

public func reduce(into state: inout State, action: Action) -> EffectTask<Action> {
switch action {
case .tapped:
return .none
}
}
}
Loading

0 comments on commit 7589819

Please sign in to comment.