Goal

I want to learn about the Coordinator pattern for navigation and implement it in Maitsu.

May 25, 2024

I previously spent several days trying to get a library called Stinsen working to no avail, so now I'm working with a library called SwiftUICoordinator.

Stinsen seemed more fully featured with better APIs, but SwiftUICoordinator seems simpler, so I'm optimistic that maybe I can dig into the guts if necessary. Stinsen, while nice, had some conflicts with more recent language developments that the maintainers hadn't really addressed and didn't seem to be active.

Stinsen: https://github.com/rundfunk47/stinsen

SwiftUICoordinator: https://github.com/erikdrobne/SwiftUICoordinator

Right now, I'm just trying to set the library up in the Maitsu project such that I can reliably render the views that I want. This is the getting-to-know-you phase where I'm just trying to figure out how things are supposed to be wired up. I'm not sure if the documentation is bad or if I'm just dumb, so this part is very frustrating. It's probably a little bit of both.

So far, it seems like there's three main structures to deal with: Coordinator, Action and Route. There's a lot of duplication in each, which I don't like very much.

The Coordinator handles all of the logic which represents a flow. It seems to consume both Action and Route. It uses Route to determine which view to render, and uses Action to determine what to do...? Action does things like appending routes and creating child coordinators.

There were also a few files that the tutorial in the repo's README didn't really mention that I had to make myself, and I only figured it out after reading through the example project.

Anyway, my app compiles with all of these, but the view I expect to render isn't rendering, so I need to dig more into what I'm doing wrong. It's hard because there's no tab bar example despite how common of a pattern that is, so I'm just flying off of some bullet points the maintainer wrote in an issue: https://github.com/erikdrobne/SwiftUICoordinator/issues/33

May 27, 2024

I got rendering working properly!

By implementing `start()` on the TabBarCoordinator, I can essentially instantiate the coordinator that I want. The TabBarCoordinator is still very incomplete, but I was able to get the TodayCoordinator working in a way that is promising.

The TabBarCoordinator shows TodayCoordinator from TabBarCoordinator.start for now. Then, TodayCoordinator.start calls show(route:) which is defined on the parent to just... show the view. I pass it the startRoute. I had to debug by printing out the error and learned that I had to make sure that TodayRoute wasn't returning nil as it isn't presenting a child coordinator.

Then, I was able to use TodayCoordinator.view(for:) to render two views. The first view represents the feed, the second view represents a detail. I was able to go back without the back button by making my own button that calls pop(animated:).

I was struggling a lot so I cheated and had Anthropic help me a bit. LLMs really aren't good at very specific, detailed tasks like this but sometimes I find that using them can at least give me a different way of thinking about a problem.

That being said, this is probably the wrong way to implement this... but it does render properly. Unfortunately, pushing a view makes the tab bar go away as well, which isn't what we want. I'm not sure how to render the tab bar _on top of_ the views, and it might not be possible without rewriting some of the library code.

I'm too tired to really think about it right now though, so I'll try again tomorrow.

May 28, 2024

I worked on this for a while tonight and made no progress. I’m not sure it’s possible with this library. I asked for help in the repo but being a very small repo, I’m not optimistic on getting a response—or at least one I’m happy with.

May 31, 2024

I tried to adapt the different example code and it didn't work. Currently, I'm trying to roll my own. It's also not working. I'm not really sure what to do!

So... it works?

I significantly dumbed down the list of requirements by not storing a NavigationPath for each tab. In reality this is fine, because you won't be able to switch tabs mid-stack anyway, as the tabs go away in favor of contextual actions.

Once I did that, I wasn't managing the interaction of the tab view struct and navigator class well, so the former couldn't tell when the latter was updating things.

Both tapping back and long pressing it to go back to the root view works, which is exciting. The pathing is definitely not correct, but at least this is a new problem!