Fix key copying animation

This commit is contained in:
Shadowfacts 2022-09-16 22:00:52 -04:00
parent 13d4ce0ab7
commit 94c39fb5c5
1 changed files with 49 additions and 26 deletions

View File

@ -12,6 +12,7 @@ struct KeyView: View {
let key: TOTPKey let key: TOTPKey
let currentCode: TOTPCode let currentCode: TOTPCode
@State private var copying = false @State private var copying = false
@State private var copiedLabelWidth: CGFloat = 0
private var formattedCode: String { private var formattedCode: String {
let code = currentCode.code let code = currentCode.code
@ -26,6 +27,8 @@ struct KeyView: View {
var body: some View { var body: some View {
Button(action: self.copy) { Button(action: self.copy) {
HStack {
ZStack {
HStack { HStack {
VStack(alignment: .leading) { VStack(alignment: .leading) {
Text(key.issuer) Text(key.issuer)
@ -36,27 +39,37 @@ struct KeyView: View {
.font(.footnote) .font(.footnote)
} }
} }
Spacer() Spacer()
if copying {
Text("Copied!")
.font(.title2)
.transition(.move(edge: .trailing).combined(with: .opacity))
} else {
Text(formattedCode)
.font(.system(.title2, design: .monospaced))
.transition(.asymmetric(insertion: .move(edge: .trailing), removal: .move(edge: .leading)).combined(with: .opacity))
} }
// Text("\(currentCode.validUntil, style: .relative)") HStack {
// .font(.body.monospacedDigit()) Spacer()
Text(formattedCode)
.font(.system(.title2, design: .monospaced))
.opacity(copying ? 0 : 1)
Text("Copied!")
.font(.title2)
.opacity(copying ? 1 : 0)
// this nonsense shouldn't be necessary, but the transition only works the first time a code is copied, for some indiscernible reason
.background(GeometryReader { proxy in
Color.clear
.preference(key: CopiedLabelWidth.self, value: proxy.size.width)
.onPreferenceChange(CopiedLabelWidth.self) { newValue in
copiedLabelWidth = newValue
}
})
}
.offset(x: copying ? 0 : copiedLabelWidth)
.clipped()
}
.padding(.trailing, 8)
// I don't think this TimelineView should be necessary since the CodeHolder timer fires every .5 seconds // I don't think this TimelineView should be necessary since the CodeHolder timer fires every .5 seconds
TimelineView(.animation) { (ctx) in TimelineView(.animation) { (ctx) in
ZStack { ZStack {
CircularProgressView(progress: progress(at: Date()), colorChangeThreshold: 5.0 / Double(key.period)) CircularProgressView(progress: progress(at: ctx.date), colorChangeThreshold: 5.0 / Double(key.period))
Text(Int(round(currentCode.validUntil.timeIntervalSinceNow)).description) Text(Int(round(currentCode.validUntil.timeIntervalSinceNow)).description)
.font(.caption.monospacedDigit()) .font(.caption.monospacedDigit())
@ -79,11 +92,21 @@ struct KeyView: View {
withAnimation(.easeInOut(duration: 0.5)) { withAnimation(.easeInOut(duration: 0.5)) {
copying = true copying = true
} }
withAnimation(.easeInOut(duration: 0.5).delay(0.65)) { // .easeInOut(duration: 0.5).delay(0.65) does not work any more
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(650)) {
withAnimation(.easeInOut(duration: 0.5)) {
copying = false copying = false
} }
} }
} }
}
private struct CopiedLabelWidth: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
struct KeyView_Previews: PreviewProvider { struct KeyView_Previews: PreviewProvider {
static var key: TOTPKey { static var key: TOTPKey {