I was just starting to learn Swift when SwiftUI came out, and I've spent most of the last year working on the backend of my app and not touching the interface elements. So this is really my first time working in SwiftUI aside from doing some of the "my first app" type tutorials, which didn't leave me quite prepared to figure out how to accomplish what I'm trying to do, especially since I'm also incorporating a couple other concepts I'm not terribly familiar with yet.
I'm building an app for audiobook library management. My primary view should be the list of books. But if the list of books is empty, it should be a view prompting the user to import some files. That part I've pretty much got worked out, except for one question.
struct FileImportView: View {
@State var showImporter: Bool = false
@State var importProgress: Progress
var body: some View {
Button(...)
.fileImporter(isPresented: $showImporter,
allowedContentTypes: [ ... ],
allowsMultipleSelection: true,
onCompletion: { result in
if let urls = try? result.get() {
importProgress = ImportManager(urls).progress
}
})
}
}
I'm still struggling with when to use @Binding
and when to use @State
, and this is my first time using Progress
as well. If I want this view to set the importProgress
to my other views, I would use @State
here, correct? And the receiving view would use @Binding
? Or have I gotten those mixed up (again)? Is it even appropriate to use that here, or should I be using another kind of variable?
Sorry, that ended up being more than one question.
Moving on.
In my ContentView
, once a book is added to the database, I want to show the list of books, and for the list to update each time a new book is added. If an import is in progress still, I want a progress indicator, but I'd like it to be somewhere relatively inconspicuous. A corner of a bottom or top bar would be my preference, but I'm running into the issue of NavigationView
not looking right in larger display devices. (This app is going to be targetted at iPad
and MacOS
users, because let's face it, few people are going to be curating their whole library on a phone.) So I'm not sure I can actually put anything in the navigation bar, which leaves me with putting the ProgressView
in a ZStack
and tucking it in a corner somewhere, overlaying the BookListView
But ZStack
and GeometryReader
are another new concept I'm struggling to get the hang of, especially since I'm not sure I'm doing the rest of it right in the first place.
struct ContentView: View {
@EnvironmentObject var library: LibraryObject
@Binding var importProgress: Progress
var body: some View {
if library.database.books.isEmpty {
FileImportView(importProgress: importProgress)
} else {
ZStack {
if importProgress.fractionCompleted < 100 {
ProgressView("Import in Progress...", value: importProgress.fractionCompleted, total: 100)
BookListView(library: _library)
} else {
BookListView(library: _library)
}
}
}
}
}
My final question: I'm not sure I understand what to do with this:
@main
struct AudiobookLibrarianApp: App {
var database = LibraryObject(database: LibraryCache.default.database)
var body: some Scene {
WindowGroup {
ContentView(importProgress: $importProgress).environmentObject(database)
}
}
}
I'm not sure how I should capture the importProgress
variable for use here. SwiftUI doesn't seem to want me to use @State
and I'm not sure what else I should be using.
Thank you.