Skip to content

Commit 989b9a4

Browse files
committed
feat: calculator v61 redesign
1 parent 9b59db3 commit 989b9a4

16 files changed

Lines changed: 1773 additions & 352 deletions

Bitkit/AppScene.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct AppScene: View {
3232
@StateObject private var contactsManager = ContactsManager()
3333
@State private var keyboardManager = KeyboardManager()
3434
@State private var trezorViewModel = TrezorViewModel()
35+
@State private var calculatorInputManager = CalculatorInputManager()
3536

3637
@State private var hideSplash = false
3738
@State private var removeSplash = false
@@ -148,6 +149,7 @@ struct AppScene: View {
148149
.environmentObject(contactsManager)
149150
.environment(keyboardManager)
150151
.environment(trezorViewModel)
152+
.environment(calculatorInputManager)
151153
.onChange(of: pubkyProfile.authState, initial: true) { _, authState in
152154
if authState == .authenticated, let pk = pubkyProfile.publicKey {
153155
Task {

Bitkit/Components/Header.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import SwiftUI
22

33
struct Header: View {
4+
@Environment(CalculatorInputManager.self) private var calculatorInput
5+
46
@AppStorage(PaykitFeatureFlags.uiEnabledKey) private var isPaykitUIEnabled = false
57

68
@EnvironmentObject var app: AppViewModel
@@ -33,12 +35,14 @@ struct Header: View {
3335
AppStatus(
3436
testID: "HeaderAppStatus",
3537
onPress: {
38+
if dismissCalculatorIfNeeded() { return }
3639
navigation.navigate(.appStatus)
3740
}
3841
)
3942

4043
if showWidgetEditButton {
4144
Button(action: {
45+
if dismissCalculatorIfNeeded() { return }
4246
isEditingWidgets.toggle()
4347
}) {
4448
Image(isEditingWidgets ? "check-mark" : "pencil")
@@ -53,6 +57,8 @@ struct Header: View {
5357
}
5458

5559
Button {
60+
if dismissCalculatorIfNeeded() { return }
61+
5662
withAnimation {
5763
app.showDrawer = true
5864
}
@@ -75,6 +81,8 @@ struct Header: View {
7581

7682
private var profileButton: some View {
7783
Button {
84+
if dismissCalculatorIfNeeded() { return }
85+
7886
if pubkyProfile.isAuthenticated || pubkyProfile.cachedName != nil {
7987
navigation.navigate(.profile)
8088
} else if pubkyProfile.initializationErrorMessage != nil {
@@ -103,6 +111,12 @@ struct Header: View {
103111
.accessibilityIdentifier("ProfileButton")
104112
}
105113

114+
private func dismissCalculatorIfNeeded() -> Bool {
115+
guard calculatorInput.isPresented else { return false }
116+
calculatorInput.dismiss()
117+
return true
118+
}
119+
106120
@ViewBuilder
107121
private var profileAvatar: some View {
108122
if let imageUri = pubkyProfile.displayImageUri {

Bitkit/Components/NumberPad.swift

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,38 @@ enum NumberPadType {
88

99
struct NumberPad: View {
1010
let type: NumberPadType
11+
let decimalSeparator: String
1112
let errorKey: String?
13+
let onDeleteLongPress: (() -> Void)?
1214
let onPress: (String) -> Void
1315

14-
init(type: NumberPadType = .simple, errorKey: String? = nil, onPress: @escaping (String) -> Void) {
16+
static var contentHeight: CGFloat {
17+
buttonHeight * 4
18+
}
19+
20+
private static var buttonHeight: CGFloat {
21+
UIScreen.main.isSmall ? 65 : 44 + 34
22+
}
23+
24+
init(
25+
type: NumberPadType = .simple,
26+
decimalSeparator: String = ".",
27+
errorKey: String? = nil,
28+
onDeleteLongPress: (() -> Void)? = nil,
29+
onPress: @escaping (String) -> Void
30+
) {
1531
self.type = type
32+
self.decimalSeparator = decimalSeparator
1633
self.errorKey = errorKey
34+
self.onDeleteLongPress = onDeleteLongPress
1735
self.onPress = onPress
1836
}
1937

20-
private let buttonHeight: CGFloat = UIScreen.main.isSmall ? 65 : 44 + 34
2138
private let gridItems = Array(repeating: GridItem(.flexible(), spacing: 0), count: 3)
2239
private let numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
40+
private var buttonHeight: CGFloat {
41+
Self.buttonHeight
42+
}
2343

2444
var body: some View {
2545
VStack(spacing: 0) {
@@ -59,7 +79,7 @@ struct NumberPad: View {
5979
}
6080
case .decimal:
6181
NumberPadButton(
62-
text: ".",
82+
text: decimalSeparator,
6383
height: buttonHeight,
6484
hasError: errorKey == ".",
6585
testID: "NDecimal"
@@ -98,6 +118,13 @@ struct NumberPad: View {
98118
.buttonStyle(NumberPadButtonStyle())
99119
.accessibilityIdentifier("NRemove")
100120
.frame(maxWidth: .infinity)
121+
.simultaneousGesture(
122+
LongPressGesture(minimumDuration: 0.45).onEnded { _ in
123+
guard let onDeleteLongPress else { return }
124+
Haptics.play(.buttonTap)
125+
onDeleteLongPress()
126+
}
127+
)
101128
}
102129
}
103130
}

Bitkit/Components/TabBar/TabBar.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import SwiftUI
22

33
struct TabBar: View {
4+
@Environment(CalculatorInputManager.self) private var calculatorInput
45
@EnvironmentObject var navigation: NavigationViewModel
56
@EnvironmentObject var sheets: SheetViewModel
67
@EnvironmentObject var wallet: WalletViewModel
78

89
var shouldShow: Bool {
10+
if calculatorInput.isPresented { return false }
11+
912
let routesWithTabBar = Set<Route>([.activityList, .savingsWallet, .spendingWallet])
1013
if navigation.path.isEmpty { return true }
1114
return navigation.currentRoute.map { routesWithTabBar.contains($0) } ?? false
@@ -34,7 +37,7 @@ struct TabBar: View {
3437
.transition(.move(edge: .bottom))
3538
}
3639
}
37-
.animation(.easeInOut, value: shouldShow)
40+
.animation(.easeOut(duration: 0.14), value: shouldShow)
3841
.bottomSafeAreaPadding()
3942
}
4043

@@ -66,6 +69,7 @@ struct TabBar: View {
6669
.frame(maxWidth: .infinity, maxHeight: .infinity)
6770
.overlay {
6871
TabBar()
72+
.environment(CalculatorInputManager())
6973
.environmentObject(NavigationViewModel())
7074
.environmentObject(SheetViewModel())
7175
}
@@ -79,6 +83,7 @@ struct TabBar: View {
7983
.frame(maxWidth: .infinity, maxHeight: .infinity)
8084
.overlay {
8185
TabBar()
86+
.environment(CalculatorInputManager())
8287
.environmentObject(NavigationViewModel())
8388
.environmentObject(SheetViewModel())
8489
}

Bitkit/Components/Widgets/BaseWidget.swift

Lines changed: 56 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -124,77 +124,74 @@ struct BaseWidget<Content: View>: View {
124124
}
125125

126126
var body: some View {
127-
Button {} label: {
128-
VStack(spacing: 0) {
129-
if isEditing {
130-
HStack {
131-
HStack(spacing: 16) {
132-
Image(metadata.icon)
133-
.resizable()
134-
.frame(width: 32, height: 32)
127+
VStack(spacing: 0) {
128+
if isEditing {
129+
HStack {
130+
HStack(spacing: 16) {
131+
Image(metadata.icon)
132+
.resizable()
133+
.frame(width: 32, height: 32)
134+
135+
BodyMSBText(truncate(metadata.name, 18))
136+
.lineLimit(1)
137+
}
135138

136-
BodyMSBText(truncate(metadata.name, 18))
137-
.lineLimit(1)
138-
}
139+
Spacer()
139140

140-
Spacer()
141-
142-
// Action buttons when in edit mode
143-
if isEditing {
144-
HStack(spacing: 8) {
145-
// Delete button
146-
Button {
147-
onDelete()
148-
} label: {
149-
Image("trash")
150-
.resizable()
151-
.foregroundColor(.textPrimary)
152-
.frame(width: 24, height: 24)
153-
}
154-
.frame(width: 32, height: 32)
155-
.contentShape(Rectangle())
156-
.accessibilityIdentifier("\(metadata.name)_WidgetActionDelete")
157-
158-
// Edit button
159-
Button {
160-
onEdit()
161-
} label: {
162-
Image("gear-six")
163-
.resizable()
164-
.foregroundColor(.textPrimary)
165-
.frame(width: 24, height: 24)
166-
}
167-
.frame(width: 32, height: 32)
168-
.contentShape(Rectangle())
169-
.accessibilityIdentifier("\(metadata.name)_WidgetActionEdit")
170-
171-
Image("burger")
141+
// Action buttons when in edit mode
142+
if isEditing {
143+
HStack(spacing: 8) {
144+
// Delete button
145+
Button {
146+
onDelete()
147+
} label: {
148+
Image("trash")
172149
.resizable()
173150
.foregroundColor(.textPrimary)
174151
.frame(width: 24, height: 24)
175-
.frame(width: 32, height: 32)
176-
.contentShape(Rectangle())
177-
.overlay {
178-
Color.clear
179-
.frame(width: 44, height: 44)
180-
.contentShape(Rectangle())
181-
.trackDragHandle()
182-
}
183-
.accessibilityIdentifier("\(metadata.name)_WidgetActionReorder")
184152
}
153+
.frame(width: 32, height: 32)
154+
.contentShape(Rectangle())
155+
.accessibilityIdentifier("\(metadata.name)_WidgetActionDelete")
156+
157+
// Edit button
158+
Button {
159+
onEdit()
160+
} label: {
161+
Image("gear-six")
162+
.resizable()
163+
.foregroundColor(.textPrimary)
164+
.frame(width: 24, height: 24)
165+
}
166+
.frame(width: 32, height: 32)
167+
.contentShape(Rectangle())
168+
.accessibilityIdentifier("\(metadata.name)_WidgetActionEdit")
169+
170+
Image("burger")
171+
.resizable()
172+
.foregroundColor(.textPrimary)
173+
.frame(width: 24, height: 24)
174+
.frame(width: 32, height: 32)
175+
.contentShape(Rectangle())
176+
.overlay {
177+
Color.clear
178+
.frame(width: 44, height: 44)
179+
.contentShape(Rectangle())
180+
.trackDragHandle()
181+
}
182+
.accessibilityIdentifier("\(metadata.name)_WidgetActionReorder")
185183
}
186184
}
187185
}
186+
}
188187

189-
// Widget content (only shown when not editing)
190-
if !isEditing {
191-
content
192-
}
188+
// Widget content (only shown when not editing)
189+
if !isEditing {
190+
content
193191
}
194-
.contentShape(Rectangle())
195192
}
196-
.accessibilityIdentifier("\(type.rawValue.capitalized)Widget")
197-
.buttonStyle(WidgetButtonStyle())
193+
.contentShape(Rectangle())
194+
.accessibilityIdentifierIfPresent(isEditing ? nil : "\(type.rawValue.capitalized)Widget")
198195
.frame(maxWidth: .infinity)
199196
.padding((hasBackground || isEditing) ? 16 : 0)
200197
.background((hasBackground || isEditing) ? Color.gray6 : Color.clear)
@@ -229,14 +226,6 @@ struct BaseWidget<Content: View>: View {
229226
}
230227
}
231228

232-
/// Custom button style for widgets
233-
struct WidgetButtonStyle: ButtonStyle {
234-
func makeBody(configuration: Configuration) -> some View {
235-
configuration.label
236-
.opacity(configuration.isPressed ? 0.9 : 1.0)
237-
}
238-
}
239-
240229
// Preview for the BaseWidget
241230
#Preview {
242231
VStack {

0 commit comments

Comments
 (0)