Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/developeracademy-postech/2024-nc2-m41-homekit
https://github.com/developeracademy-postech/2024-nc2-m41-homekit
Last synced: about 11 hours ago
JSON representation
- Host: GitHub
- URL: https://github.com/developeracademy-postech/2024-nc2-m41-homekit
- Owner: DeveloperAcademy-POSTECH
- Created: 2024-06-20T14:02:08.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2024-06-23T05:32:43.000Z (5 months ago)
- Last Synced: 2024-11-17T06:16:26.910Z (about 11 hours ago)
- Language: Swift
- Size: 77.1 KB
- Stars: 0
- Watchers: 2
- Forks: 1
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# 2024-NC2-M41-HomeKit
## π₯ Youtube Link
(μΆν λ§λ€μ΄μ§ μ νλΈ λ§ν¬ μΆκ°)## π‘ About Augmented Reality
(ν΄λΉ κΈ°μ μ λν μ‘°μ¬ λ΄μ© μ 리)
> νν·μ λ°νμΌλ‘ ν΄λν°μ μ΄μ©ν΄ μ§μ μλ μ ꡬλ₯Ό μ‘°μν μ μλ€## π― What we focus on?
> ν μ±μ μΆκ°λ κΈ°κΈ°λ₯Ό λΆλ¬μμ μ± λ΄μμ νμ΄λ¨Έλ₯Ό μ€μ νλ©΄ νμ΄λ¨Έ μ’ λ£μκ°μ λ§μΆμ΄ κΈ°κΈ°(μ ꡬ)μ μ λ©Έμ ν΅ν΄ μ¬μ©μμκ² μ립λλ€.
> μ²κ°μ₯μ μΈμ μ£Όμ μ± μ¬μ©μλ‘ μ€μ νμ΅λλ€. μ리λ₯Ό μΈμ§ν μ μλ λμμ μν΄ μ리 λμ μ ꡬμ μ λ©Έλ‘ μ΄λ ν μν©μ μ리μλ λͺ©νλ₯Ό μΈμ κ³ , κ·Έ μ€μμλ μκ°μ μ¬κ³ μ’ λ£ μμ μ νμ€ν μΈμ§ν΄μΌ νλ μΌμ μ΄μ μ λμμ΅λλ€.## πΌ Use Case
>- μΈνκΈ°λ₯Ό μλν νμ μ’ λ£ μμ μ λ§μΆμ΄ νμ΄λ¨Έλ₯Ό μ€μ νκ³ μ¬μ©νλ€.
>- λ°₯μ₯μΌλ‘ λ°₯μ μ§κ³ νμ΄λ¨Έλ₯Ό μ€μ νλ€.
>- μμ‘μ μΆλλ°μ μκ°μ΄ μ€λ 걸리λλ° κ³μν΄μ λ³΄κ³ μμ μ μκΈ° λλ¬Έμ νμ΄λ¨Έλ₯Ό μ€μ νλ€.## πΌοΈ Prototype
https://github.com/DeveloperAcademy-POSTECH/2024-NC2--M-41-HomeKit/assets/167425685/bff8b5bb-4130-4d9f-aca5-3817100ed49d
>- μ§μμ λ°©μΌλ‘ μ κ·Όν΄ νμ΄λ¨Έμ μ‘°λͺ μ μ€μ νκ³ , νμ΄λ¨Έλ₯Ό μλμν¬ μ μμ΅λλ€.
>- μ μΈμ리μμ μ μΈμ리 κ°κ°μ λν μνλ₯Ό μ μν μ μμ΅λλ€.
>- μ΅κ·Ό μ¬μ©ν νμ΄λ¨Έμμ κ°μ₯ μ΅κ·Όμ μ¬μ©ν νμ΄λ¨Έλ₯Ό λ³Ό μ μμ΅λλ€. μμ£Ό μ¬μ©νλ κΈ°λ₯μ΄λΌλ©΄ μ΅κ·Ό μ¬μ©ν νμ΄λ¨Έμμ κ³μ λ³Ό μ μμ΄ μ¬μ©μνμ λμμ΄ λ©λλ€.## π οΈ About Code
νμ΄λ¨Έλ₯Ό μ€μ ν λ€ μ’ λ£λλ©΄ μ κ΅¬κ° μ λ©Ένλ€
```swift
import SwiftUI
import Combine
import HomeKitstruct TimerView: View {
@ObservedObject var homeKitManager: HomeKitManager
@StateObject private var timerViewModel = TimerViewModel()
@Binding var timerFinished: Bool
@Binding var selectedTime: String
@Binding var showPickerSection: Bool
let timerTitle: String
private let lightController: LightController
let accessory: HMAccessory
// μ΄λ λΆλΆ
init(accessory: HMAccessory, homeKitManager: HomeKitManager, lightController: LightController, timerFinished: Binding, selectedTime: Binding, showPickerSection: Binding, timerTitle: String) {
self.accessory = accessory
self.homeKitManager = homeKitManager
self.lightController = lightController
self._timerFinished = timerFinished
self._selectedTime = selectedTime
self._showPickerSection = showPickerSection
self.timerTitle = timerTitle
}
var body: some View {
VStack {
// νμ΄λ¨Έ μ λͺ© (Ex. λΉ¨λ ν 건쑰)
HStack{
Text(timerTitle)
.font(.title)
.padding(.leading)
.bold()
.foregroundStyle(Color.white)
Spacer()
}
.padding(.vertical, 20)
// νμ΄λ¨Έ λμκ°λ μ«μ λΆλΆ
ZStack{
// νμ΄λ¨Έ μ«μ
Text(timerViewModel.timeString)
.font(.system(size: 40))
.padding()
.foregroundStyle(Color.white)
// μν νλ‘κ·Έλ μ€λ·°
RadialProgressView(progress: timerViewModel.progress)
.frame(width: 250, height: 250)
// μκ³
}
.padding(.bottom, 20)
// μ·¨μ, μΌμμ μ§/μμ λ²νΌ
HStack {
// μ·¨μλ²νΌ
Button(action: timerViewModel.reset) {
Text("μ·¨μ")
.foregroundColor(.white)
.frame(width: 92, height: 92)
.background(Color.gray.opacity(0.3))
.clipShape(Circle())
}
Spacer()
// μΌμμ μ§/μμ λ²νΌ
Button(action: timerViewModel.toggleTimer) {
Text(timerViewModel.isRunning ? "μΌμμ μ§" : "μμ")
.foregroundColor(timerViewModel.isRunning ? Color.yellow : Color.green)
.frame(width: 92, height: 92)
.background(timerViewModel.isRunning ? Color.yellow.opacity(0.3) : Color.green.opacity(0.3))
.clipShape(Circle())
}
}
.padding(.horizontal)
Spacer()
}
.background(Color.bgPrimaryDarkBase)
// νλ©΄μ΄ λνλ¬μλ
.onAppear {
let timeComponents = selectedTime.split(separator: ":").map { String($0) }
if timeComponents.count == 3 {
if let hours = Int(timeComponents[0]), let minutes = Int(timeComponents[1]), let seconds = Int(timeComponents[2]) {
timerViewModel.selectedHours = hours
timerViewModel.selectedMinutes = minutes
timerViewModel.selectedSeconds = seconds
timerViewModel.reset()
}
}
}
// νμ΄λ¨Έκ° μ’ λ£λμμ λ
.onChange(of: timerViewModel.timerFinished, initial: false) { oldValue, newValue in
if newValue {
lightController.startBlinkingBulb(for: accessory)
}
else {
lightController.stopBlinkingBulb()
}
}
//ν΄ λ° μ’ λ£λ²νΌ
.toolbar {
Button("μ’ λ£"){
lightController.stopBlinkingBulb()
}
.foregroundStyle(Color.appYellow)
}
}
}// νμ΄λ¨Έ μ€μ νλ λΆλΆ
struct PickerSection: View {
@Binding var selectedTime: String
@Binding var showPickerSection: Bool
@ObservedObject var timerViewModel: TimerViewModel
var body: some View {
VStack{
// μκ°, λΆ, μ΄ μ€μ
HStack {
// μκ° μ€μ
Picker("Hours", selection: $timerViewModel.selectedHours) {
ForEach(0..<24) { hour in
Text("\(hour) h").tag(hour)
}
}
.pickerStyle(WheelPickerStyle())
.frame(width: 90)
.clipped()
// λΆ μ€μ
Picker("Minutes", selection: $timerViewModel.selectedMinutes) {
ForEach(0..<60) { minute in
Text("\(minute) m").tag(minute)
}
}
.pickerStyle(WheelPickerStyle())
.frame(width: 90)
.clipped()
// μ΄ μ€μ
Picker("Seconds", selection: $timerViewModel.selectedSeconds) {
ForEach(0..<60) { second in
Text("\(second) s").tag(second)
}
}
.pickerStyle(WheelPickerStyle())
.frame(width: 90)
.clipped()
}
.padding()
// μ ν μλ£ ν λ²νΌμ λλ₯΄λ©΄ μμ μ«μκ° λ³κ²½λλ€
Button("set time") {
selectedTime = String(format: "%02d:%02d:%02d", timerViewModel.selectedHours, timerViewModel.selectedMinutes, timerViewModel.selectedSeconds)
showPickerSection = false
}
}
}
}// μν νλ‘κ·Έλ μ€λ·°
struct RadialProgressView: View {
var progress: Double
var body: some View {
ZStack {
Circle()
.stroke(lineWidth: 20.0)
.opacity(0.3)
.foregroundColor(Color.appYellow)
Circle()
.trim(from: 0.0, to: CGFloat(min(progress, 1.0)))
.stroke(style: StrokeStyle(lineWidth: 20.0, lineCap: .round, lineJoin: .round))
.foregroundColor(Color.appYellow)
.rotationEffect(Angle(degrees: 270.0))
.opacity(0.8)
.animation(.linear, value: progress)
}
}
}// νμ΄λ¨Έ λͺ¨λΈ.. κ΅μ₯ν 볡μ‘..
class TimerViewModel: ObservableObject {
@Published var timeString: String = "00:00:00"
@Published var progress: Double = 1.0
@Published var selectedHours: Int = 0
@Published var selectedMinutes: Int = 0
@Published var selectedSeconds: Int = 0
@Published var savedTimes: [String] = []
@Published var isRunning: Bool = false
@Published var timerFinished: Bool = false
private var cancellable: AnyCancellable?
private var totalTime: TimeInterval = 0
private var remainingTime: TimeInterval = 0
// νμ΄λ¨Έ on/off
func toggleTimer() {
if isRunning {
stop()
} else {
start()
}
}
// νμ΄λ¨Έκ° μμλλ€
func start() {
stop()
totalTime = TimeInterval(selectedHours * 3600 + selectedMinutes * 60 + selectedSeconds)
remainingTime = totalTime
isRunning = true
timerFinished = false
cancellable = Timer.publish(every: 1.0, on: .main, in: .common)
.autoconnect()
.sink { _ in
self.updateTime()
}
}
// νμ΄λ¨Έ μ μ§
func stop() {
cancellable?.cancel()
cancellable = nil
isRunning = false
}
// νμ΄λ¨Έ 리μ
func reset() {
stop()
remainingTime = totalTime
progress = 1.0
timeString = formatTime(time: remainingTime)
timerFinished = false
}
// μκ° μ μ₯μΈλ° CRUD μ€ν¨λ‘ μ¬μ©νμ§ λͺ»ν μμ΄..
func saveTime() {
let savedTime = String(format: "%02d:%02d:%02d", selectedHours, selectedMinutes, selectedSeconds)
savedTimes.append(savedTime)
}
// μκ° μ λ
private func updateTime() {
if remainingTime > 0 {
remainingTime -= 1
}
timeString = formatTime(time: remainingTime)
progress = totalTime > 0 ? remainingTime / totalTime : 1.0
if remainingTime == 0 {
stop()
timerFinished = true
}
}
// μκ°μ λ¬Έμμ΄λ‘ ν¬λ§·ν
private func formatTime(time: TimeInterval) -> String {
let hours = Int(time) / 3600
let minutes = (Int(time) % 3600) / 60
let seconds = Int(time) % 60
return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
}
}```