Skip to content

Commit 22db25e

Browse files
committed
refactor(ui): InsetHeaderScrollView, shared tab swipes
1 parent 18313b0 commit 22db25e

17 files changed

Lines changed: 469 additions & 376 deletions

File tree

Bitkit/Assets.xcassets/Illustrations/lightbulb.imageset/Contents.json renamed to Bitkit/Assets.xcassets/Illustrations/lightbulb-figure.imageset/Contents.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"images" : [
33
{
4-
"filename" : "lightbulb.png",
4+
"filename" : "lightbulb-figure.png",
55
"idiom" : "universal",
66
"scale" : "1x"
77
},
9.39 KB
Loading
Binary file not shown.

Bitkit/Assets.xcassets/Illustrations/lightning.imageset/Contents.json renamed to Bitkit/Assets.xcassets/icons/lightbulb.imageset/Contents.json

File renamed without changes.

Bitkit/Assets.xcassets/Illustrations/lightbulb.imageset/lightbulb.png renamed to Bitkit/Assets.xcassets/icons/lightbulb.imageset/lightbulb.png

File renamed without changes.

Bitkit/Components/Activity/ActivityList.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import SwiftUI
44
struct ActivityList: View {
55
@EnvironmentObject var activity: ActivityListViewModel
66
@EnvironmentObject var feeEstimatesManager: FeeEstimatesManager
7-
@State private var isHorizontalSwipe = false
87

98
let viewType: ActivityViewType
109

@@ -31,7 +30,6 @@ struct ActivityList: View {
3130
ActivityRow(item: item, feeEstimates: feeEstimatesManager.estimates)
3231
}
3332
.accessibilityIdentifier("Activity-\(index)")
34-
.disabled(isHorizontalSwipe)
3533
}
3634
}
3735
}

Bitkit/Components/Home/SuggestionsCard.swift

Lines changed: 0 additions & 57 deletions
This file was deleted.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import SwiftUI
2+
3+
// MARK: - InsetHeaderScrollView
4+
5+
// Measured top header (`safeAreaInset`) and scroll content with `minHeight` to fill the viewport below it.
6+
// Optional `scrollModifier` for refresh, margins, etc.
7+
8+
private enum HeaderHeightPreferenceKey: PreferenceKey {
9+
static var defaultValue: CGFloat = 0
10+
11+
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
12+
let next = nextValue()
13+
guard next > 0 else { return }
14+
value = next
15+
}
16+
}
17+
18+
private struct HeaderHeightMeasure: View {
19+
var body: some View {
20+
GeometryReader { proxy in
21+
Color.clear.preference(key: HeaderHeightPreferenceKey.self, value: proxy.size.height)
22+
}
23+
}
24+
}
25+
26+
struct InsetHeaderScrollView<Header: View, Content: View, ScrollModifier: ViewModifier>: View {
27+
let header: () -> Header
28+
let content: () -> Content
29+
let scrollModifier: ScrollModifier
30+
31+
@State private var headerHeight: CGFloat = 0
32+
33+
init(
34+
header: @escaping () -> Header,
35+
content: @escaping () -> Content,
36+
scrollModifier: ScrollModifier = EmptyModifier()
37+
) {
38+
self.header = header
39+
self.content = content
40+
self.scrollModifier = scrollModifier
41+
}
42+
43+
var body: some View {
44+
GeometryReader { geo in
45+
ScrollView(showsIndicators: false) {
46+
content()
47+
.frame(minHeight: contentMinHeight(in: geo), alignment: .top)
48+
}
49+
.modifier(scrollModifier)
50+
.safeAreaInset(edge: .top, spacing: 0) {
51+
header().background(HeaderHeightMeasure())
52+
}
53+
.onPreferenceChange(HeaderHeightPreferenceKey.self) { newValue in
54+
if newValue > 0 { headerHeight = newValue }
55+
}
56+
}
57+
}
58+
59+
/// Before the first header measurement, use full height so `minHeight` is non-negative.
60+
private func contentMinHeight(in geo: GeometryProxy) -> CGFloat {
61+
let insetTop = headerHeight > 0 ? headerHeight : 0
62+
return max(0, geo.size.height - insetTop)
63+
}
64+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import SwiftUI
2+
3+
/// Shared gradient tile used by suggestions widget and shop discover
4+
struct SuggestionCard: View {
5+
let title: String
6+
let description: String
7+
let imageName: String
8+
let accentColor: Color
9+
let onTap: () -> Void
10+
let onDismiss: (() -> Void)?
11+
12+
init(
13+
title: String,
14+
description: String,
15+
imageName: String,
16+
accentColor: Color,
17+
onTap: @escaping () -> Void,
18+
onDismiss: (() -> Void)? = nil
19+
) {
20+
self.title = title
21+
self.description = description
22+
self.imageName = imageName
23+
self.accentColor = accentColor
24+
self.onTap = onTap
25+
self.onDismiss = onDismiss
26+
}
27+
28+
var body: some View {
29+
ZStack(alignment: .topTrailing) {
30+
Button(action: onTap) {
31+
VStack(alignment: .leading, spacing: 0) {
32+
Spacer()
33+
34+
Image(imageName)
35+
.resizable()
36+
.scaledToFit()
37+
.frame(width: 96, height: 96)
38+
.frame(maxWidth: .infinity, alignment: .center)
39+
40+
Text(title)
41+
.font(.custom(Fonts.black, size: 20))
42+
.lineLimit(1)
43+
.kerning(-0.5)
44+
.textCase(.uppercase)
45+
.padding(.top, 4)
46+
47+
CaptionBText(description)
48+
}
49+
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
50+
.padding(.vertical, 12)
51+
.padding(.horizontal, 16)
52+
.background(
53+
RoundedRectangle(cornerRadius: 16)
54+
.fill(
55+
LinearGradient(
56+
gradient: Gradient(stops: [
57+
.init(color: accentColor, location: 0.0),
58+
.init(color: Color.black.opacity(0.1), location: 0.9),
59+
.init(color: Color.black, location: 1.0),
60+
]),
61+
startPoint: .top,
62+
endPoint: .bottom
63+
)
64+
)
65+
)
66+
}
67+
.buttonStyle(.plain)
68+
.zIndex(0)
69+
70+
if let onDismiss {
71+
Button(action: onDismiss) {
72+
Image("x-mark")
73+
.resizable()
74+
.aspectRatio(contentMode: .fit)
75+
.foregroundColor(.textSecondary)
76+
.frame(width: 16, height: 16)
77+
.padding(8)
78+
.contentShape(Rectangle())
79+
}
80+
.padding(8)
81+
.contentShape(Rectangle())
82+
.accessibilityIdentifier("SuggestionDismiss")
83+
.accessibility(label: Text("Dismiss \(title)"))
84+
.buttonStyle(.plain)
85+
.zIndex(1)
86+
}
87+
}
88+
}
89+
}

Bitkit/Components/Home/Suggestions.swift renamed to Bitkit/Components/Widgets/Suggestions.swift

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ let cards: [SuggestionCardData] = [
7575
id: "support",
7676
title: t("cards__support__title"),
7777
description: t("cards__support__description"),
78-
imageName: "lightbulb",
78+
imageName: "lightbulb-figure",
7979
color: .yellow24,
8080
action: .support
8181
),
@@ -245,10 +245,16 @@ struct Suggestions: View {
245245
spacing: 16
246246
) {
247247
ForEach(visibleCards) { card in
248-
SuggestionCard(data: card, onDismiss: { dismissCard(card) })
249-
.onTapGesture { if !isPreview { onItemTap(card) } }
250-
.accessibilityElement(children: .contain)
251-
.accessibilityIdentifier("Suggestion-\(card.accessibilityId)")
248+
SuggestionCard(
249+
title: card.title,
250+
description: card.description,
251+
imageName: card.imageName,
252+
accentColor: card.color,
253+
onTap: { if !isPreview { onItemTap(card) } },
254+
onDismiss: { dismissCard(card) }
255+
)
256+
.accessibilityElement(children: .contain)
257+
.accessibilityIdentifier("Suggestion-\(card.accessibilityId)")
252258
}
253259
}
254260
.allowsHitTesting(!isPreview)

0 commit comments

Comments
 (0)