Merge pull request #684 from kiwix/680-no-language-selected

Fix language selection initial state UI problems
This commit is contained in:
Kelson 2024-03-06 06:54:50 +01:00 committed by GitHub
commit 7989cab2ac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 52 additions and 23 deletions

View File

@ -34,7 +34,6 @@ extension Defaults.Keys {
static let libraryAutoRefresh = Key<Bool>("libraryAutoRefresh", default: true)
static let libraryUsingOldISOLangCodes = Key<Bool>("libraryUsingOldISOLangCodes", default: true)
static let libraryLastRefresh = Key<Date?>("libraryLastRefresh")
static let libraryLastRefreshTime = Key<Date?>("libraryLastRefreshTime")
static let isFirstLaunch = Key<Bool>("isFirstLaunch", default: true)
static let downloadUsingCellular = Key<Bool>("downloadUsingCellular", default: false)

View File

@ -11,16 +11,23 @@ import os
import Defaults
public enum LibraryState {
case initial
case inProgress
case complete
}
public class LibraryViewModel: ObservableObject {
@Published var selectedZimFile: ZimFile?
@MainActor @Published public private(set) var error: Error?
@MainActor @Published public private(set) var isInProgress = false
@MainActor @Published public private(set) var state: LibraryState
private let urlSession: URLSession
private let context: NSManagedObjectContext
private var insertionCount = 0
private var deletionCount = 0
@MainActor
public init(urlSession: URLSession? = nil) {
self.urlSession = urlSession ?? URLSession.shared
@ -28,6 +35,11 @@ public class LibraryViewModel: ObservableObject {
context.persistentStoreCoordinator = Database.shared.container.persistentStoreCoordinator
context.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
context.undoManager = nil
if Defaults[.libraryLastRefresh] == nil {
state = .initial
} else {
state = .complete
}
}
public func start(isUserInitiated: Bool) {
@ -36,19 +48,22 @@ public class LibraryViewModel: ObservableObject {
@MainActor
public func start(isUserInitiated: Bool) async {
guard state != .inProgress else { return }
let oldState = state
do {
guard !isInProgress else { return }
isInProgress = true
defer { isInProgress = false }
// decide if refresh should proceed
let lastRefresh: Date? = Defaults[.libraryLastRefresh]
let hasAutoRefresh: Bool = Defaults[.libraryAutoRefresh]
let isStale = (lastRefresh?.timeIntervalSinceNow ?? -3600) <= -3600
guard isUserInitiated || (hasAutoRefresh && isStale) else { return }
state = .inProgress
// refresh library
guard let data = try await fetchData() else { return }
guard let data = try await fetchData() else {
state = oldState
return
}
let parser = try await parse(data: data)
// delete all old ISO Lang Code entries if needed, by passing in an empty parser
if Defaults[.libraryUsingOldISOLangCodes] {
@ -68,12 +83,14 @@ public class LibraryViewModel: ObservableObject {
// reset error
error = nil
state = .complete
// logging
os_log("Refresh finished -- addition: %d, deletion: %d, total: %d",
log: Log.OPDS, type: .default, insertionCount, deletionCount, parser.zimFileIDs.count)
} catch {
self.error = error
state = oldState
}
}

View File

@ -69,7 +69,7 @@ struct ZimFilesNew: View {
}
#endif
ToolbarItem {
if viewModel.isInProgress {
if viewModel.state == .inProgress {
ProgressView()
#if os(macOS)
.scaleEffect(0.5)

View File

@ -14,9 +14,10 @@ import Defaults
#if os(macOS)
struct LanguageSelector: View {
@Default(.libraryLanguageCodes) private var selected
@EnvironmentObject private var library: LibraryViewModel
@State private var languages = [Language]()
@State private var sortOrder = [KeyPathComparator(\Language.count, order: .reverse)]
var body: some View {
Table(languages, sortOrder: $sortOrder) {
TableColumn("") { language in
@ -35,9 +36,20 @@ struct LanguageSelector: View {
Text(language.count.formatted())
}
}
.opacity( library.state == .complete ? 1.0 : 0.3)
.tableStyle(.bordered(alternatesRowBackgrounds: true))
.onChange(of: sortOrder) { languages.sort(using: $0) }
.task {
.onChange(of: library.state) { state in
guard state != .inProgress else { return }
reloadLanguages()
}
.onAppear {
reloadLanguages()
}
}
private func reloadLanguages() {
Task {
languages = await Languages.fetch()
languages.sort(using: sortOrder)
}
@ -48,7 +60,7 @@ struct LanguageSelector: View {
@Default(.libraryLanguageSortingMode) private var sortingMode
@State private var showing = [Language]()
@State private var hiding = [Language]()
var body: some View {
List {
Section {

View File

@ -57,12 +57,12 @@ struct LibrarySettings: View {
var body: some View {
VStack(spacing: 16) {
SettingSection(name: "library_settings.catalog.title".localized) {
SettingSection(name: "library_settings.catalog.title".localized, alignment: .top) {
HStack(spacing: 6) {
Button("library_settings.button.refresh_now".localized) {
library.start(isUserInitiated: true)
}.disabled(library.isInProgress)
if library.isInProgress {
}.disabled(library.state == .inProgress)
if library.state == .inProgress {
ProgressView().progressViewStyle(.circular).scaleEffect(0.5).frame(height: 1)
}
Spacer()
@ -173,7 +173,7 @@ struct Settings: View {
LanguageSelector()
} label: {
SelectedLanaguageLabel()
}
}.disabled(library.state != .complete)
Toggle("library_settings.toggle.cellular".localized, isOn: $downloadUsingCellular)
} header: {
Text("library_settings.tab.library.title".localized)
@ -189,7 +189,7 @@ struct Settings: View {
Spacer()
LibraryLastRefreshTime().foregroundColor(.secondary)
}
if library.isInProgress {
if library.state == .inProgress {
HStack {
Text("catalog_settings.refreshing.text".localized).foregroundColor(.secondary)
Spacer()

View File

@ -44,8 +44,8 @@ struct Welcome: View {
}
.padding()
.ignoresSafeArea()
.onChange(of: library.isInProgress) { isInProgress in
guard !isInProgress else { return }
.onChange(of: library.state) { state in
guard state != .inProgress else { return }
#if os(macOS)
navigation.currentItem = .categories
#elseif os(iOS)
@ -70,7 +70,8 @@ struct Welcome: View {
GridSection(title: "welcome.main_page.title".localized) {
ForEach(zimFiles) { zimFile in
Button {
guard let url = ZimFileService.shared.getMainPageURL(zimFileID: zimFile.fileID) else { return }
guard let url = ZimFileService.shared
.getMainPageURL(zimFileID: zimFile.fileID) else { return }
browser.load(url: url)
} label: {
ZimFileCell(zimFile, prominent: .name)
@ -121,7 +122,7 @@ struct Welcome: View {
} label: {
HStack {
Spacer()
if library.isInProgress {
if library.state == .inProgress {
#if os(macOS)
Text("welcome.button.status.fetching.text".localized)
#elseif os(iOS)
@ -135,7 +136,7 @@ struct Welcome: View {
}
Spacer()
}.padding(6)
}.disabled(library.isInProgress)
}.disabled(library.state == .inProgress)
}
.font(.subheadline)
.buttonStyle(.bordered)