Skip to content

Commit

Permalink
Merge pull request #48 from Team-HMH/feat/#47-BackgroundSchedule
Browse files Browse the repository at this point in the history
Feat [#47] background schedule&FamilyPicker 연결
  • Loading branch information
kim-seonwoo authored Jun 2, 2024
2 parents c3be176 + e5441e5 commit 46dd4e0
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 80 deletions.
32 changes: 10 additions & 22 deletions HMH_iOS/HMH_iOS/Global/Application/MidnightTaskScheduler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,29 @@
// Created by 이지희 on 5/26/24.
//

import BackgroundTasks
import CoreData
import Foundation

class MidnightTaskScheduler {
class MidnightTaskScheduler: ObservableObject {
var timer: Timer?

init() {
BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.example.app.refresh", using: nil) { task in
self.handleAppRefresh(task: task as! BGAppRefreshTask)
}
scheduleMidnightTask()
}

func scheduleMidnightTask() {
let request = BGAppRefreshTaskRequest(identifier: "com.example.app.refresh")
request.earliestBeginDate = nextMidnight() // 다음 자정에 실행되도록 설정
let nextMidnight = nextMidnightDate()
let interval = nextMidnight.timeIntervalSinceNow

do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Unable to submit task: \(error)")
}
timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(executeMidnightTask), userInfo: nil, repeats: false)
print("Timer scheduled to fire at: \(nextMidnight)")
}

func handleAppRefresh(task: BGAppRefreshTask) {
// 데이터 저장 작업 실행
@objc func executeMidnightTask() {
saveDataToLocalDatabase()

// 작업이 끝나면 새로 예약
scheduleMidnightTask()

task.setTaskCompleted(success: true)
}

func nextMidnight() -> Date {
func nextMidnightDate() -> Date {
let now = Date()
var calendar = Calendar.current
calendar.timeZone = TimeZone.current
Expand All @@ -49,7 +37,7 @@ class MidnightTaskScheduler {
}

func saveDataToLocalDatabase() {

print("Data saved to local database.")
// 백그라운드에서 실행할 API 연결
}
}

21 changes: 16 additions & 5 deletions HMH_iOS/HMH_iOS/Global/HMH_iOSApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,21 @@ enum AppState: String {
case home
}


@main
struct HMH_iOSApp: App {
@StateObject var loginViewModel = LoginViewModel()
@StateObject var userManager = UserManager.shared

@StateObject private var scheduler = MidnightTaskScheduler()

let kakaoAPIKey = Bundle.main.infoDictionary?["KAKAO_API_KEY"] as! String
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate


@Environment(\.scenePhase) private var scenePhase

init() {
KakaoSDK.initSDK(appKey: kakaoAPIKey)
}

var body: some Scene {
WindowGroup {
ZStack {
Expand All @@ -48,13 +50,22 @@ struct HMH_iOSApp: App {
case .login:
LoginView(viewModel: loginViewModel)
.onOpenURL { url in
if (AuthApi.isKakaoTalkLoginUrl(url)) {
if AuthApi.isKakaoTalkLoginUrl(url) {
_ = AuthController.handleOpenUrl(url: url)
}
}
}
}
}
}
.onChange(of: scenePhase) { newPhase in
switch newPhase {
case .background:
print("App moved to background.")
scheduler.scheduleMidnightTask()
@unknown default:
break
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ final class ChallengeViewModel: ObservableObject {
@Published var subTitleString = ""
@Published var challengeType: ChallengeType = .empty

@StateObject var screenViewModel = ScreenTimeViewModel()

enum PointStatus {
static let unearned = "UNEARNED"
static let earned = "EARNED"
Expand Down Expand Up @@ -57,18 +59,15 @@ final class ChallengeViewModel: ObservableObject {
}
}

func createChallenge(bundle: [String]) {

let dto = CreateChallengeRequestDTO(period: 7, goalTime: 1204928)
Providers.challengeProvider.request(target: .createChallenge(data: dto), instance: BaseResponse<EmptyResponseDTO>.self) { result in
print(result)
}
func addApp(appGoalTime: Int) {
var applist: [Apps] = []

bundle.forEach { bundleid in
applist.append(Apps(appCode: bundleid, goalTime: 10000000))
screenViewModel.selectedApp.applications.forEach { app in
applist.append(Apps(appCode: app.localizedDisplayName ?? "basic name", goalTime: appGoalTime))
}

screenViewModel.handleStartDeviceActivityMonitoring(includeUsageThreshold: true, interval: appGoalTime)

Providers.challengeProvider.request(target: .addApp(data: AddAppRequestDTO(apps: applist)), instance: BaseResponse<EmptyResponseDTO>.self) { result in
print(result)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@ final class ScreenTimeViewModel: ObservableObject {
}

@Published var sharedHasScreenTimePermission = false
var hashVaule: [Int] = []
@Published var hashVaule: [String] = []


@MainActor func updateSelectedApp(newSelection: FamilyActivitySelection) {
DispatchQueue.main.async {
self.selectedApp = newSelection
print(self.selectedApp.jsonString())
}
}

func saveHashValue() {
selectedApp.applicationTokens.forEach { app in
hashVaule.append(app.hashValue)
}

}

func requestAuthorization() {
Expand Down Expand Up @@ -71,22 +71,23 @@ final class ScreenTimeViewModel: ObservableObject {
func handleStartDeviceActivityMonitoring(includeUsageThreshold: Bool = true, interval: Int) {
//datacomponent타입을 써야함
let dateComponents = Calendar.current.dateComponents([.hour, .minute, .second], from: Date())
let minute: Int = interval / 60000

// 새 스케쥴 시간 설정
let schedule = DeviceActivitySchedule(
intervalStart: DateComponents(hour: dateComponents.hour, minute: dateComponents.minute, second: dateComponents.second),
intervalEnd: DateComponents(hour: 23, minute: 59, second: 59),
repeats: false,
//warning Time 설정해야 알람
warningTime: DateComponents(minute: 1)
warningTime: DateComponents(minute: minute - 1 ) // 여기는 전체 시간 가까워질 때
)
//새 이벤트 생성
let event = DeviceActivityEvent(
applications: selectedApp.applicationTokens,
categories: selectedApp.categoryTokens,
webDomains: selectedApp.webDomainTokens,
//threshold - 이 시간이 되면 특정한 event가 발생 deviceactivitymonitor에 eventdidreachthreshold
threshold: DateComponents(minute : interval)
threshold: DateComponents(minute : minute)
)

do {
Expand Down Expand Up @@ -142,6 +143,36 @@ final class ScreenTimeViewModel: ObservableObject {


extension FamilyActivitySelection: RawRepresentable {
func jsonString() -> String? {
let encoder = JSONEncoder()
do {
let data = try encoder.encode(self)
guard let jsonString = String(data: data, encoding: .utf8) else {
print("Error encoding FamilyActivitySelection")
return nil
}
return jsonString
} catch {
print("Error encoding FamilyActivitySelection: \(error)")
return nil
}
}

static func from(jsonString: String) -> FamilyActivitySelection? {
guard let data = jsonString.data(using: .utf8) else {
print("Error converting string to Data")
return nil
}

let decoder = JSONDecoder()
do {
let familyActivitySelection = try decoder.decode(FamilyActivitySelection.self, from: data)
return familyActivitySelection
} catch {
print("Error decoding FamilyActivitySelection: \(error)")
return nil
}
}
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let result = try? JSONDecoder().decode(FamilyActivitySelection.self, from: data)
Expand Down
15 changes: 1 addition & 14 deletions HMH_iOS/HMH_iOS/Presentation/Challenge/Views/ChallengeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ struct ChallengeView: View {
@StateObject var screenTimeViewModel = ScreenTimeViewModel()
@ObservedObject var viewModel: ChallengeViewModel
@State var list = [AppDeviceActivity]()
@State var isPresented = false
@State private var selection = FamilyActivitySelection()
@State private var isExpanded = false


Expand Down Expand Up @@ -126,22 +124,11 @@ extension ChallengeView {
.padding(.horizontal, 20)
DeviceActivityReport(context, filter: filter)
.frame(height: 72 * CGFloat(screenTimeViewModel.selectedApp.applicationTokens.count))
Button(action: {
isPresented = true
}, label: {
NavigationLink(destination: OnboardingContentView(isChallengeMode: true, onboardingState: 4)) {
Image(.addAppButton)
})
.familyActivityPicker(isPresented: $isPresented,
selection: $selection)
.onChange(of: selection) { newSelection in
screenTimeViewModel.updateSelectedApp(newSelection: newSelection)
screenTimeViewModel.saveHashValue()
// TODO: 챌린지 만드는 시점에 설정
// screenTimeViewModel.handleStartDeviceActivityMonitoring(interval: 1)
}
}
.onAppear() {
selection = screenTimeViewModel.selectedApp
filter = DeviceActivityFilter(
segment: .daily(
during: Calendar.current.dateInterval(
Expand Down
35 changes: 21 additions & 14 deletions HMH_iOS/HMH_iOS/Presentation/Home/Views/HomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,10 @@ struct HomeView: View {
showBackButton: false,
showPointButton: false, point: 0)
.background(.blackground)
.onAppear {
screenTimeViewModel.requestAuthorization()

appFilter = DeviceActivityFilter(
segment: .daily(
during: Calendar.current.dateInterval(
of: .day, for: .now
) ?? DateInterval()
),
users: .all,
devices: .init([.iPhone]),
applications: screenTimeViewModel.selectedApp.applicationTokens,
categories: screenTimeViewModel.selectedApp.categoryTokens
)
.task {
await loadData()
}

}
}

Expand All @@ -65,9 +54,27 @@ extension HomeView {
.padding(.bottom, 20)
}
}

@MainActor
func loadData() async {
screenTimeViewModel.requestAuthorization()

appFilter = DeviceActivityFilter(
segment: .daily(
during: Calendar.current.dateInterval(
of: .day, for: .now
) ?? DateInterval()
),
users: .all,
devices: .init([.iPhone]),
applications: screenTimeViewModel.selectedApp.applicationTokens,
categories: screenTimeViewModel.selectedApp.categoryTokens
)
}
}



//#Preview {
// HomeView()
//}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ class LoginViewModel: NSObject, ObservableObject {
@Published var isLoading: Bool = true

func handleSplashScreen() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.refreshToken()
self.isLoading = false
}
self.isLoading = false
}

private func refreshToken() {
Expand Down
Loading

0 comments on commit 46dd4e0

Please sign in to comment.