Follow up to event sorting

This is a short follow up article regarding the problems I described in this post.

I spent some time mocking this up in a Swift Playground on my iPad. First I added a new container object called EventContainer. This is an object that I can map my events to, while keeping a reference to the Core Data Event record.


class EventContainer {
    enum EventType {
        case startEvent
        case endEvent
    }
    var date: Date
    var eventType: EventType
    var event: Event
    
    init(date: Date, eventType: EventType, event: Event) {
        self.date = date
        self.eventType = eventType
        self.event = event
    }
}

I started by mapping the entire list of fetched events to an array of EventContainer

let startDateRows: [EventContainer] = fetchResults.compactMap ( { EventContainer(date: $0.dateStart!, eventType: .startEvent, event: $0 )} )

Next I filtered the fetched events to just those with end date data

let endDataData = fetchResults.filter({$0.includeEndDate == true && $0.dateEnd != nil})
let endDateRows: [EventContainer] = endDataData.compactMap( { EventContainer(date: $0.dateEnd!, eventType: .endEvent, event: $0 ) } )

Lastly I combined these arrays into one new array and sorted it based on the date property from the EventContainer

let fullList = startDateRows + endDateRows
fullList.sorted(by: {
    $0.date.compare($1.date) == .orderedDescending
})

Now I have a sorted array of EventContainers that I can use to build my list UI. Each list row can still access the Core Data Event entity to pass on to editing views. I think this is a reasonable approach, but I’m really just guessing. If you know a better way to do this please get in touch using the contact form or contact me on Twitter.

Thoughts on sorting events

Objective: 

I need a way to sort events in a list view that makes them easy to find. 

Constrains: 

  • All events have a start date
  • Some events have an end date
  • Some people may look for an event based on its start date, other may want to look for the end date. It could even vary depending on the type of data tracked on the timeline.

Options:

  1. Show only a list of events sorted by start date. Not at all what I want.
  2. Add a timeline setting to control sorting all related events. In this option an event would appear once in a list, either at the start date or end date position.
    1. Add a Bool to the Timeline entity to indicate preference to use end date if available.
    2. If an event has an end date, use it for the sorting
    3. Else, sort by start date
  3. Generate a list of all events with all start dates AND a list of events with end dates.
    1. Start date list – all events for a timeline
    2. End date list – only events with an end date for a timeline
    3. Combine these lists together and sort them. I don’t know how to sort both lists together like this…

I’d like to proceed with option three from the list above. Using this approach will place an event in the list twice if it has a start and end date. I can format the rows in the list with some indication of type such as single date, start date range, end date range. I can find some symbols to indicate what type the are. I could also place a toggle switch on the list layout to quickly show and hide the end date rows. I might even be able to make a cool animation for this.

I’m running into problems with how to actually pull this off. I wrote a simplified version of this in a playground but I can’t figure out how to sort the final resulting array, as the elements in the array have different sorting rules depending on rather they are a starting or ending record.

var fetchResults = [Event] // this is populated with an array of events

var endDateRows = fetchResults.filter({$0.includeEndDate == true && $0.dateEnd != nil})

var rows = fetchResults + endDateRows // combine the original array with the new array
// Now what do I sort by???

I’m considering some possible solutions but I’m not sure if these are a good way to proceed.

Solution A. 

Make a View Model that can fetch all of the events from Core Data, then process them into a new array of a different type. I could make a new containing object like this.

class EventContainer {
    var dateToSort: Date
    var eventRecord: Event // a reference to the Core Data record
}

My View Model could make two arrays of EventContainer, using map and filter calls to write the start and end dates to the dateToSort field, and writing the entire event to the eventRecord field. Then it could combine these two arrays into one and sort by the dateToSort field.

This approach seems reasonable but it puts a lot of processing into the hands of the View Model. Every time I navigate to a list I’ll have to run these processes. For individual Timelines that may not be a problem but when it comes to making list views that show events from all Timelines this could run into performance issues.

Solution B.

Modify the schema. Currently I have a simple Event entity in Core Data. In simplified form it looks like this.

class Event {
    var name: String
    var dateStart: Date
    var includeDateEnd: Bool = false
    var dateEnd: Date?
}

I could modify this by moving the date fields into a new table and making one to one relationships.

class Event {
    var name: String
    var dateStart: EventDate // Core Data To One relationship
    var includeDateEnd: Bool = false
    var dateEnd: EventDate //Core Data To One relationship
}

class EventDate {
    var date: Date
}

If I set this up correctly I could modify my fetch requests to record a list of EventDate records, then use the relationships to access the rest of the event data. This option would probably perform far better. It’s also a ton of work to update the app as it stands now. This might also complicate some of the calculations involving dates because the will be several database records involved instead of one Event record.

Out of these two options I’m leaning towards the first. This is not really an approach I’ve taken before and I think it could be valuable to try it. Coming from 8 years of FileMaker development, my first thought is to try to solve this like a database normalization problem, but I’ve learned the hard way before that Core Data is not a database. Sure, it uses a data and fills the same role as a database, but it’s an Object Modeling tool. It may be good to force myself to use a new type of thinking to solve this problem. If I run into performance issues then I can also take another crack at the second option. Either way, I need to spend some time thinking about this more before I decide how to proceed. Perhaps this is a good topics for Project Update.

The app I’ve been working on

The app I’ve been working on over the last few months is called Retrospective Timelines. I’m still trying to learn how to talk (and write) about the app in a way that makes sense and appeals to customers, but for now I’ll just write a bit about what it is and what it does. This will be a rambling post…

Retrospective Timelines is an app can track lists (Timelines) of personal milestones and important events. The main purpose of the app is to put these milestones and events into context. How long has it been since X Event? How long was I working on Project Y? What was happening in my life when I worked at Company Z?

An event can be a single point in time or a date range with a start date and end date. For example:

  • Jul 27, 2019: Decided to work with SwiftUI
  • June 25, 2015 – August 29, 2019: Employed at Company Z

I’ve been tracking this data for years in various spreadsheets and apps. I’ve never found one app that can hold all of it in a way that makes sense to me. Some examples of the type of data I want to track

  • Personal milestone – big picture things in my life such as my sobriety date
  • Addresses – when did I live at each address
  • Employers – when did I work for each company
  • Devices – when did I get a computer and how long did I keep using it

I’m still working on some views that will visualize this data. I’m going to start by making a graphical view for single timelines, but down the road I want to introduce the ability to combine timelines to cross reference data.

Database stuff

I’m using Core Data and CloudKit to build the backend of the app. It’s important to me that this data syncs to all of my iOS devices. The schema is simple, at least for now.

  • Timelines are lists that can have a name, icon, color, and multiple related Events.
  • Events are child records of a timeline and contain data such as event name, start date, optional end date, notes, etc.

User interface stuff

I started this project in UIKit and got pretty far before I decided to switch to SwiftUI instead. While SwiftUI is still new and buggy, there are just some things in UIKit that drive me nuts. I hope I never have to work with auto layout again.

For now the app is mostly using stock iOS controls with some styling added. I have a lot of work to do on each of the screens below, but this should give you an idea of what the app looks like for now.

Timeline views

The top of the navigation stack starts with Timeline List View. You can add, edit, reorder, and delete timelines. The four rows in the first section don’t do anything yet.

Event list and editing

I’m not really happy with the way that Events look right now, but I have data entry screens ready and working.

Event detail view

I’d like to replace this view with something more graphic. Perhaps some sort of card generated using the Timeline icon and color. The app calculates the time since a date in a readable format. For events with a date range it also calculates the curation of the range. Below you can see that I owned a MacBook Pro with an awful keyboard for 1 year, 10 months, and 7 days.

One week with SwiftUI

I just wrapped up a week of working with SwiftUI full time. It certainly has some rough edges and each new beta version brings a lot of changes. Here is a recap of what’s working for me and what I still need to figure out.

List views are really simple in SwiftUI. The first layout that loads in my app is a List view has two main sections. The first section has a few rows for some saved queries that I’ll implement later, the second section is dynamic data from Core Data. Xcode Beta 5 introduced some new property wrappers and environment variables for working with Core Data. You can read more about these additions here.

Data entry: I made some simple forms with a few fields and a custom control for picking colors. The only problem I’m having with data entry is actually with the modal presentation implementation of SwiftUI. I call the sheet modifier and pass it a view, but this has some issues with not loading data on repeated calls. I’m calling this modal sheet from the main list view for adding new records, and from a detail view for editing existing records. I have an issue where I can’t get the list view to update when I modify a record that is a few views away (List > Detail > Edit). I think this has something do do with the way that I’m loading the list with Core Data records, as there is nothing that is triggering a refresh when I save the modified record. I need to figure out a better way to setup a publisher with Core Data. A possible workaround for this is to implement record editing on the list rows, just like when a user swipes a table row to disclose an edit button. I just can’t seem to figure out how to do that yet. I may use the new ContextMenu instead if I can’t figure it out soon.

Button("Add List") {
    self.editModal = true
}
.padding(EdgeInsets(top: 0, leading: 0, bottom: 10, trailing: 20))
.accentColor(Color(Theme.shared.appMainTint))
                          
.sheet(isPresented: $editModal,
       onDismiss: {
        self.timelineEditModal = false
},
       content: {
        ListEditView()
            .environment(\.managedObjectContext, self.managedObjectContext)
})

Color Picker: The list based item in my app is composed of of a name, color, and icon. I wanted to try to mimic the new color picker in the new version of the Reminders app. While SwiftUI doesn’t have an alternative to the Collection View yet, I was able to get my color picker working by dynamically calculating a number of columns. I used Geometry Reader to get the width of the parent view, then just divided it by the size (including padding) that I wanted each color to take up. I passed that number to a child view that parses out a list of colors into rows and columns. I got the idea for the grid here. I’m planning on implementing something similar with the icon, using a subset of SF Symbols.

Dynamically sized color picker on iPad and iPhone.

I spent a large part of today refactoring a lot of my code into smaller views that are easier to reason about. Xcode can have a hard time handling complex views with lots of embedded views, so it can be helpful to break them into small components where possible.

Some issues I haven’t figured out:

  1. Master Detail by default – On iPad I get free Master Detail by default, but I’m not certain this is right for my app. I have not found a way to just fill the screen with my list view. There is also an annoying issue that iOS loads an empty detail view when in portrait mode. I can’t believe this is still the default behavior after years of iOS but it is… 
  2. Modal views seem to break when loaded from a List item. They will work correctly the first time, but when opened two or more times they do not load the data that is being passed to them. I was able to confirm that the data is being passed, but SwiftUI is not using it to update the views.
  3. iOS 13 has a new (old) style for rounding the corners of grouped tables/lists. I can’t find a way to do this yet. .listStyle(GroupedListStyle()) does not do the trick.
  4. List Edit Mode – I can toggle edit mode on, but have yet to figure out what to do next. I want to let users reorder rows, and I want to show an info button that will open a modal sheet for modifying a record.

SwiftUI is still new and can be frustrating at times but I think I can safely say that I’m going to make the production version of my app with it. In one week of work I caught up to the UIKit version of my app, which took nearly two months. Granted, a lot of that time was focused on planning and design, which benefited both versions. I think I’ll stick with SwiftUI just so I never have to deal with Auto Layout ever again.

Thinking about SwiftUI

Last week I decided to spend the weekend learning about SwiftUI. The weekend turned into an entire week but I was eventually able to learn everything I set out to learn. This course on Udemy was particularly helpful.

I’m going to take a long weekend to give myself time to reflect on what I have learned so far. One thing I want to think about is if I should use SwiftUI for my app. The app I’m working on is simple enough and SwiftUI can do almost everything I need. There are a few areas where I may have to drop out to UIKit but for the most part I think I can make it work. Importantly, I think I may be able to make a better user experience with SwiftUI than I can with UIKit. So many things in UIKit require more code and complexity and if I stay on that route it may be several months before my app meets the expectations that I have for it.

I guess I have a lot to think about this weekend.

Questions for myself about SwiftUI

This weekend I’m going to spend some time with SwiftUI. I tried to think of the most important questions that I want to answer. I have no idea how much progress I will make but if I come up with answers to these I’ll write about them.

  1. Can I connect a SwiftUI List to a Core Data FetchedResultsController?
    1. How do I set this up?
    2. Load data
    3. Edit data
    4. Delete data
  2. Does SwiftUI support advanced table features?
    1. Readable Size for cells
    2. Reorder controls
    3. Context actions
  3. How can I pass an object from a list view to a form view?
    1. Dependency injection?
  4. Can I make form views that do not save data until the done button is tapped? Pass back to the List view to save the changes. 
  5. Can I easily segue to UIKIT View Controllers? I need access to CollectionViews and Large TextViews, neither of which exist in SwiftUI.

Symbols and icons

I’m working on an icon picker for my app. The idea is to allow users to select a color and icon as a secondary way of identifying their lists. I have 10 colors picked out and the color picker is up and running, and I just wrapped up the first pass at the icon picker. For the time being I’m using SF Symbols. I went through the list of available symbols and found 101 that I think may be useful for my app. I may switch to a third-party icon pack before launch, but once I ship version 1.0 I need to make sure that I’m providing access to a consistent set of icons.

Light Mode version

Dark Mode version

Finding the right work

When I started Radical Application Development in 2015 one of my core goals for the business was to get into app development. At that time I had built a number of business systems and databases and I was eager to make a consumer product. I didn’t have time to pursue this goal full time but throughout 2016 I learned a lot about Swift and iOS development.

Time and again I ran into issues with the apps I wanted to make. Most of my ideas seemed like they would be achievable but ended up being far beyond my skills. I vastly underestimated how complex iOS development was. Each time I ran up against what I could do I gave up instead of pressing on. For example, I built a really awesome time tracking app using Core Data but when I tried to sync the data between devices I had nothing but issues. I lacked the skills and confidence to write my own syncing engine so I put the project on hold and never picked it back up.

Toward the end of 2016 my friend (and later podcast co-host) suggested that I check out SpriteKit. I had never even considered making a game, but I worked through some tutorials and decided to give it a shot. I spent most of November that year building a small game called Random Arrow. I released the app into the iOS app store in December 2016.

While Random Arrow never took off I gained something valuable from it. Working in SpriteKit and Swift on a simple game gave me the confidence I needed. Despite having no idea how game engines worked, and little “real” programming experience I was able to produce and ship something. Looking back at Random Arrow now I think it’s sort of a silly idea, but I’m still glad I made it. The confidence I gained from that project lead me to expand my consulting services beyond FileMaker. I starting making web applications in PHP–which has paid the bills ever sense–and I started learning Unity and Unreal Engine.

In early 2017 Dave and I decided to attend a local game development meetup. I wanted to share Random Arrow and was eager to meet some “real” game developers. While we were at the meetup Dave tried the Oculus Rift. He was pretty impressed by it and so was I. I didn’t actually try it at the meeting as I kind of nervous that I would look silly. I purchased a VR headset and a PC to use it with and turned my focus to VR development. I’m not going to go into details here but I spent the next two years with my attention focused on VR. You can get most of the story from VR Hermits.

As with the early iOS projects I got in way over my head with VR development. While I learned a ton about Unity, C#, 3D modeling, animation, and AI, I never shipped a consumer product. I kept my business running during this while with consulting work, mostly FileMaker or PHP projects, but I spent almost all of my time and energy on VR. At one point I was working so much that I actually did a lot of damage to my hands and wrists–damage which I’m still dealing with.

In spring of 2019 I finally decided to step away from VR development, at least where games are concerned. I know enough about game development now to know that I’ll never make a great game. I’m more than capable of using the tools and doing the development, but I lack the type of vision and creativity needed to make a great game. If I really wanted to I could make some bad games, but I’m not interested in doing that.

I’ve spent my time since then working on FileMaker, WordPress, and PHP consulting projects. I also started working on a new iOS app–something that will be the focus of this blog over the next few months. After nearly two years of trying to get good at something I’ll never be good at, I rediscovered that I am good at some things. I have a lot of skill when it comes to problem solving, user interface design, data modeling, and I’m going to spend my time and attention on those skills from now on.

I may revisit VR development someday, but not as a game developer. I’d love to create some productive applications in VR and AR, possibly even expanding on the projects I’m building now. Now that this little side quest into VR is over I’m making real progress on iOS development. Some of the concepts that baffled me in 2016 are easy to grasp now. There are also a lot of new APIs and advancements in iOS and Swift. I could even pick up my time tracking app again, as Apple had made new APIs for working with Core Data and CloudKit. For the first time in years I feel like I’m on the right track.

New Podcast: Project Update

In spring of 2018 Dave and I put VR Hermits on hiatus. Dave had some interesting work he wanted to focus on and I needed to spend some time on a few consulting projects. We had planned to resume in the fall but I think somewhere along the line Dave realized that Virtual Reality development was not what he wanted to do. It took me a lot longer to come to the same conclusion. Despite this, I kept pestering Dave to start recording again. I really missed the weekly calls where I could bounce my ideas off of him and hear about what he was working on.

A couple of months ago we finally decided to get pack to podcasting. We initially had no idea what the show would be about and even considered a return to Massively Unqualified Development. Regardless, we started recording some beta episodes in May of 2019 and we eventually settled on a new format. Those beta episodes may never be published, but the result is out new podcast called Project Update.

Joe and Dave discuss the progress of their respective projects, delving into the challenges, successes, and failures of being commercial software developers, periodic game developers, and general technology enthusiasts. Project Update is about our projects and lives, but we’ll also be bringing in other creators to talk about their projects and lives. In some ways we’re all dealing with the same issues, and in others we’re dealing with a problem space uniquely our own.

About the show, Project Update

In this new podcast we talk each week about our software development projects–among other things. Dave is building developer tools for the FileMaker community and I’m creating an iOS app in addition to my FileMaker and Web consulting work. As of the time of this post we have recorded four episodes, including an episode with our first guest.

Updating my website

Sometime last year allowed myself to get away from working on this site. I was never “complete” to begin with, but it got to the point where the content on this site was no longer relevant to the work I do. Today I decided to spend some time trying to clean things up.

I started with some new branding colors, the most important of which is HEX #5D28A7. I’m using that color heavily in an iOS app I’m working on and I plan to incorporate it into some additional products down the line. My site is powered by WordPress so the next step was to select a theme. I recently worked with Ascend on a consulting project and was impressed how customizable it was without having to dive into to the code. I installed the premium version and got to work. After selecting a layout, changing some colors, making a menu, and adjusting some settings I managed to make something that I like. I have a lot of work to do on it but I’m happy with the progress so far.

Something I had a lot of trouble with was writing a short blurb or description about myself or my business… I think for now I’ll let the site speak for itself. Perhaps I’ll add something later. I used to stress out about this sort of thing but I’ve been in business for four years now and I have never had a customer mention my website to me. It seems like all of my consulting business has been based on referrals from other customers.

Someday I’d like to get a logo made for the business and the website. I have no idea what that would look like or what I would want it to say about me.

1 3 4 5 6