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

[MOB-2845] BezierColor, BezierTheme 추가 #90

Open
wants to merge 15 commits into
base: feature/color
Choose a base branch
from

Conversation

solchan87
Copy link
Contributor

@solchan87 solchan87 commented Jan 2, 2025

어떤 PR 인가요?

BezierColor 와 BezierTheme 을 추가하는 PR 입니다.

왜 필요한건가요? (Optional)

작업 내용

  • 최소 지원 버전을 15로 올립니다.
  • BezierColor 를 추가합니다.
    • V1 Color 호환을 위해 V2 컬러를 참조하는 V1 컬러를 추가합니다.
    • deprecated 를 추가해서 마이그레이션 가이드를 제공합니다.
  • BezierTheme을 추가합니다.
  • UIKitSample 을 제거합니다.

스크린샷 혹은 동영상

Reference

Figma
BezierColor(iOS)
Color 가이드 문서

Issue-number

Checklist

  • PR 제목을 라벨과 함께 명령형으로 작성했습니다.
  • 코딩 컨벤션 에 맞춰서 작성했습니다
  • 리뷰 리퀘스트 전에 더 이상 스스로 리뷰할게 없을 정도까지 셀프 리뷰를 진행했습니다
  • 변경사항에 대한 테스트코드를 추가했습니다. 또는, 테스트코드가 필요없는 이유가 있습니다(현재는 옵셔널입니다)

Copy link

channeltalk bot commented Jan 2, 2025

@solchan87 solchan87 changed the title [Feature]/color migration [MOB-2845] BezierColor 및 BezierTheme 추가 Jan 2, 2025
@solchan87 solchan87 changed the title [MOB-2845] BezierColor 및 BezierTheme 추가 [MOB-2845] BezierColor, BezierTheme 추가 Jan 2, 2025
case .light: return .light
case .dark: return .dark
case .system:
switch UITraitCollection.current.userInterfaceStyle {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앱의 기본 UIUserInterfaceStyleunspecified 입니다.

// unspecified 상태에서 userInterfaceStyle 호출 시
print(UITraitCollection.current.userInterfaceStyle)
// light (os 테마 반환)


let toastViewModel = BezierToastViewModel()
let dialogViewModel = BezierDialogViewModel()
var config = Config()
public private(set) var currentTheme: BezierTheme = .system
Copy link
Contributor Author

@solchan87 solchan87 Jan 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테마 분기 필요 시

switch BezierSwift.shared.currentTheme.appearance {
case .light: ...
case .dark: ...
}

으로 구분합니다.

@available(*, deprecated, renamed: "bgNavyLighter", message: "Use `bgNavyLighter` instead.")
public static var bgtxtNavyLighter: BezierColor { BezierColor(functionalColorToken: .bgNavyLighter) }

@available(*, deprecated, message: "Use `fgNavyLight` for icon and text colors, and `bgNavyLight` for background color instead.")
Copy link
Contributor Author

@solchan87 solchan87 Jan 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bgtxt Color 는 V2 에서 bg/fg 로 구분합니다. icon text를 제외하고 대부분 bg Color를 사용합니다. 때문에 이 컬러에 대해서는 작업자의 판단이 필요해서 renamed 가 붙지 않습니다.

@solchan87 solchan87 requested review from bonoogi and heoblitz January 2, 2025 06:58
@solchan87 solchan87 added the PR:Reviewable Improvements or additions to documentation label Jan 2, 2025
@solchan87 solchan87 requested a review from jam0128 January 2, 2025 07:03
Copy link
Member

@heoblitz heoblitz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

작업 감사합니다

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene else { return }

self.window = windowScene.windows.first { $0.isKeyWindow }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.window = windowScene.windows.first { $0.isKeyWindow }
self.window = UIWindow(windowScene: windowScene)

예제 코드이지만 windowScene 생성자를 사용하면 좋을 것 같아요

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
  weak var windowScene: UIWindowScene?
  // ...
}

extension SceneDelegate: BezierSwiftDelegate {
  func windowsForThemeUpdate() -> [UIWindow] {
    self.windowScene?.windows ?? [] // or key window
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다. 아래 코드로 변경하겠습니다!


// MARK: - ForegroundBlue
extension FunctionalColorToken {
static var fgBlueNormal = FunctionalColorToken(lightGlobalColorToken: .blue400, darkGlobalColorToken: .blue300, pressedColorToken: PressedColorToken.fgBlueNormal)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static var fgBlueNormal = FunctionalColorToken(lightGlobalColorToken: .blue400, darkGlobalColorToken: .blue300, pressedColorToken: PressedColorToken.fgBlueNormal)
static let fgBlueNormal = FunctionalColorToken(lightGlobalColorToken: .blue400, darkGlobalColorToken: .blue300, pressedColorToken: PressedColorToken.fgBlueNormal)

변경되지 않는 값이라면 전체적으로 let 으로 처리되면 좋을 것 같아요

static var blue300_15: GlobalColorToken { GlobalColorToken(hex: "#7D9EFA26") }
static var blue300_0: GlobalColorToken { GlobalColorToken(hex: "#7D9EFA00") }
static var blue200: GlobalColorToken { GlobalColorToken(hex: "#96B7FF") }
static var blue100: GlobalColorToken { GlobalColorToken(hex: "#A9C6FF") }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

전체적으로 고정 값이라면 다시 계산되지 않도록 static let 를 사용해도 좋을 것 같아요.

)
.padding(.horizontal, Metric.textLeadingTrailing)
}

if let rightImage {
rightImage
.applyBaseImageStyle()
.foregroundColor(self.palette(self.type.imageTintColor(self.size)))
.foregroundColor(self.type.imageTintColor(self.size).color)
Copy link
Member

@heoblitz heoblitz Jan 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.color 가 항상 붙어야할 것 같아서 사용 편의성을 위해 BezierColor 가 View 나 ShapeStyle 을 직접 채택하는 것이 좋을지 조금 고민되네요.

혹은 BezierColor 를 파라미터로 받는 view extension 메서드도 생각해보았습니다.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 맞아요. 옵션으로 callAsFunction 도 생각해봤는데,

Text().foregroundColor() + Text().foregroundColor()

같이 필요한 경우 foregroundColor를 필수로 사용해야될 때는 Color를 써야되는 경우가 있어서 조금 고민이 있습니다.

일관된 사용을 위해서 .color가 좋다 생각했어요.

}
}

Text(self.param.title)
.applyBezierFontStyle(.bold14, semanticColor: .bgtxtAbsoluteWhiteDark)
.applyBezierFontStyle(.bold14, bezierColor: .bgtxtAbsoluteWhiteDark)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 친구는 아마도 fgAbsoluteWhiteDark를 사용해야 하지 않을까 싶어요. 일단 클린빌드했을때 warning이 뜨는건 이 친구 정도네요

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 감사합니다!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BezierSwift 자체에 대한 xcscheme이 없어서 매번 작업할때마다 추가해야할 것 같습니다. 추가되면 좋을 것 같아요(아래 스크린샷의 빨간 동그라미)
스크린샷 2025-01-02 오후 4 34 30

Comment on lines 117 to 126
public static func applyTheme(_ theme: BezierTheme) {
guard BezierSwift.shared.currentTheme != theme else { return }

BezierSwift.shared.currentTheme = theme
BezierSwift.shared.bezierWindow?.overrideUserInterfaceStyle = theme.userInterfaceStyle

BezierSwift.shared.delegate?.windowsForThemeUpdate().forEach { window in
window.overrideUserInterfaceStyle = theme.userInterfaceStyle
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거는 BezierSwift를 사용하는 쪽에서 호출하는거라고 보면 되겠죠? 예를들면 데스크의 AppDelegate라던가...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 맞습니다!

Comment on lines +18 to +24
// - MARK: BezierAppearance
// Appearance(Light/Dark)를 정의합니다.
// NOTE: `BezierThemeCompatible` 프로토콜을 준수하여 `BezierTheme`와 호환됩니다.
public enum BezierAppearance: BezierThemeCompatible {
case light
case dark
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

실제로 어떻게 사용된지에 대해서 감이 안와서 그러는데, BezierAppearance는 internal이어도 괜찮지 않나요? 어차피 외부에서는 BezierTheme만 사용할 것 같아서요.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(구두로 얘기 나눔)
사용처에서 현재 테마에 따른 컬러 분기를 칠 때를 위해 필요한 상황

class FooView {
  var barColor: UIColor {
    switch BezierSwift.shared.currentTheme.appearance {
    case .light: return lightCustomColor
    case .dark: return darkCustomColor
    }
  }
}

@solchan87 solchan87 changed the base branch from develop to feature/color January 2, 2025 08:16
Copy link
Contributor Author

@solchan87 solchan87 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

빠른 리뷰 감사합니다!

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene else { return }

self.window = windowScene.windows.first { $0.isKeyWindow }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다. 아래 코드로 변경하겠습니다!

Comment on lines 117 to 126
public static func applyTheme(_ theme: BezierTheme) {
guard BezierSwift.shared.currentTheme != theme else { return }

BezierSwift.shared.currentTheme = theme
BezierSwift.shared.bezierWindow?.overrideUserInterfaceStyle = theme.userInterfaceStyle

BezierSwift.shared.delegate?.windowsForThemeUpdate().forEach { window in
window.overrideUserInterfaceStyle = theme.userInterfaceStyle
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 맞습니다!

}
}

Text(self.param.title)
.applyBezierFontStyle(.bold14, semanticColor: .bgtxtAbsoluteWhiteDark)
.applyBezierFontStyle(.bold14, bezierColor: .bgtxtAbsoluteWhiteDark)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 감사합니다!

)
.padding(.horizontal, Metric.textLeadingTrailing)
}

if let rightImage {
rightImage
.applyBaseImageStyle()
.foregroundColor(self.palette(self.type.imageTintColor(self.size)))
.foregroundColor(self.type.imageTintColor(self.size).color)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 맞아요. 옵션으로 callAsFunction 도 생각해봤는데,

Text().foregroundColor() + Text().foregroundColor()

같이 필요한 경우 foregroundColor를 필수로 사용해야될 때는 Color를 써야되는 경우가 있어서 조금 고민이 있습니다.

일관된 사용을 위해서 .color가 좋다 생각했어요.

Copy link
Member

@heoblitz heoblitz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

작업 감사합니다


import Foundation

struct GlobalColorToken: ColorTokenType {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GlobalColorToken 은 Color Value를 레퍼런스하는 이름이 부여된 Global Token 입니다. hex(String)을 rawValue로 하고 있으며, GlobalToken은 디자인에 바로 사용할 수 없습니다.

var pressedColorToken: ThemeableColorTokenType { get }
}

public struct BezierColor {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BezierColor 는 GrobalColorToken <- FunctionalColorToken <- SemanticColorToken 을 화살표 방향을 레퍼런싱하는 구조입니다.

  • GlobalColorToken은 디지인 컴포넌트에 직접 사용이 불가능합니다. FunctionalColorToken 이상 부터 직접 사용이 가능합니다.
    Color 문서

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PR:Reviewable Improvements or additions to documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants