Skip to content

Various fixes#398

Merged
shp7724 merged 13 commits intomasterfrom
shp7724/misc
Feb 6, 2026
Merged

Various fixes#398
shp7724 merged 13 commits intomasterfrom
shp7724/misc

Conversation

@shp7724
Copy link
Contributor

@shp7724 shp7724 commented Feb 6, 2026

그냥 써보면서 눈에 보이는 이슈들 수정

Move CircleBadge component from TimetableScene to SharedUIComponents module for reusability across features. Update TimetableMenuSection to import from the new shared location.
- Apply cyan tint to edit/save buttons in lecture detail toolbar
- Apply cyan tint to sheet top bar buttons
- Fix lecture color resolution to respect custom colors for unsaved lectures
시간표 그리드의 시간 행 렌더링을 위한 높이와 개수를 계산하는 로직을
getDisplayGridMetrics() 메서드로 추출하여 중복 제거 및 유지보수성 개선
시간표 그리드 메트릭스 계산 로직에 대한 단위 테스트 추가:
- Safe area insets가 있는 경우의 계산 검증
- 18시간 이상 범위에서의 헤더 잘림 방지 검증
- 최소 시간 높이(10pt) 제한 검증
- Use hairline-width dividers (1.0/displayScale) for pixel-perfect rendering
- Adjust divider colors for better visual hierarchy
- Extract reusable Divider component in TimetableGridLayer
- Add timetable.background color asset to Timetable and Friends modules
- Apply background color to timetable views in both features
Store fetched themes in UserDefaults to make them available in widget extension context. Widgets now correctly display lecture colors by loading cached themes.
…dgetView

Separated timetable UI components to better distinguish between app and widget usage:
- Renamed TimetableZStack to TimetableView for app usage
- Created TimetableWidgetView for widget-specific rendering
- Updated all references in TimetableScene, LectureSearchScene, and TimetableUIProvider
- Updated widget to use TimetableWidgetView with proper environment values
- Cleaned up CLAUDE.md formatting
Add WidgetReloader dependency to automatically reload widgets when timetable or theme data changes in UserDefaults repositories. This ensures widgets stay in sync with app data without manual refresh.
@shp7724 shp7724 requested a review from a team as a code owner February 6, 2026 13:37
Copilot AI review requested due to automatic review settings February 6, 2026 13:37
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Widget/Timetable UI에서 보이는 렌더링/테마/배경 관련 이슈를 수정하고, 위젯 리로드 및 테마 로컬 저장을 추가한 PR입니다.

Changes:

  • 위젯 시간표 렌더링 개선(새 TimetableWidgetView, 그리드 라인/시간 라벨 계산 보정, 강의 색상 반영)
  • 위젯/화면 배경 및 tint 일관화, 공용 UI 컴포넌트 분리(CircleBadge, Divider)
  • 테마 목록 로컬 저장 및 변경 시 위젯 타임라인 리로드 추가

Reviewed changes

Copilot reviewed 31 out of 31 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
SNUTT/SNUTTWidget/Sources/UI/TimetableFullWidgetView.swift 위젯 풀 사이즈에서 TimetableWidgetView로 래핑 전환
SNUTT/SNUTTWidget/Sources/UI/TimetableCompactWidgetView.swift 위젯 컴팩트 뷰에 painter 전달하여 강의 색상 표시
SNUTT/SNUTTWidget/Sources/UI/TimetableAccessoryRectangularView.swift 액세서리 위젯에 painter 전달하여 강의 색상 표시
SNUTT/SNUTTWidget/Sources/SNUTTWidgetDataSource.swift 위젯에서 사용할 available themes 로드 추가
SNUTT/SNUTTWidget/Sources/SNUTTWidget.swift 엔트리에 available themes 포함 및 painter 생성 로직 복구
SNUTT/Project.swift DependenciesUtility 타겟 추가 및 WidgetKit 링크 보강
SNUTT/Modules/Utility/DependenciesUtility/Sources/WidgetReloaderDependency.swift 위젯 리로드 의존성(DependencyKey) 추가
SNUTT/Modules/Shared/SharedUIComponents/Sources/Sheet/SheetTopBar.swift TopBar tint 일관화
SNUTT/Modules/Shared/SharedUIComponents/Sources/CircleBadge.swift CircleBadge 공용 컴포넌트로 분리
SNUTT/Modules/Feature/TimetableUIComponents/Tests/TimetablePainterTests.swift 그리드 메트릭 계산 관련 테스트 추가
SNUTT/Modules/Feature/TimetableUIComponents/Sources/UI/TimetableWidgetView.swift 위젯 전용 시간표 렌더링 뷰 추가
SNUTT/Modules/Feature/TimetableUIComponents/Sources/UI/TimetableView.swift TimetableZStackTimetableView로 rename
SNUTT/Modules/Feature/TimetableUIComponents/Sources/UI/TimetableGridLayer.swift hairline/divider 및 표시 그리드 메트릭 반영
SNUTT/Modules/Feature/TimetableUIComponents/Sources/Presentation/TimetablePainter.swift 그리드 표시용 메트릭 계산 함수 추가
SNUTT/Modules/Feature/TimetableUIComponents/Sources/Presentation/TimetablePainter+Theme.swift 강의 customColor 기본 반영 보강
SNUTT/Modules/Feature/TimetableUIComponents/Resources/Assets.xcassets/Contents.json assets contents 포맷 정리
SNUTT/Modules/Feature/Timetable/Sources/UI/TimetableUIProvider.swift TimetableView로 교체
SNUTT/Modules/Feature/Timetable/Sources/UI/TimetableScene.swift 배경 컬러 적용 및 Divider/CircleBadge 정리
SNUTT/Modules/Feature/Timetable/Sources/UI/TimetableMenu/TimetableMenuSection.swift SharedUIComponents 임포트 추가
SNUTT/Modules/Feature/Timetable/Sources/UI/LectureSearchScene.swift TimetableView로 교체 및 포커스/툴바 일부 정리
SNUTT/Modules/Feature/Timetable/Sources/UI/LectureEditDetail/LectureEditDetailScene+Toolbar.swift 툴바 버튼 tint 일관화
SNUTT/Modules/Feature/Timetable/Sources/Infra/TimetableUserDefaultsRepository.swift 설정/선택 시간표 저장 시 위젯 리로드
SNUTT/Modules/Feature/Timetable/Resources/Assets.xcassets/timetable.background.colorset/Contents.json 시간표 배경 컬러 asset 추가
SNUTT/Modules/Feature/ThemesInterface/Sources/ThemeLocalRepository.swift 테마 로컬 저장소 프로토콜/의존성 키 추가
SNUTT/Modules/Feature/Themes/Sources/Presentation/ThemeViewModel.swift 테마 fetch 후 로컬 저장 추가
SNUTT/Modules/Feature/Themes/Sources/Infra/ThemeUserDefaultsRepository.swift 테마 로컬 저장(UserDefaults) 및 위젯 리로드
SNUTT/Modules/Feature/Themes/Sources/Composition/LiveDependencies.swift ThemeLocalRepository live dependency 등록
SNUTT/Modules/Feature/Settings/Sources/UI/Timetable/TimetableSettingView.swift 설정 화면 tint 일관화
SNUTT/Modules/Feature/Friends/Sources/UI/FriendsScene.swift 친구 시간표 화면 배경 및 Divider 추가
SNUTT/Modules/Feature/Friends/Resources/Assets.xcassets/timetable.background.colorset/Contents.json 친구 시간표 배경 컬러 asset 추가
SNUTT/CLAUDE.md 가이드 문구 일부 제거(코드 변경 아님)

Comment on lines 38 to 43
var availableThemes: [Theme] {
guard let data = userDefaults.data(forKey: "availableThemes"),
let themes = try? JSONDecoder().decode([Theme].self, from: data)
else { return [] }
return themes
}
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

availableThemes UserDefaults 키를 문자열 리터럴로 직접 사용하고 있어(예: \"availableThemes\") 다른 저장소(예: ThemeUserDefaultsRepository.Keys.availableThemes)와 드리프트 위험이 있습니다. 키를 shared constant/enum(예: Keys.availableThemes.rawValue)로 중앙화해서 재사용하는 형태로 맞추는 것을 권장합니다.

Copilot uses AI. Check for mistakes.
Comment on lines +13 to +24

public init(reloadAll: @escaping @Sendable () -> Void) {
self.reloadAll = reloadAll
}
}

public enum WidgetReloaderKey: DependencyKey {
public static let liveValue: WidgetReloader = .init(
reloadAll: { WidgetCenter.shared.reloadAllTimelines() }
)

public static let testValue: WidgetReloader = .init(reloadAll: {})
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

현재 WidgetReloaderreloadAll만 제공해서 호출 측이 항상 WidgetCenter.shared.reloadAllTimelines()에 종속됩니다. 위젯 종류가 특정 가능하다면 reload(kind:) 또는 reloadTimelines(ofKind:) 같은 더 좁은 API도 함께 제공해 불필요한 전체 리로드를 피할 수 있게 해주세요.

Suggested change
public init(reloadAll: @escaping @Sendable () -> Void) {
self.reloadAll = reloadAll
}
}
public enum WidgetReloaderKey: DependencyKey {
public static let liveValue: WidgetReloader = .init(
reloadAll: { WidgetCenter.shared.reloadAllTimelines() }
)
public static let testValue: WidgetReloader = .init(reloadAll: {})
public let reloadTimelinesOfKind: @Sendable (_ kind: String) -> Void
public init(
reloadAll: @escaping @Sendable () -> Void,
reloadTimelinesOfKind: @escaping @Sendable (_ kind: String) -> Void
) {
self.reloadAll = reloadAll
self.reloadTimelinesOfKind = reloadTimelinesOfKind
}
@inlinable
public func reloadTimelines(ofKind kind: String) {
reloadTimelinesOfKind(kind)
}
}
public enum WidgetReloaderKey: DependencyKey {
public static let liveValue: WidgetReloader = .init(
reloadAll: { WidgetCenter.shared.reloadAllTimelines() },
reloadTimelinesOfKind: { kind in
WidgetCenter.shared.reloadTimelines(ofKind: kind)
}
)
public static let testValue: WidgetReloader = .init(
reloadAll: {},
reloadTimelinesOfKind: { _ in }
)

Copilot uses AI. Check for mistakes.
Comment on lines 22 to 26
func storeSelectedTimetable(_ timetable: Timetable) throws {
let data = try JSONEncoder().encode(timetable)
userDefaults.set(data, forKey: Keys.currentTimetable.rawValue)
widgetReloader.reloadAll()
}
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

UserDefaults 저장 시마다 widgetReloader.reloadAll()로 전체 위젯 타임라인을 리로드하고 있습니다. 저장이 빈번할 수 있는 경로라면, (1) 특정 kind만 리로드하거나, (2) 변경을 debounce/throttle하는 방식으로 리로드 비용/레이트리밋 리스크를 줄이는 것을 권장합니다.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings February 6, 2026 13:45
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 1 comment.

Extract Xcode version to environment variable for easier maintenance across CI and deployment workflows.
…t access

Move UserDefaults key definitions from repository implementations to interface modules, enabling widgets to access the same keys without duplicating magic strings. Also fix CircleBadge color parameter and remove typo in TimetablePainter comment.
Copilot AI review requested due to automatic review settings February 6, 2026 14:30
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 35 out of 35 changed files in this pull request and generated 2 comments.

public init() {}
public var body: some View {
Rectangle()
.fill(Design.dividerColor)
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

TimetableGridLayer.DividerTimetableGridLayer의 중첩 타입 Design을 현재 스코프에서 직접 참조하고 있어 컴파일 에러가 날 가능성이 큽니다(중첩 타입 내부에서는 외부 타입의 멤버가 자동으로 스코프에 들어오지 않음). TimetableGridLayer.Design.dividerColor처럼 타입을 명시해서 참조하거나, DividerTimetableGridLayer 내부에 중첩 타입으로 두어 스코프를 명확히 해주세요.

Suggested change
.fill(Design.dividerColor)
.fill(TimetableGridLayer.Design.dividerColor)

Copilot uses AI. Check for mistakes.
TimetableGridLayer(painter: painter, geometry: geometry)
.frame(width: geometry.size.width, height: geometry.extendedContainerSize.height)
TimetableBlocksLayer(painter: painter, geometry: geometry)
.frame(width: geometry.size.width, height: geometry.size.height)
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

TimetableWidgetView에서 Grid는 extendedContainerSize.height, Blocks는 size.height로 서로 다른 높이를 사용하고 있어(특히 safeAreaInsets가 있는 경우) 레이어 정렬/클리핑이 일관되지 않을 수 있습니다. 위젯에서는 스크롤이 없으므로 두 레이어가 같은 기준 높이를 쓰도록 맞추거나, 의도적으로 다르게 둔 이유를 주석/구조로 명확히 해두는 편이 안전합니다.

Suggested change
.frame(width: geometry.size.width, height: geometry.size.height)
.frame(width: geometry.size.width, height: geometry.extendedContainerSize.height)

Copilot uses AI. Check for mistakes.
@shp7724 shp7724 merged commit f64319e into master Feb 6, 2026
1 check passed
@shp7724 shp7724 deleted the shp7724/misc branch February 6, 2026 14:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant