SwiftData / SwiftUI Combo Frustrations

The last few posts have been about my re-write of my personal application to address greeting cards.

This has been a very frustrating effort as I’ve tried to restructure the app’s UI to better adhere to Apple’s design principles in order to allow the user edit both a recipient’s Address and to add their own event types. This has required me to do the following things:

  • Restructure the database itself, going from only two tables:
    • A recipient of a card
    • An instance of a card that a recipient has been sent
  • To four tables:
    • An Event Type, i.e. Christmas, Birthday, etc.
    • A recipient, name and address
    • A gallery of greeting cards
      • With pictures, event types, descriptive name, and a URL where you can find it
    • An instance of a specific card for that a recipient has been sent

This approach would allow me to dramatically reduce the size of the database by only having one image for each Greeting Card. And it would also allow me to dramatically increase load speed, since loading the image would only occur as an AsyncImage (and could be cached, since the same image would be used by multiple instances).

Apple is pushing people to start using NavigationStack, with a navigationPath so that you can push to any screen and pop back thru the stack. However, I would like to structure the app with a NavigationSplitView since it is designed for iPad and iPhone. The basic idea would be to allow the user to start with picking do they want to add a recipient, an eventType, or a card to the Card Gallery. Those would each be a separate NavigationStack so you would get a list of all the existing items (events, recipients, or greeting cards) in column two, and then a detailed listing of all the specific cards that match it in the third column. Simple right?

The third column would be the “Detailed” view, so for a recipient, you’d get a LazyVGrid with all the Cards that they have received, sorted by date. For an EventType, you’d get a LazyVGrid with all the Cards for all recipients with that specific event sorted by date. And finally for the Card Gallery, you’d get all the cards by type.

While there is still a lot of UX improvements I can do here, the basic structure here is done using the original approach.

As I try and figure out the three column view with the NavigationSplitView, I am wondering if I can still use the NavigationPath. Also, since my SplitView starts with a list of the enumeration states (and I’ve tried both “Buttons” and just “Lists”, I can’t seem to highlight the selected item, so now I have to a title in the center column. It’s a little bit better. But for some reason you see that the “Cards Sent” in the by recipient view, is showing up in Black. It blinks for a second in the right color.

The other feature I have added was a custom picker for the image’s in the gallery by event type.

As you can see the images show up at the bottom of the window for some reason. it is very frustrating, as I am trying to use a SwiftUI Form to give the nice gray background and grouping of various sections of information.

VStack {
   Form {
     Section("Card Information") {
        Picker("Select type", selection: $selectedEvent) {
            Text("Unknown Event").tag(Optional<EventType>.none)
            if events.isEmpty == false {
                 Divider()
                 ForEach(events) { event in
                    Text(event.eventName)
                       .tag(Optional(event))
                 }
             }
         }           
         DatePicker(
            "Event Date",
            selection: $cardDate,
            displayedComponents: [.date])
         }
      }
      .padding(.bottom, 5)
      if selectedEvent != nil {
         GreetingCardsPicker(eventType: selectedEvent ?? EventType(eventName: "Unknown"), selectedGreetingCard: $selectedGreetgingCard)
      }
   }
}

If I place the GreetingCardsPicker in a Section it collapses to a single line (completely unusable). So for now, I am stuck with the cards all showing up at the bottom. Hopefully I can figure this one. At the same time, right now, the “GreetingCardsPicker” is not returning the selected item. As a matter of fact the .onTapGesture code doesn’t even execute.

Hope to make more progress soon.