Skip to content

Commit f9cd8d3

Browse files
authored
[#417] sceneWidth를 사용해서 프레임 크기를 잡은 ui를 재구성한다 (#431)
* ui: 로그인 버튼을 sceneWidth이 필요하지 않도록 개선 * chore: iPad, macOS 에서도 어셋을 사용할 수 있도록 수정 * ui: HomeView에서 screenWidth 의존성 최소화 * ui: scneWidth * 0.08 형태를 largetitle의 pointSize로 수정 * refactor: 불필요 변수 제거 * ui: 프리뷰 히트맵 부분을 동적 ui화 * refactor: ScaledMetric으로 수정
1 parent 40c4d12 commit f9cd8d3

12 files changed

Lines changed: 72 additions & 73 deletions

File tree

DevLog/Resource/Assets.xcassets/Apple.imageset/Contents.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"images" : [
33
{
44
"filename" : "Apple_black.png",
5-
"idiom" : "iphone"
5+
"idiom" : "universal"
66
},
77
{
88
"appearances" : [
@@ -12,7 +12,7 @@
1212
}
1313
],
1414
"filename" : "Apple_white.png",
15-
"idiom" : "iphone"
15+
"idiom" : "universal"
1616
}
1717
],
1818
"info" : {

DevLog/Resource/Assets.xcassets/Github.imageset/Contents.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"images" : [
33
{
44
"filename" : "Github_black.png",
5-
"idiom" : "iphone"
5+
"idiom" : "universal"
66
},
77
{
88
"appearances" : [
@@ -12,7 +12,7 @@
1212
}
1313
],
1414
"filename" : "Github_white.png",
15-
"idiom" : "iphone"
15+
"idiom" : "universal"
1616
}
1717
],
1818
"info" : {

DevLog/Resource/Assets.xcassets/Google.imageset/Contents.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"images" : [
33
{
44
"filename" : "Google.png",
5-
"idiom" : "iphone"
5+
"idiom" : "universal"
66
}
77
],
88
"info" : {

DevLog/Resource/Assets.xcassets/Primary.imageset/Contents.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"images" : [
33
{
44
"filename" : "Primary_dark.png",
5-
"idiom" : "iphone"
5+
"idiom" : "universal"
66
}
77
],
88
"info" : {

DevLog/UI/Common/Component/LoginButton.swift

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import SwiftUI
1010
struct LoginButton: View {
1111
@State private var logo: Image?
1212
@State private var text = ""
13-
@State private var height = CGFloat.zero
14-
let action: () -> Void
13+
@ScaledMetric(relativeTo: .body) private var height = CGFloat(22)
14+
private let action: () -> Void
1515

1616
init(
1717
logo: Image? = nil,
@@ -27,31 +27,24 @@ struct LoginButton: View {
2727
Button(action: {
2828
action()
2929
}) {
30-
HStack {
31-
Text(text)
32-
.foregroundStyle(Color.primary)
33-
.font(.system(size: height / 3))
34-
.frame(maxWidth: .infinity, maxHeight: .infinity)
35-
}
30+
Text(text)
31+
.foregroundStyle(Color.primary)
32+
.font(.system(.body))
3633
}
37-
.contentShape(RoundedRectangle(cornerRadius: height / 2))
38-
.overlay(
39-
GeometryReader { proxy in
40-
ZStack(alignment: .leading) {
41-
RoundedRectangle(cornerRadius: height / 2)
42-
.stroke(Color.gray, lineWidth: 1)
43-
.onAppear {
44-
height = proxy.size.height
45-
}
46-
if let logo = logo {
47-
logo
48-
.resizable()
49-
.scaledToFit()
50-
.frame(width: height / 2, height: height / 2)
51-
.padding(.leading)
52-
}
34+
.frame(width: 300, height: height + 16)
35+
.contentShape(.capsule)
36+
.overlay {
37+
ZStack(alignment: .leading) {
38+
Capsule()
39+
.stroke(Color.gray, lineWidth: 1)
40+
if let logo = logo {
41+
logo
42+
.resizable()
43+
.scaledToFit()
44+
.frame(width: height, height: height)
45+
.padding(.leading)
5346
}
5447
}
55-
)
48+
}
5649
}
5750
}

DevLog/UI/Common/Component/TodoItemRow.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import SwiftUI
99

1010
struct TodoItemRow: View {
11-
@Environment(\.sceneWidth) private var sceneWidth
11+
@ScaledMetric(relativeTo: .largeTitle) private var labelWidth = CGFloat(34)
1212
private let item: TodoListItem
1313

1414
init(_ item: TodoListItem) {
@@ -19,7 +19,7 @@ struct TodoItemRow: View {
1919
HStack {
2020
Image(systemName: "checkmark.circle")
2121
.resizable()
22-
.frame(width: sceneWidth * 0.08, height: sceneWidth * 0.08)
22+
.frame(width: labelWidth, height: labelWidth)
2323
.foregroundStyle(item.isCompleted ? .green : .secondary)
2424
VStack(alignment: .leading, spacing: 0) {
2525
HStack {

DevLog/UI/Common/Component/WebItemRow.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@
88
import SwiftUI
99

1010
struct WebItemRow: View {
11-
@Environment(\.sceneWidth) private var sceneWidth
12-
11+
@ScaledMetric(relativeTo: .largeTitle) private var labelWidth = CGFloat(34)
1312
let item: WebPageItem
1413
let showsChevron: Bool
1514

1615
var body: some View {
1716
HStack {
1817
thumbnail
19-
.frame(width: sceneWidth * 0.08, height: sceneWidth * 0.08)
18+
.frame(width: labelWidth, height: labelWidth)
2019
.clipShape(RoundedRectangle(cornerRadius: 10))
2120

2221
VStack(alignment: .leading) {

DevLog/UI/Home/HomeView.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import SwiftUI
99

1010
struct HomeView: View {
1111
@Environment(\.diContainer) var container: any DIContainer
12-
@Environment(\.sceneWidth) var sceneWidth: CGFloat
1312
@State private var router = NavigationRouter()
1413
@State var viewModel: HomeViewModel
14+
@ScaledMetric(relativeTo: .largeTitle) private var labelWidth = CGFloat(34)
1515

1616
var body: some View {
1717
NavigationStack(path: $router.path) {
@@ -210,7 +210,7 @@ struct HomeView: View {
210210
} else {
211211
ForEach(viewModel.state.recentTodos, id: \.id) { todo in
212212
NavigationLink(value: Path.detail(todo.id)) {
213-
RecentTodoRow(todo: todo, sceneWidth: sceneWidth)
213+
RecentTodoRow(todo: todo)
214214
}
215215
}
216216
}
@@ -370,7 +370,7 @@ struct HomeView: View {
370370
HStack {
371371
RoundedRectangle(cornerRadius: 8)
372372
.fill(imageColor)
373-
.frame(width: sceneWidth * 0.08, height: sceneWidth * 0.08)
373+
.frame(width: labelWidth, height: labelWidth)
374374
.overlay {
375375
Image(systemName: systemName)
376376
.foregroundStyle(Color.white)
@@ -391,15 +391,15 @@ struct HomeView: View {
391391
}
392392

393393
private struct RecentTodoRow: View {
394+
@ScaledMetric(relativeTo: .largeTitle) private var labelWidth = CGFloat(34)
394395
let todo: RecentTodoItem
395-
let sceneWidth: CGFloat
396396

397397
var body: some View {
398398
let category = TodoCategoryItem(from: todo.category)
399399
HStack(alignment: .top, spacing: 12) {
400400
RoundedRectangle(cornerRadius: 8)
401401
.fill(category.color)
402-
.frame(width: sceneWidth * 0.08, height: sceneWidth * 0.08)
402+
.frame(width: labelWidth, height: labelWidth)
403403
.overlay {
404404
Image(systemName: category.symbolName)
405405
.foregroundStyle(Color.white)

DevLog/UI/Login/LoginView.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,14 @@ struct LoginView: View {
2525
LoginButton(logo: Image("Google"), text: String(localized: "login_google_sign_in")) {
2626
viewModel.send(.tapSignInButton(.google))
2727
}
28-
.frame(width: sceneWidth * 3 / 4, height: sceneWidth / 10)
2928

3029
LoginButton(logo: Image("Github"), text: String(localized: "login_github_sign_in")) {
3130
viewModel.send(.tapSignInButton(.github))
3231
}
33-
.frame(width: sceneWidth * 3 / 4, height: sceneWidth / 10)
3432

3533
LoginButton(logo: Image("Apple"), text: String(localized: "login_apple_sign_in")) {
3634
viewModel.send(.tapSignInButton(.apple))
3735
}
38-
.frame(width: sceneWidth * 3 / 4, height: sceneWidth / 10)
3936
}
4037
.padding(.bottom, 30)
4138
Text(String(localized: "login_terms_notice"))

DevLog/UI/Profile/HeatmapView.swift

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
import SwiftUI
99

1010
struct HeatmapView: View {
11-
@Environment(\.safeAreaInsets) private var safeAreaInsets
12-
@Environment(\.sceneWidth) private var sceneWidth
11+
@State private var availableWidth = CGFloat.zero
1312
let quarter: HeatmapQuarter
1413
let selectedActivityKinds: Set<ActivityKind>
1514
let selectedDay: HeatmapDay?
@@ -21,31 +20,32 @@ struct HeatmapView: View {
2120
weekCounts: quarter.months.map(\.weeks.count)
2221
)
2322

24-
HStack(alignment: .top, spacing: layout.monthSpacing) {
25-
ForEach(quarter.months) { month in
26-
MonthCompactHeatmapView(
27-
month: month,
28-
maxCount: maxCount,
29-
layout: layout,
30-
selectedActivityKinds: selectedActivityKinds,
31-
selectedDay: selectedDay,
32-
onSelectDay: onSelectDay
33-
)
23+
ScrollView(.horizontal) {
24+
LazyHStack(alignment: .top, spacing: layout.monthSpacing) {
25+
ForEach(quarter.months) { month in
26+
MonthCompactHeatmapView(
27+
month: month,
28+
maxCount: maxCount,
29+
layout: layout,
30+
selectedActivityKinds: selectedActivityKinds,
31+
selectedDay: selectedDay,
32+
onSelectDay: onSelectDay
33+
)
34+
}
35+
}
36+
.padding(.vertical, 2)
37+
.frame(width: layout.contentWidth, alignment: .leading)
38+
}
39+
.scrollIndicators(.hidden)
40+
.scrollDisabled(true)
41+
.frame(maxWidth: .infinity, alignment: .leading)
42+
.background {
43+
GeometryReader { geometry in
44+
Color.clear
45+
.onAppear { updateAvailableWidth(geometry.size.width) }
46+
.onChange(of: geometry.size.width) { updateAvailableWidth($1) }
3447
}
3548
}
36-
.padding(.vertical, 2)
37-
}
38-
39-
private var availableWidth: CGFloat {
40-
// ProfileView의 바깥 가로 패딩(16)과 히트맵 카드 내부 패딩(12)을 합한 값
41-
let horizontalPadding: CGFloat = 16 + 12
42-
return max(
43-
0,
44-
sceneWidth
45-
- safeAreaInsets.leading
46-
- safeAreaInsets.trailing
47-
- (horizontalPadding * 2)
48-
)
4949
}
5050

5151
private var maxCount: Int {
@@ -70,13 +70,22 @@ struct HeatmapView: View {
7070
}
7171
return value
7272
}
73+
74+
private func updateAvailableWidth(_ width: CGFloat) {
75+
if availableWidth != width {
76+
availableWidth = width
77+
}
78+
}
7379
}
7480

7581
private struct HeatmapLayout {
82+
private static let minimumCellSize: CGFloat = 8
83+
private static let maximumCellSize: CGFloat = 22
7684
let cellSize: CGFloat
7785
let cellSpacing: CGFloat = 4
7886
let monthSpacing: CGFloat = 12
7987
let monthTitleSpacing: CGFloat = 6
88+
let contentWidth: CGFloat
8089

8190
init(availableWidth: CGFloat, weekCounts: [Int]) {
8291
let totalColumns = max(weekCounts.reduce(0, +), 1)
@@ -85,7 +94,9 @@ private struct HeatmapLayout {
8594
}
8695
let fixedWidth = monthSpacing * CGFloat(max(weekCounts.count - 1, 0))
8796
+ cellSpacing * CGFloat(totalColumnSpacings)
88-
cellSize = max(0, availableWidth - fixedWidth) / CGFloat(totalColumns)
97+
let fittingCellSize = max(0, availableWidth - fixedWidth) / CGFloat(totalColumns)
98+
cellSize = min(max(fittingCellSize, Self.minimumCellSize), Self.maximumCellSize)
99+
contentWidth = cellSize * CGFloat(totalColumns) + fixedWidth
89100
}
90101

91102
var cellCornerRadius: CGFloat {

0 commit comments

Comments
 (0)