Skip to content

Commit

Permalink
Merge pull request #87 from Team-HMH/feat/#80/ShieldView
Browse files Browse the repository at this point in the history
Feat [#80] 잠금 화면 뷰 구현 완료
  • Loading branch information
Zoe0929 authored Jan 15, 2024
2 parents c21fa76 + dace317 commit 5ad3a7a
Show file tree
Hide file tree
Showing 20 changed files with 503 additions and 59 deletions.
26 changes: 26 additions & 0 deletions HMH_iOS/DeviceMonitor/HMHMonitorExtension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// HMHMonitorExtension.swift
// DeviceMonitor
//
// Created by 지희의 MAC on 1/15/24.
//

import Foundation
import DeviceActivity
import ManagedSettings

class MyMonitorExtension: DeviceActivityMonitor {
let store = ManagedSettingsStore()


// You can use the `store` property to shield apps when an interval starts, ends, or meets a threshold.
override func intervalDidStart(for activity: DeviceActivityName) {
super.intervalDidStart(for: activity)


// Shield selected applications.
// let model = MyModel()
// let applications = model.selectionToShield.applications
// store.shield.applications = applications.isEmpty ? nil : applications
}
}
33 changes: 33 additions & 0 deletions HMH_iOS/DeviceReport/ActivityReport.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// ActivityReport.swift
// DeviceReport
//
// Created by 지희의 MAC on 1/15/24.
//

// MARK: - Device Activity Report 관련 데이터 모델이 정의되어 있는 파일입니다.
import Foundation
import ManagedSettings

struct ActivityReport {
let totalDuration: TimeInterval
let apps: [AppDeviceActivity]
}

struct AppDeviceActivity: Identifiable {
var id: String
var displayName: String
var duration: TimeInterval
var numberOfPickups: Int
var token: ApplicationToken?
}

extension TimeInterval {
/// TimeInterval 타입 값을 00:00 형식의 String으로 변환해주는 메서드
func toString() -> String {
let time = NSInteger(self)
let minutes = (time / 60) % 60
let hours = (time / 3600)
return String(format: "%0.2d:%0.2d", hours,minutes)
}
}
2 changes: 1 addition & 1 deletion HMH_iOS/DeviceReport/DeviceReport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ struct DeviceReport: DeviceActivityReportExtension {
var body: some DeviceActivityReportScene {
// Create a report for each DeviceActivityReport.Context that your app supports.
TotalActivityReport { totalActivity in
TotalActivityView(totalActivity: totalActivity)
TotalActivityView(totalActivity: totalActivity.totalDuration.toString())
}
// Add more reports here...
}
Expand Down
51 changes: 41 additions & 10 deletions HMH_iOS/DeviceReport/TotalActivityReport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,62 @@
import DeviceActivity
import SwiftUI

// MARK: - 각각의 Device Activity Report들에 대응하는 컨텍스트 정의
extension DeviceActivityReport.Context {
// If your app initializes a DeviceActivityReport with this context, then the system will use
// your extension's corresponding DeviceActivityReportScene to render the contents of the
// report.
/// 해당 리포트의 내용 렌더링에 사용할 DeviceActivityReportScene에 대응하는 익스텐션이 필요합니다. ex) TotalActivityReport
static let totalActivity = Self("Total Activity")
}

// MARK: - Device Activity Report의 내용을 어떻게 구성할 지 설정
struct TotalActivityReport: DeviceActivityReportScene {
// Define which context your scene will represent.
/// 보여줄 리포트에 대한 컨텍스트를 정의해줍니다.
let context: DeviceActivityReport.Context = .totalActivity

// Define the custom configuration and the resulting view for this report.
let content: (String) -> TotalActivityView
/// 어떤 데이터를 사용해서 어떤 뷰를 보여줄 지 정의해줍니다. (SwiftUI View)
let content: (ActivityReport) -> TotalActivityView

func makeConfiguration(representing data: DeviceActivityResults<DeviceActivityData>) async -> String {
/// DeviceActivityResults 데이터를 받아서 필터링
func makeConfiguration(
representing data: DeviceActivityResults<DeviceActivityData>) async -> ActivityReport {
// Reformat the data into a configuration that can be used to create
// the report's view.
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.day, .hour, .minute, .second]
formatter.unitsStyle = .abbreviated
formatter.zeroFormattingBehavior = .dropAll
var totalActivityDuration: Double = 0 /// 총 스크린 타임 시간
var list: [AppDeviceActivity] = [] /// 사용 앱 리스트

let totalActivityDuration = await data.flatMap { $0.activitySegments }.reduce(0, {
$0 + $1.totalActivityDuration
})
return formatter.string(from: totalActivityDuration) ?? "No activity data"
/// DeviceActivityResults 데이터에서 화면에 보여주기 위해 필요한 내용을 추출해줍니다.
for await eachData in data {
/// 특정 시간 간격 동안 사용자의 활동
for await activitySegment in eachData.activitySegments {
/// 활동 세그먼트 동안 사용자의 카테고리 별 Device Activity
for await categoryActivity in activitySegment.categories {
/// 이 카테고리의 totalActivityDuration에 기여한 사용자의 application Activity
for await applicationActivity in categoryActivity.applications {
let appName = (applicationActivity.application.localizedDisplayName ?? "nil") /// 앱 이름
let bundle = (applicationActivity.application.bundleIdentifier ?? "nil") /// 앱 번들id
let duration = applicationActivity.totalActivityDuration /// 앱의 total activity 기간
totalActivityDuration += duration
let numberOfPickups = applicationActivity.numberOfPickups /// 앱에 대해 직접적인 pickup 횟수
let token = applicationActivity.application.token /// 앱의 토큰
let appActivity = AppDeviceActivity(
id: bundle,
displayName: appName,
duration: duration,
numberOfPickups: numberOfPickups,
token: token
)
list.append(appActivity)
}
}

}
}

/// 필터링된 ActivityReport 데이터들을 반환
return ActivityReport(totalDuration: totalActivityDuration, apps: list)
}
}
20 changes: 20 additions & 0 deletions HMH_iOS/HMH_iOS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@
17CF9FC92B4EE964000DD09C /* AppUsingProgressViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17CF9FC82B4EE964000DD09C /* AppUsingProgressViewCell.swift */; };
17CF9FCF2B4F1A91000DD09C /* MyGoalTimeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17CF9FCE2B4F1A91000DD09C /* MyGoalTimeCell.swift */; };
17CF9FD12B4F31C0000DD09C /* BlackHoleImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17CF9FD02B4F31C0000DD09C /* BlackHoleImageCell.swift */; };
360D11082B536746008BE85A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 360D11072B536746008BE85A /* Assets.xcassets */; };
360D110E2B541DB4008BE85A /* UserDefault+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 360D110D2B541DB4008BE85A /* UserDefault+.swift */; };
360D11102B5443FD008BE85A /* ActivityReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 360D110F2B5443FD008BE85A /* ActivityReport.swift */; };
17CF9FDE2B52F86A000DD09C /* GetUserDataResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17CF9FDD2B52F86A000DD09C /* GetUserDataResponseDTO.swift */; };
17CF9FE02B52FA26000DD09C /* MyPageRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17CF9FDF2B52FA26000DD09C /* MyPageRouter.swift */; };
360D11022B5343C6008BE85A /* requestPermision.swift in Sources */ = {isa = PBXBuildFile; fileRef = 360D11012B5343C6008BE85A /* requestPermision.swift */; };
Expand All @@ -95,6 +98,8 @@
364923A02B505F2000BF7ACA /* CreateChallengeRequestDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3649239F2B505F2000BF7ACA /* CreateChallengeRequestDTO.swift */; };
364C4E712B4BC9780015729C /* AppAddButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 364C4E702B4BC9780015729C /* AppAddButtonView.swift */; };
364C4E732B4BF27C0015729C /* AppAddCollectionReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 364C4E722B4BF27C0015729C /* AppAddCollectionReusableView.swift */; };
365AF6672B54547800BAC51F /* HMHMonitorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 365AF6662B54547800BAC51F /* HMHMonitorExtension.swift */; };
36610E3C2B5463280044F1CA /* HMHPushAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36610E3B2B5463280044F1CA /* HMHPushAlert.swift */; };
3666C84D2B45F41300564874 /* HMHAppSelectButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3666C84C2B45F41300564874 /* HMHAppSelectButtonView.swift */; };
3666C8552B45F47600564874 /* DeviceActivity.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3666C8542B45F47600564874 /* DeviceActivity.framework */; };
3666C8582B45F47600564874 /* DeviceActivityMonitorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3666C8572B45F47600564874 /* DeviceActivityMonitorExtension.swift */; };
Expand Down Expand Up @@ -287,6 +292,9 @@
17CF9FC82B4EE964000DD09C /* AppUsingProgressViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUsingProgressViewCell.swift; sourceTree = "<group>"; };
17CF9FCE2B4F1A91000DD09C /* MyGoalTimeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyGoalTimeCell.swift; sourceTree = "<group>"; };
17CF9FD02B4F31C0000DD09C /* BlackHoleImageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlackHoleImageCell.swift; sourceTree = "<group>"; };
360D11072B536746008BE85A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
360D110D2B541DB4008BE85A /* UserDefault+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefault+.swift"; sourceTree = "<group>"; };
360D110F2B5443FD008BE85A /* ActivityReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityReport.swift; sourceTree = "<group>"; };
17CF9FDD2B52F86A000DD09C /* GetUserDataResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetUserDataResponseDTO.swift; sourceTree = "<group>"; };
17CF9FDF2B52FA26000DD09C /* MyPageRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageRouter.swift; sourceTree = "<group>"; };
360D11012B5343C6008BE85A /* requestPermision.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = requestPermision.swift; sourceTree = "<group>"; };
Expand All @@ -309,6 +317,8 @@
3649239F2B505F2000BF7ACA /* CreateChallengeRequestDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateChallengeRequestDTO.swift; sourceTree = "<group>"; };
364C4E702B4BC9780015729C /* AppAddButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppAddButtonView.swift; sourceTree = "<group>"; };
364C4E722B4BF27C0015729C /* AppAddCollectionReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppAddCollectionReusableView.swift; sourceTree = "<group>"; };
365AF6662B54547800BAC51F /* HMHMonitorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMHMonitorExtension.swift; sourceTree = "<group>"; };
36610E3B2B5463280044F1CA /* HMHPushAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMHPushAlert.swift; sourceTree = "<group>"; };
3666C84C2B45F41300564874 /* HMHAppSelectButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMHAppSelectButtonView.swift; sourceTree = "<group>"; };
3666C8522B45F47600564874 /* DeviceMonitor.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = DeviceMonitor.appex; sourceTree = BUILT_PRODUCTS_DIR; };
3666C8542B45F47600564874 /* DeviceActivity.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DeviceActivity.framework; path = System/Library/Frameworks/DeviceActivity.framework; sourceTree = SDKROOT; };
Expand Down Expand Up @@ -594,6 +604,7 @@
36A3D9BB2B3EBD2D007EA272 /* UIScreen+.swift */,
3666C88C2B471B1D00564874 /* UIImage+.swift */,
0B17D3F02B51AD4B00CFA3B7 /* UIViewController+.swift */,
360D110D2B541DB4008BE85A /* UserDefault+.swift */,
360D11032B53465B008BE85A /* UIApplication+.swift */,
);
path = Extension;
Expand Down Expand Up @@ -822,6 +833,7 @@
17314F822B486BEC0089A551 /* AlertViewController.swift */,
17314F842B497FDE0089A551 /* HMHLogoutAlert.swift */,
17314F862B49853C0089A551 /* HMHQuitAlert.swift */,
36610E3B2B5463280044F1CA /* HMHPushAlert.swift */,
);
path = CustomAlert;
sourceTree = "<group>";
Expand Down Expand Up @@ -1010,6 +1022,7 @@
3666C8572B45F47600564874 /* DeviceActivityMonitorExtension.swift */,
3666C8592B45F47600564874 /* Info.plist */,
3666C85A2B45F47600564874 /* DeviceMonitor.entitlements */,
365AF6662B54547800BAC51F /* HMHMonitorExtension.swift */,
);
path = DeviceMonitor;
sourceTree = "<group>";
Expand All @@ -1022,6 +1035,7 @@
3666C86C2B45F4B200564874 /* TotalActivityView.swift */,
3666C86E2B45F4B200564874 /* Info.plist */,
3666C86F2B45F4B200564874 /* DeviceReport.entitlements */,
360D110F2B5443FD008BE85A /* ActivityReport.swift */,
);
path = DeviceReport;
sourceTree = "<group>";
Expand Down Expand Up @@ -1081,6 +1095,7 @@
36E531BD2B4C78A900B4BBE3 /* ShieldConfigurationExtension.swift */,
36E531BF2B4C78A900B4BBE3 /* Info.plist */,
36E531C02B4C78A900B4BBE3 /* ShiledConfig.entitlements */,
360D11072B536746008BE85A /* Assets.xcassets */,
);
path = ShiledConfig;
sourceTree = "<group>";
Expand Down Expand Up @@ -1305,6 +1320,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
360D11082B536746008BE85A /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -1323,6 +1339,7 @@
0B8A89BC2B369F2D00688BA6 /* UIView+.swift in Sources */,
0B8A89AF2B369E4300688BA6 /* HomeModel.swift in Sources */,
3666C89F2B485C8F00564874 /* DateCollectionViewCell.swift in Sources */,
36610E3C2B5463280044F1CA /* HMHPushAlert.swift in Sources */,
3666C87A2B45F4F900564874 /* SelectedBlocker.swift in Sources */,
0B17D3ED2B5108D200CFA3B7 /* UserDefaultWrapper.swift in Sources */,
0BC0EBD42B494459003EF5D4 /* OnboardingSwipeView.swift in Sources */,
Expand Down Expand Up @@ -1352,6 +1369,7 @@
174AF49A2B447CFB00450D07 /* ChanllengeViews.swift in Sources */,
17CF9FC92B4EE964000DD09C /* AppUsingProgressViewCell.swift in Sources */,
0B000CEB2B4D9D9100AEC582 /* SelectTotalTimeController.swift in Sources */,
360D110E2B541DB4008BE85A /* UserDefault+.swift in Sources */,
0B1AE8212B53ABC400CF5154 /* SignUpResponseDTO.swift in Sources */,
17314F872B49853C0089A551 /* HMHQuitAlert.swift in Sources */,
364923A02B505F2000BF7ACA /* CreateChallengeRequestDTO.swift in Sources */,
Expand Down Expand Up @@ -1434,6 +1452,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
365AF6672B54547800BAC51F /* HMHMonitorExtension.swift in Sources */,
3666C8582B45F47600564874 /* DeviceActivityMonitorExtension.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -1442,6 +1461,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
360D11102B5443FD008BE85A /* ActivityReport.swift in Sources */,
3666C86D2B45F4B200564874 /* TotalActivityView.swift in Sources */,
3666C8692B45F4B200564874 /* DeviceReport.swift in Sources */,
3666C86B2B45F4B200564874 /* TotalActivityReport.swift in Sources */,
Expand Down
41 changes: 32 additions & 9 deletions HMH_iOS/HMH_iOS/Application/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,51 @@ import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {




func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let userNotiCenter = UNUserNotificationCenter.current()
userNotiCenter.delegate = self

return true
}

// MARK: UISceneSession Lifecycle

func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}

func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}


}

extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.list, .badge, .sound])
}

func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {

// deep link처리 시 아래 url값 가지고 처리
guard let appName = response.notification.request.content.userInfo.values.first as? String else { return }
showCustomAlert(appName: String(stringLiteral: appName))
completionHandler()
}

func showCustomAlert(appName: String) {
let pushAertViewController = AlertViewController()
pushAertViewController.appName = appName
pushAertViewController.alertType = .HMHPushALert
pushAertViewController.modalPresentationStyle = .overFullScreen
UIApplication.shared.windows.first?.rootViewController?.present(pushAertViewController, animated: false, completion: nil)
}
}
12 changes: 12 additions & 0 deletions HMH_iOS/HMH_iOS/Global/Extension/UserDefault+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// UserDefault+.swift
// HMH_iOS
//
// Created by 지희의 MAC on 1/14/24.
//

import Foundation

public extension UserDefaults {
static let shared = UserDefaults(suiteName: "group.HMH")!
}
2 changes: 2 additions & 0 deletions HMH_iOS/HMH_iOS/Global/Literals/String/String.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,12 @@ enum StringLiteral {
enum AlertTitle {
static let logout = "HMH을 로그아웃 하실 건가요?"
static let quit = "HMH을 탈퇴 하실 건가요?"
static let push = "을(를)\n계속 사용하시겠어요?"
}

enum AlertDescription {
static let quit = "회원탈퇴 후 유저의 정보는 30일 동안 임시보관 후 영구 삭제됩니다."
static let push = "사용 시간을 연장하면\n챌린지를 실패해요"
}

enum OnboardingButton {
Expand Down
2 changes: 2 additions & 0 deletions HMH_iOS/HMH_iOS/HMH_iOS.entitlements
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>aps-environment</key>
<string>development</string>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
Expand Down
Loading

0 comments on commit 5ad3a7a

Please sign in to comment.