Skip to content

Commit

Permalink
Merge pull request #389 from OMZigak/fix/#383-removeBack
Browse files Browse the repository at this point in the history
[Fix] 최종 qa 반영
  • Loading branch information
hooni0918 authored Sep 20, 2024
2 parents 913bfcb + d55e8dc commit 762cc7b
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 46 deletions.
35 changes: 34 additions & 1 deletion KkuMulKum/Application/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import KakaoSDKCommon
import KakaoSDKAuth
import Firebase
import FirebaseMessaging
import UserNotifications

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
Expand All @@ -30,10 +31,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

setupFirebase(application: application)

UNUserNotificationCenter.current().delegate = self

return true
}

// 카카오 로그인 URL 처리 (중복 제거)
func application(
_ app: UIApplication,
open url: URL,
Expand Down Expand Up @@ -62,6 +64,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
_ application: UIApplication,
didDiscardSceneSessions sceneSessions: Set<UISceneSession>
) {}

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
if let sceneDelegate = UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate {
sceneDelegate.handleNotification(userInfo: userInfo)
}
completionHandler(.newData)
}
}

// MARK: - Firebase Setup
Expand Down Expand Up @@ -125,4 +134,28 @@ extension AppDelegate: MessagingDelegate, UNUserNotificationCenterDelegate {
) -> UIInterfaceOrientationMask {
return .portrait
}

func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo

completionHandler([.banner, .sound])

if let sceneDelegate = UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate {
sceneDelegate.handleNotification(userInfo: userInfo)
}
}

func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo

if let sceneDelegate = UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate {
sceneDelegate.handleNotification(userInfo: userInfo)
}

completionHandler()
}
}
73 changes: 58 additions & 15 deletions KkuMulKum/Application/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@
//

import UIKit

import KakaoSDKAuth
import UserNotifications

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
let loginViewModel = LoginViewModel()
var pendingNotificationData: [String: Any]?

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
Expand All @@ -22,9 +25,14 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
self.window?.rootViewController = launchScreenViewController
self.window?.makeKeyAndVisible()

if let notificationResponse = connectionOptions.notificationResponse {
let userInfo = notificationResponse.notification.request.content.userInfo
handleNotification(userInfo: userInfo)
}

performAutoLogin()
}

private func performAutoLogin() {
print("Performing auto login")
loginViewModel.autoLogin { [weak self] success in
Expand All @@ -39,18 +47,14 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
if let url = URLContexts.first?.url {
if (AuthApi.isKakaoTalkLoginUrl(url)) {
_ = AuthController.handleOpenUrl(url: url)
}
if let url = URLContexts.first?.url {
if (AuthApi.isKakaoTalkLoginUrl(url)) {
_ = AuthController.handleOpenUrl(url: url)
}
}
}

func application(
_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey : Any] = [:]
) -> Bool {
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
if (AuthApi.isKakaoTalkLoginUrl(url)) {
return AuthController.handleOpenUrl(url: url)
}
Expand All @@ -66,6 +70,11 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
navigationController.isNavigationBarHidden = true

animateRootViewControllerChange(to: navigationController)

if let notificationData = pendingNotificationData {
handleNotificationNavigation(data: notificationData)
pendingNotificationData = nil
}
}

private func showLoginScreen() {
Expand All @@ -80,16 +89,50 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
duration: 0.3,
options: .transitionCrossDissolve,
animations: {
let oldState = UIView.areAnimationsEnabled
UIView.setAnimationsEnabled(false)
window.rootViewController = newRootViewController
UIView.setAnimationsEnabled(oldState)
let oldState = UIView.areAnimationsEnabled
UIView.setAnimationsEnabled(false)
window.rootViewController = newRootViewController
UIView.setAnimationsEnabled(oldState)
})
}

func sceneDidDisconnect(_ scene: UIScene) {}
func sceneDidBecomeActive(_ scene: UIScene) {}

func sceneDidBecomeActive(_ scene: UIScene) {
if let notificationData = pendingNotificationData {
handleNotificationNavigation(data: notificationData)
pendingNotificationData = nil
}
}

func sceneWillResignActive(_ scene: UIScene) {}
func sceneWillEnterForeground(_ scene: UIScene) {}
func sceneDidEnterBackground(_ scene: UIScene) {}

func handleNotification(userInfo: [AnyHashable: Any]) {
if let data = userInfo["data"] as? [String: Any] {
handleNotificationNavigation(data: data)
}
}

private func handleNotificationNavigation(data: [String: Any]) {
guard let screen = data["screen"] as? String,
let promiseId = data["promiseId"] as? Int else {
return
}

guard let navigationController = window?.rootViewController as? UINavigationController else {
pendingNotificationData = data
return
}

switch screen {
case "readyStatus":
let promiseViewModel = PromiseViewModel(promiseID: promiseId, service: PromiseService())
let readyStatusVC = ReadyStatusViewController(viewModel: promiseViewModel)
navigationController.pushViewController(readyStatusVC, animated: true)
default:
break
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ class MyPageViewController: BaseViewController, CustomActionSheetDelegate {
let levelText = viewModel.getLevelText(for: userInfo.level)

rootView.contentView.nameLabel.text = (userInfo.name.map { $0 + "" }) ?? "꾸물리안 님"
rootView.contentView.levelLabel.setText("Lv. \(userInfo.level) \(levelText)", style: .body05, color: .white)

let fullLevelText = "Lv. \(userInfo.level) \(levelText)"
rootView.contentView.levelLabel.setText(fullLevelText, style: .body05, color: .white)
rootView.contentView.levelLabel.setHighlightText("Lv. \(userInfo.level)", style: .body05, color: .lightGreen)

updateProfileImage(with: userInfo.profileImageURL)
Expand Down Expand Up @@ -240,10 +242,8 @@ class MyPageViewController: BaseViewController, CustomActionSheetDelegate {
private func navigateToLoginScreen() {
let loginViewModel = LoginViewModel()
let loginViewController = LoginViewController(viewModel: loginViewModel)
let navigationController = UINavigationController(rootViewController: loginViewController)
navigationController.modalPresentationStyle = .fullScreen
self.view.window?.rootViewController = navigationController
self.view.window?.makeKeyAndVisible()
loginViewController.modalPresentationStyle = .fullScreen
self.present(loginViewController, animated: true, completion: nil)
}

func actionButtonDidTap(for kind: ActionSheetKind) {
Expand All @@ -253,6 +253,9 @@ class MyPageViewController: BaseViewController, CustomActionSheetDelegate {
private func showActionSheet(for kind: ActionSheetKind) {
let actionSheet = CustomActionSheetController(kind: kind)
actionSheet.delegate = self
present(actionSheet, animated: true, completion: nil)

if let tabBarController = self.tabBarController {
tabBarController.present(actionSheet, animated: true, completion: nil)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
//

import UIKit
import PhotosUI

class ProfileSetupViewController: BaseViewController {
private let rootView = ProfileSetupView()
private let viewModel: ProfileSetupViewModel
private let imagePicker = UIImagePickerController()

init(viewModel: ProfileSetupViewModel) {
self.viewModel = viewModel
Expand All @@ -30,6 +32,13 @@ class ProfileSetupViewController: BaseViewController {
setupNavigationBarTitle(with: "프로필 설정")
setupNavigationBarBackButton()
setupBindings()
setupImagePicker()
}

private func setupImagePicker() {
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = true
}

override func setupAction() {
Expand Down Expand Up @@ -69,36 +78,69 @@ class ProfileSetupViewController: BaseViewController {
}

@objc private func cameraButtonTapped() {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = true
checkPhotoLibraryPermission()
}

private func checkPhotoLibraryPermission() {
PHPhotoLibrary.requestAuthorization { [weak self] status in
DispatchQueue.main.async {
switch status {
case .authorized, .limited:
self?.presentImagePicker()
case .denied, .restricted:
self?.showPermissionDeniedAlert()
case .notDetermined:
break
@unknown default:
break
}
}
}
}

private func presentImagePicker() {
present(imagePicker, animated: true)
}

private func showPermissionDeniedAlert() {
let alert = UIAlertController(
title: "권한 거부됨",
message: "사진 라이브러리 접근 권한이 거부되었습니다. 설정에서 권한을 변경해주세요.",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "설정", style: .default) { _ in
if let settingsURL = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(settingsURL)
}
})
alert.addAction(UIAlertAction(title: "취소", style: .cancel))
present(alert, animated: true)
}

private func cropToCircle(image: UIImage) -> UIImage {
let shorterSide = min(image.size.width, image.size.height)
let imageBounds = CGRect(x: 0, y: 0, width: shorterSide, height: shorterSide)
UIGraphicsBeginImageContextWithOptions(imageBounds.size, false, UIScreen.main.scale)
let context = UIGraphicsGetCurrentContext()!
context.addEllipse(in: imageBounds)
context.clip()
image.draw(in: imageBounds)
let circleImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return circleImage
}
let shorterSide = min(image.size.width, image.size.height)
let imageBounds = CGRect(x: 0, y: 0, width: shorterSide, height: shorterSide)
UIGraphicsBeginImageContextWithOptions(imageBounds.size, false, UIScreen.main.scale)
let context = UIGraphicsGetCurrentContext()!
context.addEllipse(in: imageBounds)
context.clip()
image.draw(in: imageBounds)
let circleImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return circleImage
}
}

extension ProfileSetupViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(
_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]
) {
if let editedImage = info[.editedImage] as? UIImage ?? info[.originalImage] as? UIImage {
let croppedImage = cropToCircle(image: editedImage)
viewModel.updateProfileImage(croppedImage)
}
dismiss(animated: true)
}
_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]
) {
if let editedImage = info[.editedImage] as? UIImage ?? info[.originalImage] as? UIImage {
let croppedImage = cropToCircle(image: editedImage)
viewModel.updateProfileImage(croppedImage)
}
dismiss(animated: true)
}
}

0 comments on commit 762cc7b

Please sign in to comment.