|
Bogdan Timofte
authored
2 months ago
|
1
|
//
|
|
Bogdan Timofte
authored
2 months ago
|
2
|
// MeterInfoCardView.swift
|
|
Bogdan Timofte
authored
2 months ago
|
3
|
// USB Meter
|
|
|
4
|
//
|
|
|
5
|
|
|
|
6
|
import SwiftUI
|
|
|
7
|
|
|
Bogdan Timofte
authored
a month ago
|
8
|
struct MeterInfoCardView<Content: View, TrailingActions: View>: View {
|
|
Bogdan Timofte
authored
2 months ago
|
9
|
let title: String
|
|
Bogdan Timofte
authored
a month ago
|
10
|
let infoMessage: String?
|
|
Bogdan Timofte
authored
2 months ago
|
11
|
let tint: Color
|
|
Bogdan Timofte
authored
a month ago
|
12
|
let isCollapsible: Bool
|
|
|
13
|
@State private var isExpanded: Bool
|
|
Bogdan Timofte
authored
a month ago
|
14
|
@ViewBuilder var trailingActions: TrailingActions
|
|
Bogdan Timofte
authored
2 months ago
|
15
|
@ViewBuilder var content: Content
|
|
|
16
|
|
|
Bogdan Timofte
authored
a month ago
|
17
|
init(
|
|
|
18
|
title: String,
|
|
|
19
|
infoMessage: String? = nil,
|
|
|
20
|
tint: Color,
|
|
Bogdan Timofte
authored
a month ago
|
21
|
isCollapsible: Bool = false,
|
|
|
22
|
initiallyExpanded: Bool = true,
|
|
Bogdan Timofte
authored
a month ago
|
23
|
@ViewBuilder trailingActions: () -> TrailingActions = { EmptyView() },
|
|
Bogdan Timofte
authored
a month ago
|
24
|
@ViewBuilder content: () -> Content
|
|
|
25
|
) {
|
|
|
26
|
self.title = title
|
|
|
27
|
self.infoMessage = infoMessage
|
|
|
28
|
self.tint = tint
|
|
Bogdan Timofte
authored
a month ago
|
29
|
self.isCollapsible = isCollapsible
|
|
|
30
|
self._isExpanded = State(initialValue: initiallyExpanded)
|
|
Bogdan Timofte
authored
a month ago
|
31
|
self.trailingActions = trailingActions()
|
|
Bogdan Timofte
authored
a month ago
|
32
|
self.content = content()
|
|
|
33
|
}
|
|
|
34
|
|
|
Bogdan Timofte
authored
2 months ago
|
35
|
var body: some View {
|
|
Bogdan Timofte
authored
a month ago
|
36
|
VStack(alignment: .leading, spacing: isExpanded ? 12 : 0) {
|
|
Bogdan Timofte
authored
a month ago
|
37
|
HStack(spacing: 8) {
|
|
|
38
|
Text(title)
|
|
|
39
|
.font(.headline)
|
|
|
40
|
if let infoMessage {
|
|
|
41
|
ContextInfoButton(title: title, message: infoMessage)
|
|
|
42
|
}
|
|
Bogdan Timofte
authored
a month ago
|
43
|
Spacer(minLength: 0)
|
|
|
44
|
trailingActions
|
|
Bogdan Timofte
authored
a month ago
|
45
|
if isCollapsible {
|
|
|
46
|
Image(systemName: "chevron.up")
|
|
|
47
|
.font(.caption.weight(.semibold))
|
|
|
48
|
.foregroundColor(.secondary)
|
|
|
49
|
.rotationEffect(.degrees(isExpanded ? 0 : -180))
|
|
|
50
|
.animation(.easeInOut(duration: 0.2), value: isExpanded)
|
|
|
51
|
}
|
|
|
52
|
}
|
|
|
53
|
.contentShape(Rectangle())
|
|
|
54
|
.onTapGesture {
|
|
|
55
|
guard isCollapsible else { return }
|
|
|
56
|
withAnimation(.easeInOut(duration: 0.25)) {
|
|
|
57
|
isExpanded.toggle()
|
|
|
58
|
}
|
|
|
59
|
}
|
|
|
60
|
|
|
|
61
|
if isExpanded {
|
|
|
62
|
content
|
|
|
63
|
.transition(.opacity.combined(with: .move(edge: .top)))
|
|
Bogdan Timofte
authored
a month ago
|
64
|
}
|
|
Bogdan Timofte
authored
2 months ago
|
65
|
}
|
|
|
66
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
|
67
|
.padding(18)
|
|
|
68
|
.meterCard(tint: tint, fillOpacity: 0.18, strokeOpacity: 0.24)
|
|
|
69
|
}
|
|
Bogdan Timofte
authored
a month ago
|
70
|
}
|