Categories
Hobbies

Two Thumbs Up for the Lynn Loop

This morning, Steph and I snuck away for an morning hike up in Lynn Headwaters Regional Park. We’re both pretty sure neither of us had been there before, but it was splendid.

Most of the loop is two parallel trails, one that follows the Lynn Creeks east bank. The other trail is still on the east side but is further east, at a higher elevation, and almost out of ear shot of the creek.

Apparently the usual way (more interesting way?) to do the loop is to start out on the trail further away from the creek. This trail starts with a fairly steep section, but is then fairly flat up to the intersection where you can return to the parking lot via the trail running beside the creek.

The full loop that we did was listed as 8 km and recommended allowing 4 hours. We thought it was more like 9 km, and we were back in a bit under three hours. (YMMV as they say)

If you don’t feel like doing the full 8km, there is a second link between the two trails about halfway along. (This will all be obvious when you see the map.)

There are also more challenging trails heading off in a few different directions, but we didn’t investigate them. This is also a great place for dog owners, or anyone else who enjoys meeting dogs on the trail. (Dogs on hiking trails always seem to be their happy place, I reckon.)

A stump that used to be a cedar tree
Categories
Software

A SwiftUI Picker Using an Swift Enum Part 2

In Part 1, we created a basic SwiftUI Picker that was bound to an enum variable that included n possible values. When users pick a value from the picker, the app’s data model is aware of this change and the UI updates to reflect the user’s selection.

In this post we are going to extend this basic functionality.

Display Text for Sort Types

Life would be better if we could customize the display text for each of the different sort types. To do this we will add a function to our enum.

    func displayText() -> String {
        switch self {
        case .name:
            return NSLocalizedString("Name", comment: "display text for sort type: name")
        case .height:
            return NSLocalizedString("Height", comment: "display text for sort type: height")
        case .averageScore:
            return NSLocalizedString("Average Score", comment: "display text for sort type: averageScore")
        }
    }

In order to use this new function, replace rawValue calls with displayText() calls.

struct ContentView: View {
    @ObservedObject var settings = Settings.shared
    var body: some View {
        VStack {
            Picker(selection: $settings.sortType, label: Text("Sort Type")) {
                ForEach(SortType.allCases, id: \.self) { sortType in
                    Text("\(sortType.displayText())")
                }
            }
            Text("sort type is: \(settings.sortType.displayText())")
        }
    }
}

Persist Preferred Sort Type

In this section we will add code to remember a user’s previously selected sort type. So if the user closes the app and relaunches it, their preferred sort type will still be selected. To do this, we will write the sortType to UserDefaults, and then read this value when the app launches. These changes will be made in the Settings class.

class Settings: ObservableObject {
    static let shared = Settings()
    @Published var sortType: SortType {
        didSet {
            UserDefaults.standard.setValue(sortType.rawValue, forKey: "sortType")
        }
    }
    init() {
        sortType = SortType(rawValue: UserDefaults.standard.string(forKey: "sortType") ?? "name") ?? .name
    }
}

I’m mildly pained by the need to include both a fallback value for the string read from UserDefaults and also a fallback value SortType(rawValue: ) return value. I guess this is just my way to demonstrate that I don’t like forced unwraps !

Add a New Sort Type

So what happens when end requirements change and now our data can also be sorted by…. let’s say Shoe Size? What needs to change in our example? In fact, very little needs to change. Basically just add the new enum case, and add a corresponding case to the displayText function

enum SortType: String, CaseIterable {
    case name
    case height
    case averageScore
    case shoeSize
    
    func displayText() -> String {
        switch self {
        case .name:
            return NSLocalizedString("Name", comment: "display text for sort type: name")
        case .height:
            return NSLocalizedString("Height", comment: "display text for sort type: height")
        case .averageScore:
            return NSLocalizedString("Average Score", comment: "display text for sort type: averageScore")
        case .shoeSize:
            return NSLocalizedString("Shoe Size", comment: "display text for sort type: shoeSize")
        }
    }
}
Categories
Software Uncategorized

A SwiftUI Picker Using an Swift Enum

These two items (the SwiftUI Picker and a Swift enum) work really well together. Some might say they go together as well as Peanut Butter and Banana.

Requirement: Your app needs a way for a user to choose how to sort their list items. Today list items can be sorted by Name, Height and Average Score. Some time in the future, the list of sort types is expected to grow.

Eventually we are going to need some UI for this, but let’s start be defining an enum to define the sort types. Our enum needs to conform to CaseIterable because we will need to call the allCases class method. I don’t think String is required, but is helpful in the initial stage before we polish the UI.

enum SortType: String, CaseIterable {
    case name
    case height
    case averageScore
}

And also a Settings model object to store our source of truth (ie sort type) We will access the Settings singleton via the shared static variable. Settings needs to conform to ObservableObject because the Picker will bind to the sortType property.

class Settings: ObservableObject {
    static let shared = Settings()
    @Published var sortType: SortType
    init() {
        sortType = .name
    }
}

For the UI, we will use the following Picker init

    public init(selection: Binding<SelectionValue>, label: Label, @ViewBuilder content: () -> Content)

The UI content view will start with something like this:

struct ContentView: View {
    @ObservedObject var settings = Settings.shared
    var body: some View {
        VStack {
            Picker(selection: $settings.sortType, label: Text("Sort Type")) {
                ForEach(SortType.allCases, id: \.self) { sortType in
                    Text("\(sortType.rawValue)")
                }
            }
            Text("sort type is: \(settings.sortType.rawValue)")
        }
    }
}

If we run this code, we’ll see a picker above a text label. When we pick a different value in the picker, the text label updates accordingly. Woot!

In Part 2, we will:

  1. Improve the UI by adding display names for the sort types
  2. Use UserDefaults to persist and recall the selected sort type
  3. Add another sort type
Categories
Uncategorized

Orca Overwhelms Otherwise Ordinary Outing

So yea, I saw an Orca this morning while biking along the sea wall in Stanley Park. It was quite a wonderful moment. I was clipping along with the wind at my back when I saw a black dorsal fin break the surface of the water under Lions Gate Bridge. Immediately and inelegantly, I stopped and got off my bike. Without consciously deciding, I just started walking back the direction I’d come from, to try and keep up with this whale. I was barely even aware of the fact that I was wearing my dorky bike shoes that are nearly impossible to walk in.

After walking alongside the whale for…. I don’t know how far exactly… maybe 60 metres, this lovely creature dove deeper and disappeared. A woman who had the presence of mind to record a video, said ‘He must be going to get some breakfast.’

As I clip clop walked back toward my bike, I was thinking about this happy connected feeling, and how it was strange that I felt so connected to this creature that I’m pretty sure had no idea I was appreciating it.

It was quite the magic moment.

On Orca just east of Lions Gate Bridge, heading into the inner harbour.

Update (9 June 2021): I reported my sighting to Ocean Wise Research, and they put a detailed post on Instagram.

Categories
Family

A Trip to Visit My Great Grandparents

I learned recently that my great grandparents were buried in a cemetery above West Vancouver (CapilanoView) But like any fact gleaned from the internet I felt I needed to see it to believe it.

So today, I struck out by bike, over Lions Gate Bridge to see if this was true. The ride was easier and shorter than I’d expected, although it felt like the last leg was straight up hill.

When I arrived at the cemetery, I was struck by feelings of calm and tranquility. I headed to the office, and was initially dismayed to see a ‘Office Closed due to Covid’ sign out front. After a moment of imagining myself searching through the many rows of headstones, I realized there were people in the office and the office phone number was included on the ‘Closed’ sign.

As I began fumbling to take out my phone, an employee came out of the office with a smile and said ‘Let me save you a phone call.’ I laughed a grateful laugh, and then told him ‘I think my great grandparents are buried here’. He took down their names and went back into the office. Before disappearing into the office, he asked me my name, and told me his was Clayton.

Moments later, he came back out with a clip board and said ‘Good news, your relatives are resting here.’

I liked his choice of word (resting) more than my crude choice. (buried)

He showed me the sheet on his clipboard that seemed to be a grid of random numbers. They weren’t in any discernible order, but he put his finger on the square marked ’25’.

He explained each square represented 4 (or was it 8?) plots and so we first needed to go 8 rows in. I didn’t really understand, but followed him as he started walking across the grass covered in orderly rows of head stones. I was momentarily mortified as I’d always thought you were not supposed to walk on graves. But if Clayton could do it so could I. Onwards!

After getting to the 8th row, Clayton again consulted his grid of random squares and appeared ready to start the next phase of the search. ‘Now it should be somewhere in this row…oh it’s right here.’

Sure enough right at our feet was the head stone of Thomas and Catherine R. Deas. It included the requisite dates, as well as their respective places of birth. Also, bookending the family name Deas, at the top of the stone were two Scottish thistles. I immediately thought of my grandfather Jack (their eldest son) and his favourite mock admonishment. ‘You’re being a bit of a thistle!’

At this point I wasn’t sure what to do. Clayton had left me. I first brushed a few pieces of grass from the headstone. I then ran through an internal slide show of the various pictures I’d seen of these two people. I then thought of all the wonderful people I knew who had descended from them. In the end, I felt grateful to be part of the tree of descendants of these two people.

Most of the Deas family and an unknown guest. From left to right, Catherine, Mystery Woman, Margaret, Catherine, Tom. I suspect this picture was taken by Jack Deas. I have no idea where this picture was taken. I further suspect it would have been taken in the early 1930’s.
The aforementioned headstone.
Irises @ Capilano View Cemetery
Categories
Software

Zentangle App

I’ve already mentioned my affinity for making zentangles however I often struggle with choosing which tangles to include. I always fear I’ll get in a rut and repeatedly pick the same tangles, and miss out on others that would feel good to draw. However the only thing worse than inadvertently ignoring an old favourite would be spending a lot of time and energy diligently making sure my picking was fair.

To this end, I want to build an app that will keep track of all the tangles, and which ones I’ve used most, and also allow me to pick some of my favourites. Also (not sure how useful this will be) it’d be nice to present a set of suggestions that include different types of patterns.

All this to say, I’ve been working on an app that uses the CloudKit framework to store both the immutable and the mutable tangle details. I’ve come across a few interesting technical challenges along the way. My plan is to create some posts to describe some of these challenges and things I’ve learned about CloudKit.

possible topics:

  • turning a swiftUI Image into a Navigation Link and it turns blue
  • connecting an enum to a swiftUI Picker
  • the value of being able to set recordId’s (and don’t forget to include the prefix)
  • challenges I’ve found when using iCloud dashboard (save needs to be clicked twice, adding index loses recent edits)
  • SettingsView, userDefaults
  • tabBar via model
  • navViews in a tabBar seem to reset (or get confused if you switch tabs and come back
Categories
Meta

The 4 Tendencies

This is a framework created by the author/researcher Gretchen Rubin that explores our relationships with commitments and expectations.

The four tendencies are:

  • Upholder
  • Obliger
  • Questioner
  • Rebel

So what are they mean? Things will become clearer with a summary of the tendencies.

Upholder

Upholders regularly meet both inner and outer expectations. For example, if you ask an upholder to do you a favour and they say they will, then they do. Also, if an upholder makes a new years resolution to give up carbs, they will mostly likely meet their goal.

Upholders do not like breaking the rules and tend to get defensive when blamed for something they don’t think is their fault.

Obliger

Obligers regularly meet outer expectations, but struggle to meet inner expectations. Similar to Upholders, they tend to keep the commitments they make to others, however expectations that don’t have external accountability are difficult for Obligers. A good hack for Obligers is to use external accountability to help meet an internal goals. For example if you want to exercise more, get a Fitbit and organize a group of friends to share how many steps you are getting each day.

Beware Obliger rebellion. This is what happens when and were the obliger finally snaps and says ‘to hell with these external obligations, I quit!’

Obliger is the most common tendency in the general population.

Questioner

Questioners meet internal and external obligations if they understand the reasoning behind the obligation. They tend not to succeed at arbitrary or inefficient tasks. Once you can answer their questions justifying why a particular course of action makes sense, they will be more likely to buy into it. Questioners are usually the people who will email you links to research/data to reinforce a topic you have recently discussed with them.

Ironically (this is anecdotal and from Gretchin’s observations) many questioners don’t like being questioned.

Rebels

Rebels struggle to meet both internal and external obligations. Telling them they have to do something won’t work. They can’t even get themselves to do things this way. Rebels are motivated by their sense of identity. So, for example when they see themselves as fit and health conscious they will exercise and eat healthily. However if you tell them they need to exercise at a specific time on a specific day, or bend their knees more, or not drink alcohol, you will be more likely to have them do the opposite.

Apparently Rebel is the least common tendency in the general population.


The purpose of the framework is not to judge the tendencies, but rather to understand your tendencies and the tendencies of the people around you. Instead of feeling bad when you or others don’t meet expectations, view it as an opportunity. It might be an opportunity to better understand your tendencies, or the tendencies of others.

Categories
Books

Kleptopia

I recently read Kleptopia by Tom Burgis. While being primarily about the corruption of the financial elite in Kazakhstan, it reached into Africa, London, Moscow, and ever so briefly into the United States including a surprisingly tiny Trump cameo appearance.

I was left with the impression that the safeguards in the financial world, to detect ill-gotten capital and prevent it from gaining legitimacy, are completely ineffective. Further any time a motivated crusader tries to provide effective oversight into corrupt practices, they are very quickly fired, or worse.

When I started reading this book, I wasn’t aware it was so focussed on Kazakhstan. It is a country I know very little about, however it has always been my metaphorical place I could go with my bike and just hide from the world. I’m not yet sure if learning about the corruption of its leaders has removed some of the shine this country has had for me.

Perhaps money can not buy happiness, but if you’re an oligarch, it appears to be able to buy pretty well everything else.

Categories
Hobbies

Flower Photos

I quite enjoy taking photos of flowers. In the beginning, I was using extension tubes on a film SLR, to take extreme closeups. (self reminder to digitize some of my early macro photos.)

These days, I’m much less ambitious, but I’m still always on the lookout for beautiful light falling on interesting colourful flowers. Irises are my favourite flowers, so I’m enjoying the fact that we are currently smack dab in the middle of Iris season.

Here are a couple of Iris photos I took today.

Siberian Irises in our backyard
Irises on the Arbutus Greenway
Irises beside the Arbutus Greenway
Categories
Family

My Great Grandmother

I’ve recently become interested in my great grandmother. Grandma Deas was my mom’s dad’s mother. Her and I only overlapped briefly on this planet, she died when I was three. I don’t have any memories of her, but according to my mom I spent a fair bit of time with Grandma Deas.

Starting out, I’m a bit overwhelmed by all the aspects of her life that I’d like to write about:

  • the general arc of her life
  • the house in West Vancouver where she lived for 40 plus years
  • her siblings
  • her various stages of motherhood

For now, I think I’m going to start with Hydrangeas. My mom has a thriving Hydrangea behind her house. She recently told me that it came from a cutting from Grandma Deas’ garden. I’ve made a couple of attempts at starting some cuttings, but so far no success. Perhaps third time’s the charm!

While I’ve been disappointed at my failed attempts at transplanting this hydrangea, I’m looking forward to the day when I’ll be able to look out in my backyard and see a plant that is a direct descendent something that was grown and tended by my great grandmother.

Insert catchy sign-off phrase here!

Catherine Deas, with Jack (on the left) and Jeannie (on her lap)