Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] #206 - 알림 권한 요청 다이얼로그 구현 #209

Merged
merged 8 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions iOS-NOTTODO/iOS-NOTTODO.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@
3B027AA2299C355800BEB65C /* AchievementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B027AA1299C355800BEB65C /* AchievementViewController.swift */; };
3B027AA4299C357000BEB65C /* MyInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B027AA3299C357000BEB65C /* MyInfoViewController.swift */; };
3B027AAC299C35E500BEB65C /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3B027AAB299C35E500BEB65C /* Colors.xcassets */; };
3B03D0D62B0F15AA00302872 /* NotificationDialogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B03D0D52B0F15AA00302872 /* NotificationDialogViewController.swift */; };
3B03D0D82B0F5EF300302872 /* CGSize+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B03D0D72B0F5EF300302872 /* CGSize+.swift */; };
3B0CBA222A45FC170004F2DB /* UpdateMissionResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B0CBA212A45FC170004F2DB /* UpdateMissionResponseDTO.swift */; };
3B0CBA242A461B1C0004F2DB /* RecentMissionResponseDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B0CBA232A461B1C0004F2DB /* RecentMissionResponseDTO.swift */; };
3B11740D2A4B574B0033DDF3 /* CALayer+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B11740C2A4B574B0033DDF3 /* CALayer+.swift */; };
Expand Down Expand Up @@ -235,6 +237,8 @@
3B027AA1299C355800BEB65C /* AchievementViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AchievementViewController.swift; sourceTree = "<group>"; };
3B027AA3299C357000BEB65C /* MyInfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoViewController.swift; sourceTree = "<group>"; };
3B027AAB299C35E500BEB65C /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = "<group>"; };
3B03D0D52B0F15AA00302872 /* NotificationDialogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationDialogViewController.swift; sourceTree = "<group>"; };
3B03D0D72B0F5EF300302872 /* CGSize+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGSize+.swift"; sourceTree = "<group>"; };
3B0CBA212A45FC170004F2DB /* UpdateMissionResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateMissionResponseDTO.swift; sourceTree = "<group>"; };
3B0CBA232A461B1C0004F2DB /* RecentMissionResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentMissionResponseDTO.swift; sourceTree = "<group>"; };
3B11740C2A4B574B0033DDF3 /* CALayer+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CALayer+.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -657,6 +661,7 @@
097568352A2FEF3F0001EC46 /* String+.swift */,
3B11740C2A4B574B0033DDF3 /* CALayer+.swift */,
0943A9F82A53239200614761 /* Bundle+.swift */,
3B03D0D72B0F5EF300302872 /* CGSize+.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -685,6 +690,7 @@
3B027A97299C343D00BEB65C /* Presentation */ = {
isa = PBXGroup;
children = (
3B03D0D32B0F157700302872 /* NotificatoinDialog */,
09F6717E29CAD68100708725 /* Onboarding */,
3B027A9B299C348800BEB65C /* Achievement */,
3B027A9C299C349A00BEB65C /* AddMission */,
Expand Down Expand Up @@ -808,6 +814,22 @@
path = Assets;
sourceTree = "<group>";
};
3B03D0D32B0F157700302872 /* NotificatoinDialog */ = {
isa = PBXGroup;
children = (
3B03D0D42B0F159100302872 /* ViewControllers */,
);
path = NotificatoinDialog;
sourceTree = "<group>";
};
3B03D0D42B0F159100302872 /* ViewControllers */ = {
isa = PBXGroup;
children = (
3B03D0D52B0F15AA00302872 /* NotificationDialogViewController.swift */,
);
path = ViewControllers;
sourceTree = "<group>";
};
3B3C89DB29C0EF6A00B1D56D /* Models */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1244,6 +1266,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3B03D0D62B0F15AA00302872 /* NotificationDialogViewController.swift in Sources */,
09F6719729CC81B500708725 /* DetailAchievementCollectionViewCell.swift in Sources */,
0960C0D62A38BC8100A3D8DB /* DefaultKeys.swift in Sources */,
3B14A14129A6FDA900F92897 /* UILabel+.swift in Sources */,
Expand Down Expand Up @@ -1300,6 +1323,7 @@
098BFD5F29B7AECF008E80F9 /* MyInfoHeaderCollectionReusableView.swift in Sources */,
3B482FA7299EB8FD00BCF424 /* UIViewController+.swift in Sources */,
0960C0D42A38BC6500A3D8DB /* KeychainUtil.swift in Sources */,
3B03D0D82B0F5EF300302872 /* CGSize+.swift in Sources */,
6CA208302A1925EE001C4247 /* RecommendActionResponseDTO.swift in Sources */,
09F6718629CB26E400708725 /* OnboardingHeaderView.swift in Sources */,
3B11740D2A4B574B0033DDF3 /* CALayer+.swift in Sources */,
Expand Down
22 changes: 1 addition & 21 deletions iOS-NOTTODO/iOS-NOTTODO/Application/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,40 +31,20 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
if KeychainUtil.getAccessToken() != "" {
self.skipAuthView()
print("토큰 유효")
} else {
// self.showAuthView()
// 토큰이 유효하지 않을 경우 일단은 온보딩->로그인->홈 이렇게만 가도록
}

// 메시지 대리자 설정
Messaging.messaging().delegate = self

// FCM 다시 사용 설정
Messaging.messaging().isAutoInitEnabled = true

// 푸시 알림 권한 설정 및 푸시 알림에 앱 등록
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions, completionHandler: { _, _ in })


// device token 요청.
application.registerForRemoteNotifications()

return true
}

func showAuthView() {
DispatchQueue.main.async {
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let window = windowScene.windows.first {
let authViewController = AuthViewController()
let navigationController = UINavigationController(rootViewController: authViewController)
window.rootViewController = navigationController
window.makeKeyAndVisible()
}
}
}

func skipAuthView() {
// 홈 화면으로 바로 이동
DispatchQueue.main.async {
Expand Down
29 changes: 29 additions & 0 deletions iOS-NOTTODO/iOS-NOTTODO/Global/Extensions/CGSize+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// CGSize+.swift
// iOS-NOTTODO
//
// Created by 강윤서 on 11/23/23.
//

import UIKit

extension CGSize {

func getDeviceWidth() -> CGFloat {
return UIScreen.main.bounds.width
}

func getDeviceHeight() -> CGFloat {
return UIScreen.main.bounds.height
}

/// 아이폰 13 미니(width 375)를 기준으로 레이아웃을 잡고, 기기의 width 사이즈를 곱해 대응 값을 구할 때 사용
func convertByWidthRatio(_ convert: CGFloat) -> CGFloat {
return (convert / 375) * getDeviceWidth()
}

/// 아이폰 13 미니(height 812)를 기준으로 레이아웃을 잡고, 기기의 height 사이즈를 곱해 대응 값을 구할 때 사용
func convertByHeightRatio(_ convert: CGFloat) -> CGFloat {
return (convert / 812) * getDeviceHeight()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ extension UIColor {
static let green2 = UIColor(named: "green2")
static let systemBlack = UIColor(named: "systemBlack")
static let kakaoYellow = UIColor(named: "yellow")
static let notiBlack = UIColor(named: "notiBlack")
static let notiGreen = UIColor(named: "notiGreen")
static let notiBlue = UIColor(named: "notiBlue")
static let notiBg = UIColor(named: "notiBg")
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ extension UIImage {
static var icSNS: UIImage { UIImage(named: "ic_snsmessage")! }
static var icTrashbin: UIImage { UIImage(named: "ic_trashbin")! }
static var icToastError: UIImage { UIImage(named: "ic_toast_error")! }
static var icBell: UIImage { UIImage(named: "ic_bell")! }
static var icCircle: UIImage { UIImage(named: "acceptCircle")! }

// image

Expand Down Expand Up @@ -110,4 +112,5 @@ extension UIImage {

static var quit1: UIImage { UIImage(named: "img_quit1")! }
static var quit2: UIImage { UIImage(named: "img_quit2")! }
static var notificationDialog: UIImage { UIImage(named: "NotificationDialog")! }
}
17 changes: 16 additions & 1 deletion iOS-NOTTODO/iOS-NOTTODO/Global/Literals/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,22 @@ struct I18N {
static let delete = "삭제하기"
static let deleteModalTitle = "삭제하시겠습니까?"
static let deleteModalSubtitle = "한 번 삭제하면 되돌릴 수 없어요."

static let notiDialogTitle = """
알림을 허용하면
낫투두가 더 잘 도울 수 있어요!
"""
static let notiAllowTitle = """
'낫투두'에서 알림을
보내고자 합니다.
"""
static let notiAllowSubTitle = """
알림 기능이 꺼져있으면
알람이 울릴 때까지 확인하기 어려워요
"""
static let notAllow = "허용 안 함"
static let allow = "허용"
static let notiDialogButton = "네, 알겠어요 :)"

/// home
static let subText = "*달성 가능한 계획을 위해 다가올 일주일만 선택할 수 있어요"
}
40 changes: 32 additions & 8 deletions iOS-NOTTODO/iOS-NOTTODO/Presentation/Auth/AuthViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -241,21 +241,45 @@ extension AuthViewController {
guard let userId = result?.data?.userId else { return }
KeychainUtil.setAccessToken(accessToken)
Amplitude.instance().setUserId(userId)
self?.presentToHomeViewController()

self?.checkNotificationSettings()
}
}
}
}

func presentToHomeViewController() {
if let window = view.window?.windowScene?.keyWindow {
let tabBarController = TabBarController()
let navigationController = UINavigationController(rootViewController: tabBarController)
navigationController.isNavigationBarHidden = true
window.rootViewController = navigationController
DispatchQueue.main.async {
SceneDelegate.shared?.changeRootViewControllerTo(TabBarController())
}
}

func checkNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { settings in
switch settings.authorizationStatus {
case .notDetermined:
self.showNotiDialogView()
default:
break
}
}
}

func showNotiDialogView() {
DispatchQueue.main.async {
let notiDialogViewController = NotificationDialogViewController()
notiDialogViewController.buttonHandler = {
self.requestNotification()
}
SceneDelegate.shared?.changeRootViewControllerTo(notiDialogViewController)
}
}

func requestNotification() {
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions, completionHandler: { _, _ in
self.presentToHomeViewController()
})
}
}

// MARK: - AppleSignIn
Expand Down Expand Up @@ -298,7 +322,7 @@ extension AuthViewController: ASAuthorizationControllerDelegate, ASAuthorization
guard let userId = result?.data?.userId else { return }
KeychainUtil.setAccessToken(accessToken)
Amplitude.instance().setUserId(userId)
self?.presentToHomeViewController()
self?.checkNotificationSettings()
}
default:
break
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,16 +180,11 @@ extension MyInfoAccountViewController {
if !UserDefaults.standard.bool(forKey: DefaultKeys.isAppleLogin) {
kakaoLogout()
}
AuthAPI.shared.deleteAuth { [weak self] _ in
AuthAPI.shared.deleteAuth { _ in
UserDefaults.standard.removeObject(forKey: DefaultKeys.accessToken)
UserDefaults.standard.removeObject(forKey: DefaultKeys.socialToken)
AmplitudeAnalyticsService.shared.send(event: AnalyticsEvent.AccountInfo.completeLogout)
let authViewController = AuthViewController()
if let window = self?.view.window?.windowScene?.keyWindow {
let navigationController = UINavigationController(rootViewController: authViewController)
navigationController.isNavigationBarHidden = true
window.rootViewController = navigationController
}
SceneDelegate.shared?.changeRootViewControllerTo(AuthViewController())
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//
// NotificationDialogViewController.swift
// iOS-NOTTODO
//
// Created by 강윤서 on 11/23/23.
//

import UIKit

import SnapKit
import Then

final class NotificationDialogViewController: UIViewController {

// MARK: - Properties

var buttonHandler: (() -> Void)?

// MARK: - UI Components

private let bellImage = UIImageView()
private let titleLabel = UILabel()
private let bottomButton = UIButton()

// MARK: - Life Cycle

override func viewDidLoad() {
super.viewDidLoad()
setUI()
setLayout()
}

}

extension NotificationDialogViewController {
private func setUI() {
view.backgroundColor = .ntdBlack

bellImage.image = .icBell

titleLabel.do {
$0.text = I18N.notiDialogTitle
$0.textColor = .white
$0.font = .Pretendard(.semiBold, size: 22)
$0.numberOfLines = 0
$0.textAlignment = .center
}

bottomButton.do {
$0.backgroundColor = .white
$0.layer.cornerRadius = 25
$0.titleLabel?.font = .Pretendard(.semiBold, size: 16)
$0.setTitleColor(.black, for: .normal)
$0.setTitle(I18N.notiDialogButton, for: .normal)
$0.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
}

}

private func setLayout() {
view.addSubviews(bellImage, titleLabel, bottomButton)

bellImage.snp.makeConstraints {
$0.top.equalTo(view.safeAreaLayoutGuide).inset(convertByHeightRatio(63))
$0.centerX.equalToSuperview()
$0.height.equalTo(convertByHeightRatio(107))
}

titleLabel.snp.makeConstraints {
$0.top.equalTo(bellImage.snp.bottom).offset(convertByHeightRatio(2))
$0.directionalHorizontalEdges.equalToSuperview().inset(convertByHeightRatio(57))
$0.height.equalTo(convertByHeightRatio(60))
}

bottomButton.snp.makeConstraints {
$0.bottom.equalTo(view.safeAreaLayoutGuide).inset(convertByHeightRatio(44))
$0.directionalHorizontalEdges.equalToSuperview().inset(convertByHeightRatio(15))
$0.height.equalTo(convertByHeightRatio(50))
}
}

@objc
private func buttonTapped() {
buttonHandler?()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,7 @@ extension FifthOnboardingViewController {
if let window = view.window?.windowScene?.keyWindow {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
UIView.animate(withDuration: 0.01) {
let TabBarController = AuthViewController()
let navigationController = UINavigationController(rootViewController: TabBarController)
navigationController.isNavigationBarHidden = true
window.rootViewController = navigationController
SceneDelegate.shared?.changeRootViewControllerTo(AuthViewController())
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "acceptCircle.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "acceptCircle@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "acceptCircle@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading