Skip to content

Commit

Permalink
Merge pull request #46 from Student-Center/feature/WEAV-137
Browse files Browse the repository at this point in the history
[WEAV-137] 토스트 전역으로 구현되도록 수정, 프로필 위젯 토스트 구현
  • Loading branch information
jisu15-kim authored Nov 21, 2024
2 parents b289ae2 + 627dcd7 commit 29cae89
Show file tree
Hide file tree
Showing 18 changed files with 266 additions and 70 deletions.
19 changes: 5 additions & 14 deletions Projects/Core/CommonKit/Sources/AppCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public final class AppCoordinator: ObservableObject {

//MARK: - Properties
public var authState: AuthState = .none
public var userInfo: UserInfo?
@Published public var userInfo: UserInfo?
public var needFadeTransition: Bool = false
@Published public var navigationStack: [PathType] = [.intro]
let authService = AuthService.shared
Expand All @@ -43,7 +43,6 @@ public final class AppCoordinator: ObservableObject {
}
}
}
startRefreshMyUserInfo()
}

@MainActor
Expand Down Expand Up @@ -102,25 +101,17 @@ public final class AppCoordinator: ObservableObject {
}
}

public func refreshMyUserInfo() async throws {
public func refreshMyUserInfo() async throws -> UserInfo? {
if TokenManager.accessToken == nil || TokenManager.accessToken == "" {
return
AuthState.change(.loggedOut)
return nil
}
let userInfo = try await authService.requestMyUserInfo()
await MainActor.run {
self.userInfo = userInfo
AuthState.change(.login)
}
}

// 20초마다 한번씩 refreshMyUserInfo() 를 호출
private func startRefreshMyUserInfo() {
Task {
while true {
try? await Task.sleep(for: .seconds(20))
try? await refreshMyUserInfo()
}
}
return userInfo
}

public func logout() {
Expand Down
151 changes: 151 additions & 0 deletions Projects/DesignSystem/DesignCore/Sources/Toast/Toast.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
//
// Toast.swift
// DesignCore
//
// Created by 김지수 on 11/17/24.
// Copyright © 2024 com.weave. All rights reserved.
//

import UIKit
import Toast

public class ToastHelper {
public enum ToastStyle {
case normal
case error

var icon: UIImage? {
switch self {
case .normal: return nil
case .error: return DesignCore.Images.alert.uiImage
}
}

var backgroundColor: UIColor {
switch self {
case .normal: .white
case .error: .init(hex: 0xFFF5F8)
}
}
}

private static let manager = ToastManager.shared
public static func show(
message: String,
style: ToastStyle = .normal
) {
manager.showToast(message: message, style: style)
}

public static func show(_ message: String) {
manager.showToast(message: message, style: .normal)
}

public static func showErrorMessage(
_ message: String = "에러가 발생했어요 다시 시도해주세요"
) {
manager.showToast(message: message, style: .error)
}
}

final class ToastManager {
static let shared = ToastManager()
private var toastWindow: UIWindow?

private init() {}

func showToast(
message: String,
style: ToastHelper.ToastStyle = .normal,
duration: TimeInterval = 3.0
) {
DispatchQueue.main.async {
self.createToastWindow(
with: message,
style: style
)

DispatchQueue.main.asyncAfter(deadline: .now() + duration + 0.5) {
self.clearToast()
}
}
}

private func createToastWindow(
with message: String,
style: ToastHelper.ToastStyle
) {
guard toastWindow == nil else { return }

let toastWindow = UIWindow(frame: UIScreen.main.bounds)
toastWindow.windowLevel = .statusBar + 1
toastWindow.backgroundColor = .clear

let containerVC = UIViewController()
containerVC.view.backgroundColor = .clear

let viewConfig: ToastViewConfiguration = .init(
minHeight: 52,
minWidth: Device.width - 56,
darkBackgroundColor: style.backgroundColor,
lightBackgroundColor: style.backgroundColor,
titleNumberOfLines: 0,
subtitleNumberOfLines: 0,
cornerRadius: 14
)
let toastConfig: ToastConfiguration = .init(
direction: .bottom,
dismissBy: [
.tap,
.swipe(direction: .natural),
.time(time: 3)
],
enteringAnimation: .default,
exitingAnimation: .default,
allowToastOverlap: false
)

let toast: Toast
if let icon = style.icon {
toast = Toast.default(
image: icon,
title: createAttributedTitle(with: message),
viewConfig: viewConfig,
config: toastConfig
)
} else {
toast = Toast.text(
createAttributedTitle(with: message),
subtitle: nil,
viewConfig: viewConfig,
config: toastConfig
)
}

if style == .error {
toast.view.layer.borderWidth = 1
toast.view.layer.borderColor = UIColor(hex: 0xF2597F)
.withAlphaComponent(0.5)
.cgColor
}
toast.show(haptic: .success)
}

private func createAttributedTitle(with message: String) -> NSAttributedString {
let attributes: [NSAttributedString.Key: Any] = [
.font: UIFont.pretendard(._500, size: 16),
.foregroundColor: UIColor(DesignCore.Colors.grey400),
.paragraphStyle: {
let style = NSMutableParagraphStyle()
style.alignment = .center
return style
}()
]

return NSAttributedString(string: message, attributes: attributes)
}

private func clearToast() {
self.toastWindow = nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct ToastViewModifier: ViewModifier {
ZStack {
VStack {
Spacer()
Toast(
ToastView(
message: message,
isPresent: $isPresented
)
Expand All @@ -46,7 +46,7 @@ extension View {
}
}

struct Toast: View {
struct ToastView: View {
let message: String
@Binding var isPresent: Bool

Expand Down
3 changes: 2 additions & 1 deletion Projects/DesignSystem/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ let project: Project = .make(
product: .framework,
useResource: true,
dependencies: [
.external(.nuke)
.external(.nuke),
.external(.toast)
]
),
.makeUnitTest(
Expand Down
5 changes: 4 additions & 1 deletion Projects/Features/Home/Sources/HomeMain/HomeMainIntent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import CommonKit
import CoreKit
import Model
import NetworkKit
import DesignCore

//MARK: - Intent
class HomeMainIntent {
Expand Down Expand Up @@ -68,5 +69,7 @@ extension HomeMainIntent: HomeMainIntent.Intentable {
func task() async {}

// content
func onTapNextButton() {}
func onTapNextButton() {
ToastHelper.show(message: "토스트얍")
}
}
6 changes: 6 additions & 0 deletions Projects/Features/Home/Sources/HomeMain/HomeMainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ public struct HomeMainView: View {
// 첫 번째 탭 내용
VStack {
Text("첫 번째 탭")
Button {
intent.onTapNextButton()
} label: {
Text("토스트!")
}

}
.tag(HomeMainTab.home)

Expand Down
16 changes: 15 additions & 1 deletion Projects/Features/Home/Sources/Profile/ProfileIntent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import CommonKit
import CoreKit
import Model
import NetworkKit
import DesignCore

//MARK: - Intent
class ProfileIntent {
Expand Down Expand Up @@ -40,6 +41,7 @@ extension ProfileIntent {
func deleteWidget(_ widget: ProfileWidget) async

func onTapNextButton()
func refreshUserInfo() async
func fetchUserInfo(_ userInfo: UserInfo)

// default
Expand Down Expand Up @@ -73,18 +75,29 @@ extension ProfileIntent: ProfileIntent.Intentable {
do {
model?.setLoading(status: true)
try await requestDeleteWidget(widget)
try await AppCoordinator.shared.refreshMyUserInfo()
await refreshUserInfo()
model?.setLoading(status: false)
try await Task.sleep(for: .milliseconds(500))
ToastHelper.show("위젯이 삭제되었어요")
} catch {
print(error)
model?.setLoading(status: false)
DispatchQueue.main.asyncAfter(wallDeadline: .now() + 1.0) {
ToastHelper.showErrorMessage()
}
}
}

func onAppear() {
fetchUserInfo(input.userInfo)
}

func refreshUserInfo() async {
if let userInfo = try? await AppCoordinator.shared.refreshMyUserInfo() {
fetchUserInfo(userInfo)
}
}

func fetchUserInfo(_ userInfo: UserInfo) {
model?.setUserInfo(userInfo)
}
Expand All @@ -95,6 +108,7 @@ extension ProfileIntent: ProfileIntent.Intentable {
func onTapNextButton() {}

func requestDeleteWidget(_ widget: ProfileWidget) async throws {
throw NSError(domain: "33", code: 33)
try await profileService.requestDeleteProfileWidget(widgetType: widget.widgetType.toDto)
}
}
Loading

0 comments on commit 29cae89

Please sign in to comment.