Files
ios-mail/Modules/InboxCoreUI/Sources/LoadingBar/LoadingBar.swift
T
Mateusz Szklarek c84038174e Improve animation and API for loading bar (make usage easier)
Using timer and syncing it with animation cycles is not best idea, it's
super easy to get out of sync. I switched to completion from:

func withAnimation<Result>(
    _ animation: Animation? = .default,
    completionCriteria: AnimationCompletionCriteria = .logicallyComplete,
    _ body: () throws -> Result,
    completion: @escaping () -> Void
) rethrows -> Result

rely on that for animation cycle.
2025-11-28 11:46:42 +01:00

52 lines
1.8 KiB
Swift

// Copyright (c) 2025 Proton Technologies AG
//
// This file is part of Proton Mail.
//
// Proton Mail is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Proton Mail is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Proton Mail. If not, see https://www.gnu.org/licenses/.
import Combine
import SwiftUI
public struct LoadingBar<Content: View>: View {
private let isLoading: Bool
private let configuration: LoadingBarConfiguration
private let content: () -> Content
@StateObject private var stateStore: LoadingBarStateStore
public init(isLoading: Bool, @ViewBuilder content: @escaping () -> Content) {
let configuration = LoadingBarConfiguration()
self.isLoading = isLoading
self.configuration = configuration
self.content = content
_stateStore = .init(wrappedValue: .init(configuration: configuration))
}
// MARK: - View
public var body: some View {
ZStack(alignment: .top) {
content()
if stateStore.isLoading {
CyclingProgressBar(configuration: configuration) {
stateStore.handle(action: .cycleCompleted)
}
}
}
.onChange(of: isLoading, initial: true) { _, newValue in
let action: LoadingBarStateStore.Action = newValue ? .startLoading : .stopLoading
stateStore.handle(action: action)
}
}
}