Wait for initial profiles (#847)
Show progress view until initial local/remote profiles are fetched. May visually improve later.
This commit is contained in:
parent
49d22e6e67
commit
30ccd58d4a
|
@ -114,11 +114,13 @@ private struct ContainerModifier: ViewModifier {
|
||||||
func body(content: Content) -> some View {
|
func body(content: Content) -> some View {
|
||||||
debugChanges()
|
debugChanges()
|
||||||
return content
|
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)
|
.searchable(text: $search)
|
||||||
.onChange(of: search) {
|
.onChange(of: search) {
|
||||||
profileManager.search(byName: $0)
|
profileManager.search(byName: $0)
|
||||||
}
|
}
|
||||||
|
.themeAnimation(on: profileManager.isReady, category: .profiles)
|
||||||
.themeAnimation(on: profileManager.headers, category: .profiles)
|
.themeAnimation(on: profileManager.headers, category: .profiles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,20 @@ import PassepartoutKit
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
public final class ProfileManager: ObservableObject {
|
public final class ProfileManager: ObservableObject {
|
||||||
|
private enum Observer: CaseIterable {
|
||||||
|
case local
|
||||||
|
|
||||||
|
case remote
|
||||||
|
}
|
||||||
|
|
||||||
public enum Event {
|
public enum Event {
|
||||||
case save(Profile)
|
case save(Profile)
|
||||||
|
|
||||||
case remove([Profile.ID])
|
case remove([Profile.ID])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: Dependencies
|
||||||
|
|
||||||
private let repository: ProfileRepository
|
private let repository: ProfileRepository
|
||||||
|
|
||||||
private let backupRepository: ProfileRepository?
|
private let backupRepository: ProfileRepository?
|
||||||
|
@ -47,6 +55,8 @@ public final class ProfileManager: ObservableObject {
|
||||||
|
|
||||||
private let processor: ProfileProcessor?
|
private let processor: ProfileProcessor?
|
||||||
|
|
||||||
|
// MARK: State
|
||||||
|
|
||||||
@Published
|
@Published
|
||||||
private var profiles: [Profile]
|
private var profiles: [Profile]
|
||||||
|
|
||||||
|
@ -56,10 +66,19 @@ public final class ProfileManager: ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var allRemoteProfiles: [Profile.ID: Profile]
|
||||||
|
|
||||||
@Published
|
@Published
|
||||||
public private(set) var isRemoteImportingEnabled: Bool
|
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>
|
public let didChange: PassthroughSubject<Event, Never>
|
||||||
|
|
||||||
|
@ -78,15 +97,17 @@ public final class ProfileManager: ObservableObject {
|
||||||
}
|
}
|
||||||
mirrorsRemoteRepository = false
|
mirrorsRemoteRepository = false
|
||||||
processor = nil
|
processor = nil
|
||||||
|
|
||||||
self.profiles = []
|
self.profiles = []
|
||||||
allProfiles = profiles.reduce(into: [:]) {
|
allProfiles = profiles.reduce(into: [:]) {
|
||||||
$0[$1.id] = $1
|
$0[$1.id] = $1
|
||||||
}
|
}
|
||||||
allRemoteProfiles = [:]
|
allRemoteProfiles = [:]
|
||||||
|
isRemoteImportingEnabled = false
|
||||||
|
waitingObservers = []
|
||||||
|
|
||||||
didChange = PassthroughSubject()
|
didChange = PassthroughSubject()
|
||||||
searchSubject = CurrentValueSubject("")
|
searchSubject = CurrentValueSubject("")
|
||||||
isRemoteImportingEnabled = false
|
|
||||||
subscriptions = []
|
subscriptions = []
|
||||||
remoteSubscriptions = []
|
remoteSubscriptions = []
|
||||||
}
|
}
|
||||||
|
@ -104,13 +125,19 @@ public final class ProfileManager: ObservableObject {
|
||||||
self.remoteRepositoryBlock = remoteRepositoryBlock
|
self.remoteRepositoryBlock = remoteRepositoryBlock
|
||||||
self.mirrorsRemoteRepository = mirrorsRemoteRepository
|
self.mirrorsRemoteRepository = mirrorsRemoteRepository
|
||||||
self.processor = processor
|
self.processor = processor
|
||||||
|
|
||||||
profiles = []
|
profiles = []
|
||||||
allProfiles = [:]
|
allProfiles = [:]
|
||||||
allRemoteProfiles = [:]
|
allRemoteProfiles = [:]
|
||||||
|
isRemoteImportingEnabled = false
|
||||||
|
if remoteRepositoryBlock != nil {
|
||||||
|
waitingObservers = [.local, .remote]
|
||||||
|
} else {
|
||||||
|
waitingObservers = [.local]
|
||||||
|
}
|
||||||
|
|
||||||
didChange = PassthroughSubject()
|
didChange = PassthroughSubject()
|
||||||
searchSubject = CurrentValueSubject("")
|
searchSubject = CurrentValueSubject("")
|
||||||
isRemoteImportingEnabled = false
|
|
||||||
subscriptions = []
|
subscriptions = []
|
||||||
remoteSubscriptions = []
|
remoteSubscriptions = []
|
||||||
}
|
}
|
||||||
|
@ -323,10 +350,10 @@ extension ProfileManager {
|
||||||
self.isRemoteImportingEnabled = isRemoteImportingEnabled
|
self.isRemoteImportingEnabled = isRemoteImportingEnabled
|
||||||
remoteSubscriptions.removeAll()
|
remoteSubscriptions.removeAll()
|
||||||
|
|
||||||
remoteRepository = remoteRepositoryBlock(isRemoteImportingEnabled)
|
let newRepository = remoteRepositoryBlock(isRemoteImportingEnabled)
|
||||||
if let initialProfiles = try await remoteRepository?.fetchProfiles() {
|
let initialProfiles = try await newRepository.fetchProfiles()
|
||||||
reloadRemoteProfiles(initialProfiles, importing: false)
|
reloadRemoteProfiles(initialProfiles, importing: false)
|
||||||
}
|
remoteRepository = newRepository
|
||||||
|
|
||||||
remoteRepository?
|
remoteRepository?
|
||||||
.profilesPublisher
|
.profilesPublisher
|
||||||
|
@ -345,7 +372,9 @@ private extension ProfileManager {
|
||||||
allProfiles = result.reduce(into: [:]) {
|
allProfiles = result.reduce(into: [:]) {
|
||||||
$0[$1.id] = $1
|
$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
|
// should not be imported at all, but you never know
|
||||||
if let processor {
|
if let processor {
|
||||||
|
@ -369,7 +398,9 @@ private extension ProfileManager {
|
||||||
allRemoteProfiles = result.reduce(into: [:]) {
|
allRemoteProfiles = result.reduce(into: [:]) {
|
||||||
$0[$1.id] = $1
|
$0[$1.id] = $1
|
||||||
}
|
}
|
||||||
objectWillChange.send()
|
if waitingObservers.contains(.remote) {
|
||||||
|
waitingObservers.remove(.remote)
|
||||||
|
}
|
||||||
|
|
||||||
guard importing else {
|
guard importing else {
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in New Issue