Link'n'Sync indeterminate primary spinner
This commit is contained in:
parent
867bac9f55
commit
1a51bebf69
@ -1619,6 +1619,7 @@
|
||||
B99288002CF124AC000D62C4 /* Text+Links.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99287FF2CF124AC000D62C4 /* Text+Links.swift */; };
|
||||
B99B155D2A71BA5200E26DAC /* StoryContextViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99B155C2A71BA5200E26DAC /* StoryContextViewState.swift */; };
|
||||
B9A0807A2B07D76A000FDB5B /* HomeTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9A080792B07D76A000FDB5B /* HomeTabViewController.swift */; };
|
||||
B9A47ACE2D36DA6B0024DD9C /* circular_indeterminate.json in Resources */ = {isa = PBXBuildFile; fileRef = B9A47ACD2D36DA6B0024DD9C /* circular_indeterminate.json */; };
|
||||
B9A53B912CF507FB0000578B /* LinkAndSyncProgressModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9A53B902CF507FB0000578B /* LinkAndSyncProgressModal.swift */; };
|
||||
B9A53B932CF7928A0000578B /* SheetPreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9A53B922CF7928A0000578B /* SheetPreviewViewController.swift */; };
|
||||
B9A53B952CF799590000578B /* LinkOrSyncPickerSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9A53B942CF799590000578B /* LinkOrSyncPickerSheet.swift */; };
|
||||
@ -5373,6 +5374,7 @@
|
||||
B99287FF2CF124AC000D62C4 /* Text+Links.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Text+Links.swift"; sourceTree = "<group>"; };
|
||||
B99B155C2A71BA5200E26DAC /* StoryContextViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoryContextViewState.swift; sourceTree = "<group>"; };
|
||||
B9A080792B07D76A000FDB5B /* HomeTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTabViewController.swift; sourceTree = "<group>"; };
|
||||
B9A47ACD2D36DA6B0024DD9C /* circular_indeterminate.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = circular_indeterminate.json; sourceTree = "<group>"; };
|
||||
B9A53B902CF507FB0000578B /* LinkAndSyncProgressModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkAndSyncProgressModal.swift; sourceTree = "<group>"; };
|
||||
B9A53B922CF7928A0000578B /* SheetPreviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SheetPreviewViewController.swift; sourceTree = "<group>"; };
|
||||
B9A53B942CF799590000578B /* LinkOrSyncPickerSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkOrSyncPickerSheet.swift; sourceTree = "<group>"; };
|
||||
@ -10519,6 +10521,7 @@
|
||||
34848D5D25D43ADD00E5034B /* add-money.json */,
|
||||
88DBDFBA2638FFBC00C2101C /* audio-played-dot.json */,
|
||||
34848D5A25D43ADD00E5034B /* cash-out.json */,
|
||||
B9A47ACD2D36DA6B0024DD9C /* circular_indeterminate.json */,
|
||||
880FB3EA28CA53D200FA1C10 /* determinate_spinner_44.json */,
|
||||
880FB3EC28CA53D300FA1C10 /* determinate_spinner_56.json */,
|
||||
88E8BEEF28D53C3700509CE2 /* indeterminate_spinner_20.json */,
|
||||
@ -14471,6 +14474,7 @@
|
||||
45B74A7B2044AAB600CD42F8 /* chord.aifc in Resources */,
|
||||
45B74A892044AAB600CD42F8 /* circles-quiet.aifc in Resources */,
|
||||
45B74A832044AAB600CD42F8 /* circles.aifc in Resources */,
|
||||
B9A47ACE2D36DA6B0024DD9C /* circular_indeterminate.json in Resources */,
|
||||
4503F1BE20470A5B00CEE724 /* classic-quiet.aifc in Resources */,
|
||||
4503F1BF20470A5B00CEE724 /* classic.aifc in Resources */,
|
||||
45B74A872044AAB600CD42F8 /* complete-quiet.aifc in Resources */,
|
||||
|
||||
1
Signal/Lottie/circular_indeterminate.json
Normal file
1
Signal/Lottie/circular_indeterminate.json
Normal file
@ -0,0 +1 @@
|
||||
{"v":"5.9.0","fr":60,"ip":0,"op":110,"w":52,"h":52,"nm":"Progress indicator - Indeterminate - Circular","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":4,"ty":4,"nm":"1","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-26]},{"t":81,"s":[0]}],"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[48,48],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.133333340287,0.403921574354,0.960784316063,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[5]},{"i":{"x":[0.679],"y":[0.748]},"o":{"x":[0.43],"y":[0]},"t":40,"s":[0]},{"t":109,"s":[87.471]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":0,"s":[6]},{"i":{"x":[0.614],"y":[0.241]},"o":{"x":[0.16],"y":[0]},"t":40,"s":[75]},{"t":109,"s":[89.606]}],"ix":2},"o":{"a":0,"k":1,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":110,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Rotator","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":109,"s":[397.294]},{"t":323,"s":[1444]}],"ix":10},"p":{"a":0,"k":[26,26,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[],"ip":0,"op":111,"st":0,"bm":0}],"markers":[]}
|
||||
@ -3,6 +3,7 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
import Lottie
|
||||
import SwiftUI
|
||||
import SignalUI
|
||||
import SignalServiceKit
|
||||
@ -11,40 +12,67 @@ import SignalServiceKit
|
||||
|
||||
class LinkAndSyncProgressViewModel: ObservableObject {
|
||||
|
||||
enum Phase {
|
||||
case preparing
|
||||
case syncing
|
||||
}
|
||||
|
||||
@Published private(set) var progress: Float = 0
|
||||
@Published private(set) var canBeCancelled: Bool = false
|
||||
@Published var phase: Phase = .preparing
|
||||
@Published var linkNSyncTask: Task<Void, Never>?
|
||||
@Published var didTapCancel: Bool = false
|
||||
@Published var taskProgress: Float = 0
|
||||
@Published var isIndeterminate = true
|
||||
@Published var canBeCancelled: Bool = false
|
||||
@Published var linkNSyncTask: Task<Void, Never>?
|
||||
|
||||
#if DEBUG
|
||||
@Published var progressSourceLabel: String?
|
||||
#endif
|
||||
|
||||
var cancelButtonEnabled: Bool {
|
||||
linkNSyncTask != nil && canBeCancelled && !didTapCancel
|
||||
}
|
||||
|
||||
var title: String {
|
||||
switch phase {
|
||||
case .preparing:
|
||||
OWSLocalizedString(
|
||||
"LINK_NEW_DEVICE_SYNC_PROGRESS_TITLE_PREPARING",
|
||||
comment: "Title for a progress modal indicating the sync progress while it's preparing for upload"
|
||||
)
|
||||
case .syncing:
|
||||
OWSLocalizedString(
|
||||
"LINK_NEW_DEVICE_SYNC_PROGRESS_TITLE",
|
||||
comment: "Title for a progress modal indicating the sync progress"
|
||||
)
|
||||
}
|
||||
var progress: Float {
|
||||
didTapCancel ? 0 : taskProgress
|
||||
}
|
||||
|
||||
func updateProgress(progress: Float, canBeCancelled: Bool) {
|
||||
self.progress = progress
|
||||
fileprivate func updateProgress(progress: Float, canBeCancelled: Bool) {
|
||||
withAnimation(.smooth) {
|
||||
self.taskProgress = progress
|
||||
}
|
||||
self.canBeCancelled = canBeCancelled
|
||||
}
|
||||
|
||||
func updateProgress(progress: OWSProgress) {
|
||||
// This seems to help with the Lottie bug mentioned below
|
||||
objectWillChange.send()
|
||||
|
||||
let canBeCancelled: Bool
|
||||
if let label = progress.currentSourceLabel {
|
||||
canBeCancelled = label != PrimaryLinkNSyncProgressPhase.waitingForLinking.rawValue
|
||||
} else {
|
||||
canBeCancelled = false
|
||||
}
|
||||
|
||||
if progress.completedUnitCount > PrimaryLinkNSyncProgressPhase.waitingForLinking.percentOfTotalProgress {
|
||||
self.isIndeterminate = false
|
||||
}
|
||||
|
||||
updateProgress(
|
||||
progress: progress.percentComplete,
|
||||
canBeCancelled: canBeCancelled
|
||||
)
|
||||
|
||||
#if DEBUG
|
||||
progressSourceLabel = progress.currentSourceLabel
|
||||
#endif
|
||||
}
|
||||
|
||||
func cancel() {
|
||||
linkNSyncTask?.cancel()
|
||||
withAnimation(.smooth(duration: 0.2)) {
|
||||
taskProgress = 0
|
||||
}
|
||||
didTapCancel = true
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) { [weak self] in
|
||||
self?.isIndeterminate = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Hosting Controller
|
||||
@ -93,6 +121,11 @@ struct LinkAndSyncProgressView: View {
|
||||
|
||||
@ObservedObject fileprivate var viewModel: LinkAndSyncProgressViewModel
|
||||
|
||||
@State private var indeterminateProgressShouldShow = false
|
||||
private var loopMode: LottieLoopMode {
|
||||
viewModel.isIndeterminate ? .loop : .playOnce
|
||||
}
|
||||
|
||||
// If the first portion fills very quickly before the view is visible,
|
||||
// we still want to animate it from 0.
|
||||
private var progressToShow: Float {
|
||||
@ -100,21 +133,77 @@ struct LinkAndSyncProgressView: View {
|
||||
case .appearing:
|
||||
0
|
||||
case .cancelled, .finished, .none:
|
||||
viewModel.progress
|
||||
indeterminateProgressShouldShow ? 0 : viewModel.progress
|
||||
}
|
||||
}
|
||||
|
||||
private var showIndeterminateProgress: Bool {
|
||||
switch appearanceTransitionState {
|
||||
case .none, .appearing, .cancelled:
|
||||
false
|
||||
case .finished:
|
||||
viewModel.isIndeterminate || indeterminateProgressShouldShow
|
||||
}
|
||||
}
|
||||
|
||||
private var title: String {
|
||||
if viewModel.didTapCancel {
|
||||
OWSLocalizedString(
|
||||
"LINK_NEW_DEVICE_SYNC_PROGRESS_TILE_CANCELLING",
|
||||
comment: "Title for a progress modal that would be indicating the sync progress while it's cancelling that sync"
|
||||
)
|
||||
} else if indeterminateProgressShouldShow || appearanceTransitionState != .finished {
|
||||
OWSLocalizedString(
|
||||
"LINK_NEW_DEVICE_SYNC_PROGRESS_TITLE_PREPARING",
|
||||
comment: "Title for a progress modal indicating the sync progress while it's preparing for upload"
|
||||
)
|
||||
} else {
|
||||
OWSLocalizedString(
|
||||
"LINK_NEW_DEVICE_SYNC_PROGRESS_TITLE",
|
||||
comment: "Title for a progress modal indicating the sync progress"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
// TODO: this should become an "indefinite" animation when cancelled
|
||||
CircleProgressView(progress: progressToShow)
|
||||
.padding(.top, 14)
|
||||
.padding(.bottom, 20)
|
||||
.animation(.linear, value: progressToShow)
|
||||
ZStack {
|
||||
CircleProgressView(progress: progressToShow)
|
||||
.animation(.smooth, value: appearanceTransitionState)
|
||||
.animation(.smooth, value: indeterminateProgressShouldShow)
|
||||
|
||||
Text(viewModel.title)
|
||||
if showIndeterminateProgress {
|
||||
LottieView(animation: .named("circular_indeterminate"))
|
||||
.playing(loopMode: loopMode)
|
||||
.animationDidFinish { completed in
|
||||
print("animationDidFinish: \(completed)")
|
||||
guard completed else { return }
|
||||
indeterminateProgressShouldShow = false
|
||||
}
|
||||
.onAppear {
|
||||
indeterminateProgressShouldShow = true
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.top, 12)
|
||||
.padding(.bottom, 20)
|
||||
.onChange(of: viewModel.isIndeterminate) { isIndeterminate in
|
||||
guard !isIndeterminate else { return }
|
||||
// There is a seemingly rng bug where the Lottie
|
||||
// view doesn't properly respond to the change of
|
||||
// loopMode, leading to .animationDidFinish never
|
||||
// being called. The animation is a bit over one
|
||||
// second, so if it's not done after two seconds,
|
||||
// force hide it.
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
||||
self.indeterminateProgressShouldShow = false
|
||||
}
|
||||
}
|
||||
|
||||
Text(title)
|
||||
.font(.headline)
|
||||
.padding(.bottom, 8)
|
||||
.animation(.none, value: title)
|
||||
|
||||
Text(String(
|
||||
format: OWSLocalizedString(
|
||||
@ -136,11 +225,17 @@ struct LinkAndSyncProgressView: View {
|
||||
.padding(.bottom, 36)
|
||||
|
||||
Button(CommonStrings.cancelButton) {
|
||||
viewModel.linkNSyncTask?.cancel()
|
||||
viewModel.didTapCancel = true
|
||||
viewModel.cancel()
|
||||
}
|
||||
.disabled(!viewModel.cancelButtonEnabled)
|
||||
.font(.body.weight(.semibold))
|
||||
|
||||
#if DEBUG
|
||||
Text("DEBUG: " + (viewModel.progressSourceLabel ?? "none"))
|
||||
.padding(.top)
|
||||
.foregroundStyle(Color.Signal.quaternaryLabel)
|
||||
.animation(.none, value: viewModel.progressSourceLabel)
|
||||
#endif
|
||||
}
|
||||
.padding(.horizontal, 26)
|
||||
.padding(.vertical, 28)
|
||||
@ -163,9 +258,9 @@ struct LinkAndSyncProgressView: View {
|
||||
.rotation(.degrees(-90))
|
||||
.stroke(style: StrokeStyle(lineWidth: 4, lineCap: .round, lineJoin: .round))
|
||||
.foregroundStyle(Color.Signal.accent)
|
||||
.animation(.linear, value: progress)
|
||||
}
|
||||
.frame(width: 52, height: 52)
|
||||
.frame(width: 48, height: 48)
|
||||
.padding(2)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -173,30 +268,100 @@ struct LinkAndSyncProgressView: View {
|
||||
// MARK: Previews
|
||||
|
||||
#if DEBUG
|
||||
|
||||
@MainActor
|
||||
@available(iOS 17, *)
|
||||
#Preview {
|
||||
SheetPreviewViewController {
|
||||
let modal = LinkAndSyncProgressModal()
|
||||
modal.linkNSyncTask = Task {}
|
||||
private func setupDemoProgress(
|
||||
modal: LinkAndSyncProgressModal,
|
||||
slowLinking: Bool
|
||||
) async throws {
|
||||
let progress = OWSProgress.createSink { progress in
|
||||
modal.viewModel.updateProgress(progress: progress)
|
||||
}
|
||||
|
||||
Task { @MainActor in
|
||||
modal.viewModel.updateProgress(progress: 0.2, canBeCancelled: false)
|
||||
let loadingPoints = (0..<20)
|
||||
.map { _ in Float.random(in: (0.2)...1) }
|
||||
.sorted()
|
||||
let waitForLinkingProgress = await progress.addSource(
|
||||
withLabel: PrimaryLinkNSyncProgressPhase.waitingForLinking.rawValue,
|
||||
unitCount: PrimaryLinkNSyncProgressPhase.waitingForLinking.percentOfTotalProgress
|
||||
)
|
||||
let exportingBackupProgress = await progress.addSource(
|
||||
withLabel: PrimaryLinkNSyncProgressPhase.exportingBackup.rawValue,
|
||||
unitCount: PrimaryLinkNSyncProgressPhase.exportingBackup.percentOfTotalProgress
|
||||
)
|
||||
let uploadingBackupProgress = await progress.addSource(
|
||||
withLabel: PrimaryLinkNSyncProgressPhase.uploadingBackup.rawValue,
|
||||
unitCount: PrimaryLinkNSyncProgressPhase.uploadingBackup.percentOfTotalProgress
|
||||
)
|
||||
let markUploadedProgress = await progress.addSource(
|
||||
withLabel: PrimaryLinkNSyncProgressPhase.finishing.rawValue,
|
||||
unitCount: PrimaryLinkNSyncProgressPhase.finishing.percentOfTotalProgress
|
||||
)
|
||||
|
||||
for point in loadingPoints {
|
||||
try? await Task.sleep(for: .milliseconds(100))
|
||||
modal.viewModel.updateProgress(progress: point, canBeCancelled: point >= 0.4)
|
||||
modal.viewModel.phase = point >= 0.6 ? .syncing : .preparing
|
||||
}
|
||||
if slowLinking {
|
||||
try await Task.sleep(for: .milliseconds(700))
|
||||
} else {
|
||||
try await Task.sleep(for: .milliseconds(100))
|
||||
}
|
||||
|
||||
try? await Task.sleep(for: .milliseconds(100))
|
||||
modal.viewModel.updateProgress(progress: 1, canBeCancelled: true)
|
||||
waitForLinkingProgress.incrementCompletedUnitCount(by: PrimaryLinkNSyncProgressPhase.waitingForLinking.percentOfTotalProgress)
|
||||
|
||||
await modal.completeAndDismiss()
|
||||
if slowLinking {
|
||||
try await Task.sleep(for: .milliseconds(700))
|
||||
} else {
|
||||
try await Task.sleep(for: .milliseconds(100))
|
||||
}
|
||||
|
||||
func simulateProgress(for source: OWSProgressSource) async throws {
|
||||
for _ in 0..<(source.totalUnitCount / 2) {
|
||||
source.incrementCompletedUnitCount(by: 2)
|
||||
try await Task.sleep(for: .milliseconds(50))
|
||||
}
|
||||
|
||||
source.incrementCompletedUnitCount(by: source.totalUnitCount)
|
||||
}
|
||||
|
||||
try await simulateProgress(for: exportingBackupProgress)
|
||||
try await simulateProgress(for: uploadingBackupProgress)
|
||||
|
||||
try await Task.sleep(for: .milliseconds(500))
|
||||
|
||||
try Task.checkCancellation()
|
||||
markUploadedProgress.incrementCompletedUnitCount(by: PrimaryLinkNSyncProgressPhase.finishing.percentOfTotalProgress)
|
||||
|
||||
await modal.completeAndDismiss()
|
||||
}
|
||||
|
||||
@MainActor
|
||||
@available(iOS 17, *)
|
||||
func demoTask(
|
||||
modal: LinkAndSyncProgressModal,
|
||||
slowLinking: Bool
|
||||
) -> Task<Void, Never> {
|
||||
Task {
|
||||
do {
|
||||
try await setupDemoProgress(modal: modal, slowLinking: slowLinking)
|
||||
} catch {
|
||||
try? await Task.detached {
|
||||
try await Task.sleep(for: slowLinking ? .seconds(3) : .milliseconds(500))
|
||||
}.value
|
||||
modal.dismiss(animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 17, *)
|
||||
#Preview("Slow linking") {
|
||||
SheetPreviewViewController(animateFirstAppearance: true) {
|
||||
let modal = LinkAndSyncProgressModal()
|
||||
modal.linkNSyncTask = demoTask(modal: modal, slowLinking: true)
|
||||
return modal
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 17, *)
|
||||
#Preview("Fast linking") {
|
||||
SheetPreviewViewController(animateFirstAppearance: true) {
|
||||
let modal = LinkAndSyncProgressModal()
|
||||
modal.linkNSyncTask = demoTask(modal: modal, slowLinking: false)
|
||||
return modal
|
||||
}
|
||||
}
|
||||
|
||||
@ -282,30 +282,7 @@ extension LinkedDevicesViewModel: LinkDeviceViewControllerDelegate {
|
||||
|
||||
let progress = OWSProgress.createSink { progress in
|
||||
Task { @MainActor in
|
||||
let canBeCancelled: Bool
|
||||
if let label = progress.currentSourceLabel {
|
||||
canBeCancelled = label != PrimaryLinkNSyncProgressPhase.waitingForLinking.rawValue
|
||||
} else {
|
||||
canBeCancelled = false
|
||||
}
|
||||
|
||||
switch progress.currentSourceLabel {
|
||||
case
|
||||
PrimaryLinkNSyncProgressPhase.waitingForLinking.rawValue,
|
||||
PrimaryLinkNSyncProgressPhase.exportingBackup.rawValue:
|
||||
linkAndSyncProgressModal.viewModel.phase = .preparing
|
||||
case
|
||||
PrimaryLinkNSyncProgressPhase.uploadingBackup.rawValue,
|
||||
PrimaryLinkNSyncProgressPhase.finishing.rawValue:
|
||||
linkAndSyncProgressModal.viewModel.phase = .syncing
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
linkAndSyncProgressModal.viewModel.updateProgress(
|
||||
progress: progress.percentComplete,
|
||||
canBeCancelled: canBeCancelled
|
||||
)
|
||||
linkAndSyncProgressModal.viewModel.updateProgress(progress: progress)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4078,6 +4078,9 @@
|
||||
/* On a progress modal indicating the percent complete the sync process is. Embeds {{ formatted percentage }} */
|
||||
"LINK_NEW_DEVICE_SYNC_PROGRESS_PERCENT" = "%@ complete";
|
||||
|
||||
/* Title for a progress modal that would be indicating the sync progress while it's cancelling that sync */
|
||||
"LINK_NEW_DEVICE_SYNC_PROGRESS_TILE_CANCELLING" = "Cancelling…";
|
||||
|
||||
/* Title for a progress modal indicating the sync progress */
|
||||
"LINK_NEW_DEVICE_SYNC_PROGRESS_TITLE" = "Syncing Messages…";
|
||||
|
||||
|
||||
@ -57,10 +57,10 @@ public enum PrimaryLinkNSyncProgressPhase: String {
|
||||
case uploadingBackup
|
||||
case finishing
|
||||
|
||||
var percentOfTotalProgress: UInt64 {
|
||||
public var percentOfTotalProgress: UInt64 {
|
||||
return switch self {
|
||||
case .waitingForLinking: 30
|
||||
case .exportingBackup: 25
|
||||
case .waitingForLinking: 5
|
||||
case .exportingBackup: 50
|
||||
case .uploadingBackup: 40
|
||||
case .finishing: 5
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import UIKit
|
||||
|
||||
#if DEBUG
|
||||
public class SheetPreviewViewController: UIViewController {
|
||||
private let animateFirstAppearance: Bool
|
||||
private let presentAction: PresentAction
|
||||
|
||||
private enum PresentAction {
|
||||
@ -25,21 +26,31 @@ public class SheetPreviewViewController: UIViewController {
|
||||
}
|
||||
|
||||
public init(
|
||||
animateFirstAppearance: Bool = false,
|
||||
presentSheet: @escaping (
|
||||
_ viewController: SheetPreviewViewController,
|
||||
_ animated: Bool
|
||||
) -> Void
|
||||
) {
|
||||
self.animateFirstAppearance = animateFirstAppearance
|
||||
self.presentAction = .presentSheet(presentSheet)
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
public init(sheet: @escaping @autoclosure () -> UIViewController) {
|
||||
public init(
|
||||
animateFirstAppearance: Bool = false,
|
||||
sheet: @escaping @autoclosure () -> UIViewController
|
||||
) {
|
||||
self.animateFirstAppearance = animateFirstAppearance
|
||||
self.presentAction = .createSheet(sheet)
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
public init(createSheet: @escaping () -> UIViewController) {
|
||||
public init(
|
||||
animateFirstAppearance: Bool = false,
|
||||
createSheet: @escaping () -> UIViewController
|
||||
) {
|
||||
self.animateFirstAppearance = animateFirstAppearance
|
||||
self.presentAction = .createSheet(createSheet)
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
@ -60,7 +71,7 @@ public class SheetPreviewViewController: UIViewController {
|
||||
|
||||
public override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
self.presentAction.present(from: self, animated: false)
|
||||
self.presentAction.present(from: self, animated: animateFirstAppearance)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Loading…
Reference in New Issue
Block a user