mirror of
https://github.com/kiwix/kiwix-apple.git
synced 2025-09-25 12:56:13 -04:00
Merge pull request #684 from kiwix/680-no-language-selected
Fix language selection initial state UI problems
This commit is contained in:
commit
7989cab2ac
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ struct ZimFilesNew: View {
|
||||
}
|
||||
#endif
|
||||
ToolbarItem {
|
||||
if viewModel.isInProgress {
|
||||
if viewModel.state == .inProgress {
|
||||
ProgressView()
|
||||
#if os(macOS)
|
||||
.scaleEffect(0.5)
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user