Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
5 changes: 4 additions & 1 deletion DevLog.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 2640;
LastUpgradeCheck = 2600;
LastUpgradeCheck = 2640;
TargetAttributes = {
DF3416442E45F67C00F9312B = {
CreatedOnToolsVersion = 16.3;
Expand All @@ -295,6 +295,7 @@
knownRegions = (
ko,
en,
Base,
);
mainGroup = DFD48AF72DC4D6E2005905C5;
minimizedProjectReferenceProxies = 1;
Expand Down Expand Up @@ -603,6 +604,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
Expand Down Expand Up @@ -671,6 +673,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
Expand Down
2 changes: 1 addition & 1 deletion DevLog.xcodeproj/xcshareddata/xcschemes/DevLog.xcscheme
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "2600"
LastUpgradeVersion = "2640"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,26 @@
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "2"
queueDebuggingEnableBacktraceRecording = "Yes">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<RemoteRunnable
runnableDebuggingMode = "2"
BundleIdentifier = "com.apple.springboard">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DFD3A96F2F8E89DD001DA7CD"
BuildableName = "DevLogWidgetExtension.appex"
BlueprintName = "DevLogWidgetExtension"
ReferencedContainer = "container:DevLog.xcodeproj">
</BuildableReference>
</RemoteRunnable>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DFD48AFF2DC4D6E2005905C5"
BuildableName = "DevLog.app"
BlueprintName = "DevLog"
ReferencedContainer = "container:DevLog.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</MacroExpansion>
<EnvironmentVariables>
<EnvironmentVariable
key = "_XCWidgetKind"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "2600"
LastUpgradeVersion = "2640"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
3 changes: 2 additions & 1 deletion DevLog/App/Assembler/DataAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ final class DataAssembler: Assembler {
AuthenticationService.self,
name: "GoogleAuthenticationService"
),
userService: container.resolve(UserService.self)
userService: container.resolve(UserService.self),
widgetSnapshotUpdater: container.resolve(WidgetSnapshotUpdater.self)
)
}

Expand Down
9 changes: 8 additions & 1 deletion DevLog/Data/Repository/AuthenticationRepositoryImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,22 @@ final class AuthenticationRepositoryImpl: AuthenticationRepository {
private let githubAuthService: AuthenticationService
private let googleAuthService: AuthenticationService
private let userService: UserService
private let widgetSnapshotUpdater: WidgetSnapshotUpdater

init(
authService: AuthService,
appleAuthService: AuthenticationService,
githubAuthService: AuthenticationService,
googleAuthService: AuthenticationService,
userService: UserService
userService: UserService,
widgetSnapshotUpdater: WidgetSnapshotUpdater
) {
self.authService = authService
self.appleAuthService = appleAuthService
self.githubAuthService = githubAuthService
self.googleAuthService = googleAuthService
self.userService = userService
self.widgetSnapshotUpdater = widgetSnapshotUpdater
}

func signIn(_ provider: AuthProvider) async throws {
Expand Down Expand Up @@ -58,6 +61,7 @@ final class AuthenticationRepositoryImpl: AuthenticationRepository {
let provider = AuthProvider(rawValue: providerID)
else {
try await authService.clearCurrentSession()
widgetSnapshotUpdater.clear()
return
}

Expand All @@ -73,6 +77,8 @@ final class AuthenticationRepositoryImpl: AuthenticationRepository {
} catch AuthError.notAuthenticated {
try await authService.clearCurrentSession()
}

widgetSnapshotUpdater.clear()
}

func restore() -> Bool {
Expand Down Expand Up @@ -100,5 +106,6 @@ final class AuthenticationRepositoryImpl: AuthenticationRepository {

try await authService.deleteCurrentUser()
try await authService.clearCurrentSession()
widgetSnapshotUpdater.clear()
}
}
6 changes: 6 additions & 0 deletions DevLog/Storage/Persistence/WidgetSnapshotUpdater.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,10 @@ final class WidgetSnapshotUpdater {
)
}
}

func clear() {
snapshotStore.clearSnapshots()
Comment thread
opficdev marked this conversation as resolved.
WidgetCenter.shared.reloadTimelines(ofKind: WidgetKind.todayTodo)
WidgetCenter.shared.reloadTimelines(ofKind: WidgetKind.heatmap)
Comment thread
opficdev marked this conversation as resolved.
Outdated
}
}
4 changes: 4 additions & 0 deletions DevLog/Widget/Common/WidgetSharedDefaultsStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@ final class WidgetSharedDefaultsStore {
func setData(_ value: Data?, forKey key: String) {
userDefaults.set(value, forKey: key)
}

func removeObject(forKey key: String) {
userDefaults.removeObject(forKey: key)
}
}
6 changes: 6 additions & 0 deletions DevLog/Widget/Common/WidgetSnapshotStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,10 @@ final class WidgetSnapshotStore {
guard let data = store.data(forKey: WidgetSnapshotKey.heatmap) else { return nil }
return try decoder.decode(HeatmapWidgetSnapshot.self, from: data)
}

func clearSnapshots() {
WidgetSnapshotKey.snapshots.forEach {
store.removeObject(forKey: $0)
}
}
}
4 changes: 2 additions & 2 deletions DevLogWidget/Heatmap/HeatmapWidget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ struct HeatmapWidget: Widget {
.containerBackground(.fill.tertiary, for: .widget)
.widgetURL(WidgetDeepLink.heatmapURL)
}
.configurationDisplayName("Heatmap")
.description("활동 히트맵을 표시합니다.")
.configurationDisplayName(LocalizedStringResource("widget_heatmap_title"))
.description("widget_heatmap_description")
.supportedFamilies([.systemSmall, .systemMedium])
}
}
4 changes: 2 additions & 2 deletions DevLogWidget/Heatmap/HeatmapWidgetConfigurationIntent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ import AppIntents
import WidgetKit

struct HeatmapWidgetConfigurationIntent: WidgetConfigurationIntent {
static var title: LocalizedStringResource = "Heatmap"
static var description = IntentDescription("활동 히트맵을 표시합니다.")
static var title: LocalizedStringResource = "widget_heatmap_title"
static var description = IntentDescription("widget_heatmap_description")
}
10 changes: 5 additions & 5 deletions DevLogWidget/Heatmap/HeatmapWidgetEntryView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ struct HeatmapWidgetEntryView: View {
switch widgetFamily {
case .systemSmall:
VStack(alignment: .leading, spacing: 4) {
header(title: "이번 달 히트맵")
header(title: "widget_heatmap_current_month_title")
WidgetHeatmapGrid(
months: currentMonths(from: snapshot),
selectedActivityKindRawValues: snapshot.selectedActivityKindRawValues,
Expand All @@ -38,7 +38,7 @@ struct HeatmapWidgetEntryView: View {
}
case .systemMedium:
VStack(alignment: .leading, spacing: 8) {
header(title: "이번 분기 히트맵")
header(title: "widget_heatmap_current_quarter_title")
WidgetHeatmapGrid(
months: snapshot.months,
selectedActivityKindRawValues: snapshot.selectedActivityKindRawValues,
Expand All @@ -58,15 +58,15 @@ struct HeatmapWidgetEntryView: View {
switch widgetFamily {
case .systemSmall:
VStack(alignment: .leading, spacing: 8) {
header(title: "이번 달 히트맵")
header(title: "widget_heatmap_current_month_title")
WidgetHeatmapPlaceholderGrid(
months: shape.currentMonths,
showsMonthTitles: false
)
}
case .systemMedium:
VStack(alignment: .leading, spacing: 8) {
header(title: "이번 분기 히트맵")
header(title: "widget_heatmap_current_quarter_title")
WidgetHeatmapPlaceholderGrid(
months: shape.quarterMonths,
showsMonthTitles: true
Expand All @@ -77,7 +77,7 @@ struct HeatmapWidgetEntryView: View {
}
}

private func header(title: String) -> some View {
private func header(title: LocalizedStringKey) -> some View {
HStack(alignment: .firstTextBaseline, spacing: 6) {
Text(title)
.font(.headline)
Expand Down
61 changes: 9 additions & 52 deletions DevLogWidget/Heatmap/WidgetHeatmapGrid.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,15 @@ struct WidgetHeatmapGrid: View {
showsMonthTitles: showsMonthTitles
)

HStack(alignment: .top, spacing: layout.weekdayLabelSpacing) {
WidgetHeatmapWeekdayLabels(layout: layout)

HStack(alignment: .top, spacing: layout.monthSpacing) {
ForEach(months, id: \.monthStart) { month in
WidgetHeatmapMonthGrid(
month: month,
layout: layout,
selectedActivityKindRawValues: selectedActivityKindRawValues,
maxCount: maxCount,
showsMonthTitle: showsMonthTitles
)
}
HStack(alignment: .top, spacing: layout.monthSpacing) {
ForEach(months, id: \.monthStart) { month in
WidgetHeatmapMonthGrid(
month: month,
layout: layout,
selectedActivityKindRawValues: selectedActivityKindRawValues,
maxCount: maxCount,
showsMonthTitle: showsMonthTitles
)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
Expand Down Expand Up @@ -71,45 +67,6 @@ struct WidgetHeatmapPlaceholderGrid: View {
}
}

private struct WidgetHeatmapWeekdayLabels: View {
let layout: WidgetHeatmapLayout
private let orderedWeekdays = Array(1...7)
private let weekdayLabels = [
2: "월",
4: "수",
6: "금"
]

var body: some View {
VStack(alignment: .leading, spacing: layout.cellSpacing) {
ForEach(orderedWeekdays, id: \.self) { weekday in
weekdayLabel(for: weekday)
}
}
.padding(.top, layout.weekdayTopPadding)
}

@ViewBuilder
private func weekdayLabel(for weekday: Int) -> some View {
if let label = weekdayLabels[weekday] {
Text(label)
.font(.caption2)
.foregroundStyle(.secondary)
.frame(
width: layout.weekdayLabelWidth,
height: layout.cellSize,
alignment: .leading
)
} else {
Color.clear
.frame(
width: layout.weekdayLabelWidth,
height: layout.cellSize
)
}
}
}

private struct WidgetHeatmapMonthGrid: View {
let month: WidgetHeatmapMonthSnapshot
let layout: WidgetHeatmapLayout
Expand Down
14 changes: 2 additions & 12 deletions DevLogWidget/Heatmap/WidgetHeatmapLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ struct WidgetHeatmapLayout {
let cellSpacing: CGFloat
let monthSpacing: CGFloat
let monthTitleSpacing: CGFloat
let weekdayLabelSpacing: CGFloat = Self.baseWeekdayLabelSpacing
let weekdayLabelWidth: CGFloat = Self.baseWeekdayLabelWidth
let showsMonthTitles: Bool

init(
Expand All @@ -37,10 +35,6 @@ struct WidgetHeatmapLayout {
)
}

var weekdayTopPadding: CGFloat {
showsMonthTitles ? cellSize + monthTitleSpacing : 0
}

var cellCornerRadius: CGFloat {
max(2, cellSize * 0.2)
}
Expand All @@ -49,8 +43,6 @@ struct WidgetHeatmapLayout {
private static let baseMonthSpacing: CGFloat = 10
private static let maxMonthSpacing: CGFloat = 26
private static let baseMonthTitleSpacing: CGFloat = 4
private static let baseWeekdayLabelSpacing: CGFloat = 5
private static let baseWeekdayLabelWidth: CGFloat = 14

private static func resolvedMonthTitleSpacing(showsMonthTitles: Bool) -> CGFloat {
// 월 제목을 표시하는 Medium에서만 제목과 셀 사이 간격을 확보한다.
Expand Down Expand Up @@ -99,10 +91,8 @@ struct WidgetHeatmapLayout {
) -> CGFloat {
// 셀 크기는 높이 기준으로 고정하고, 남는 가로폭만 월 간격 계산에 사용한다.
let sanitizedWeekCounts = sanitizedWeekCounts(weekCounts)
// 요일 라벨 영역, 전체 셀 컬럼, 월 내부 주차 spacing을 더해 기본 너비를 구한다.
let contentWidth = baseWeekdayLabelWidth
+ baseWeekdayLabelSpacing
+ cellSize * CGFloat(totalColumns(in: sanitizedWeekCounts))
// 전체 셀 컬럼과 월 내부 주차 spacing을 더해 기본 너비를 구한다.
let contentWidth = cellSize * CGFloat(totalColumns(in: sanitizedWeekCounts))
+ baseCellSpacing * CGFloat(totalColumnSpacings(in: sanitizedWeekCounts))
// 기본 너비보다 위젯이 넓을 때만 월 간격에 분배할 여유 폭이 생긴다.
return max(0, availableWidth - contentWidth)
Expand Down
Loading