Wait for initial profiles (#847)

Show progress view until initial local/remote profiles are fetched. May
visually improve later.
This commit is contained in:
Davide 2024-11-11 12:08:22 +01:00 committed by GitHub
parent 49d22e6e67
commit 30ccd58d4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 43 additions and 10 deletions

View File

@ -114,11 +114,13 @@ private struct ContainerModifier: ViewModifier {
func body(content: Content) -> some View {
debugChanges()
return content
.themeEmptyContent(if: !profileManager.hasProfiles, message: Strings.Views.Profiles.Folders.noProfiles)
.themeProgress(if: !profileManager.isReady)
.themeEmptyContent(if: profileManager.isReady && !profileManager.hasProfiles, message: Strings.Views.Profiles.Folders.noProfiles)
.searchable(text: $search)
.onChange(of: search) {
profileManager.search(byName: $0)
}
.themeAnimation(on: profileManager.isReady, category: .profiles)
.themeAnimation(on: profileManager.headers, category: .profiles)
}
}

View File

@ -29,12 +29,20 @@ import PassepartoutKit
@MainActor
public final class ProfileManager: ObservableObject {
private enum Observer: CaseIterable {
case local
case remote
}
public enum Event {
case save(Profile)
case remove([Profile.ID])
}
// MARK: Dependencies
private let repository: ProfileRepository
private let backupRepository: ProfileRepository?
@ -47,6 +55,8 @@ public final class ProfileManager: ObservableObject {
private let processor: ProfileProcessor?
// MARK: State
@Published
private var profiles: [Profile]
@ -56,10 +66,19 @@ public final class ProfileManager: ObservableObject {
}
}
private var allRemoteProfiles: [Profile.ID: Profile]
@Published
public private(set) var isRemoteImportingEnabled: Bool
private var allRemoteProfiles: [Profile.ID: Profile]
public var isReady: Bool {
waitingObservers.isEmpty
}
@Published
private var waitingObservers: Set<Observer>
// MARK: Publishers
public let didChange: PassthroughSubject<Event, Never>
@ -78,15 +97,17 @@ public final class ProfileManager: ObservableObject {
}
mirrorsRemoteRepository = false
processor = nil
self.profiles = []
allProfiles = profiles.reduce(into: [:]) {
$0[$1.id] = $1
}
allRemoteProfiles = [:]
isRemoteImportingEnabled = false
waitingObservers = []
didChange = PassthroughSubject()
searchSubject = CurrentValueSubject("")
isRemoteImportingEnabled = false
subscriptions = []
remoteSubscriptions = []
}
@ -104,13 +125,19 @@ public final class ProfileManager: ObservableObject {
self.remoteRepositoryBlock = remoteRepositoryBlock
self.mirrorsRemoteRepository = mirrorsRemoteRepository
self.processor = processor
profiles = []
allProfiles = [:]
allRemoteProfiles = [:]
isRemoteImportingEnabled = false
if remoteRepositoryBlock != nil {
waitingObservers = [.local, .remote]
} else {
waitingObservers = [.local]
}
didChange = PassthroughSubject()
searchSubject = CurrentValueSubject("")
isRemoteImportingEnabled = false
subscriptions = []
remoteSubscriptions = []
}
@ -323,10 +350,10 @@ extension ProfileManager {
self.isRemoteImportingEnabled = isRemoteImportingEnabled
remoteSubscriptions.removeAll()
remoteRepository = remoteRepositoryBlock(isRemoteImportingEnabled)
if let initialProfiles = try await remoteRepository?.fetchProfiles() {
reloadRemoteProfiles(initialProfiles, importing: false)
}
let newRepository = remoteRepositoryBlock(isRemoteImportingEnabled)
let initialProfiles = try await newRepository.fetchProfiles()
reloadRemoteProfiles(initialProfiles, importing: false)
remoteRepository = newRepository
remoteRepository?
.profilesPublisher
@ -345,7 +372,9 @@ private extension ProfileManager {
allProfiles = result.reduce(into: [:]) {
$0[$1.id] = $1
}
// objectWillChange implicit from updating profiles in didSet
if waitingObservers.contains(.local) {
waitingObservers.remove(.local)
}
// should not be imported at all, but you never know
if let processor {
@ -369,7 +398,9 @@ private extension ProfileManager {
allRemoteProfiles = result.reduce(into: [:]) {
$0[$1.id] = $1
}
objectWillChange.send()
if waitingObservers.contains(.remote) {
waitingObservers.remove(.remote)
}
guard importing else {
return