SwiftUI – Simple ScrollViewReader use to get ScrollView to start at the top left.

Had occasion to use a SwiftUI ScrollView today and ran into the issue where the SwiftUI team decided to use one of the two most sensible defaults for initial presentation when the content is too large to fit in the container – center the content. This makes sense for images or maps, but not for much of anything else I am thinking of. Everything else seems to want top left (for left-to-right locales at least). Strange that something that a large percentage of people are going to want isn’t as easy to set as alignment or something, but so it goes.

Anyway, this gave me an opportunity to read up on ScrollViewReader which, combined with the .onAppear modifier, can get the initial presentation of a ScrollView to the top left like so many want/need it to be.

Putting the code here so I remember for next time and in case anyone else finds a bazillion Stack Overflow posts about how ScrollView is so hard to make display properly but no modern ScrollViewReader answers.

//
//  ContentView.swift
//  trashme
//

import SwiftUI

struct ContentView : View {
  var cellSize: CGFloat = 50
  var numRows: Int = 30
  var numCols: Int = 10
  var body : some View {

    VStack(alignment: .leading, spacing: 20) {
      ScrollViewReader() { proxy in
        ScrollView([.horizontal,.vertical], showsIndicators: true) {
          HStack( alignment: .top, spacing: 0) {
            VStack ( alignment: .leading, spacing: 0) {
              ForEach(0 ..< numRows, id: \.self) { row in
                Text("row " + row.description)
                  .frame( height: self.cellSize )
              }
            }
            ForEach(0 ..< self.numCols, id: \.self) { col in
              VStack( spacing: 0) {
                ForEach(0 ..< self.numRows, id: \.self) { row in
                  Text("\(row), \(col)")
                    .frame( width: self.cellSize, 
                            height: self.cellSize, 
                            alignment: .center)
                    .border(.blue)
                }
              }
            }
          }
          .id("root")  // since our ForEach views don't really 
          		// have true ids (\.self ~)  
          		// we make one for the outer HStack
          		// in the ScrollView
        }
        .onAppear {
          proxy.scrollTo("root", anchor: .topLeading)
        }
      }
    }
  }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

And here’s what it looks like in an iOS SwiftUI preview pane:

Twitter Advanced Search cheatsheet

Here so I can find it again 🙂

from:username
to:username       // to username
@username         // mentioning @username
keyword           // can be a #hashtag
-keyword
keyword OR keyword
min_retweets: x
min_faves: x
min_replies: x
filter:links
filter:images     // any image
filter:twimg      // twitter pic.twitter.com image
filter:video
filter:native_video
filter:periscope
filter:vine
filter:media      // image or video
filter:retweets
filter:safe
filter:verified   // verified users
-filter:____      // use with any of the above filter nouns to exclude
since:YYYY-MM-DD
until:YYYY-MM-DD
near:X within:10mi // (where X is a city name)
list:user/listname
url:apple          // has url containing "apple" anywhere in it
lang:languagecode  // en, da, cs, de, es, fr, it, ja, ko, nl, no, pt, ro, uk,…

19?! Wow…

Today we remember Nina who would have been 19 today.

Today we remember Nina who would have been 19 today. Impossible for me to really imagine her at 19 since she didn’t live to 4, but here she is on her 2nd birthday in her new dress from a friend of grandma’s in Kenya:

Nina 2nd birthday in her new birthday dress made by grandma’s friend in Kenya

I woke up this morning remembering what an intense day this was 19 years ago and the intense week that followed. We knew she had hydrocephalus and that she’d need a shunt in her brain to relieve the CSF pressure, but we didn’t know she’d be in the neonatal intensive care unit (NICU) for a week and we definitely didn’t expect all the other medical challenges she was born with. Nor did we expect the three other major surgeries she’d need in that first year (spinal cord surgery, intestinal surgery, eye surgery).

It wasn’t until a couple of months before this picture on her 2nd birthday that we finally got a diagnosis of Fanconi Anemia (FA), and some idea of what to expect for her as a result. Up until then it was a mystery to her doctors. Unfortunately, that expectation was likely a short life due to the type of FA she had. She had a pretty great year from this birthday through the next one. And then a month not so great due to brain surgery to remove a new tumor, but then a really great summer of family visitors, and good early fall before her decline and departure.

Outcomes are much better now for people with FA, but it’s still tough for many. These improvements are largely thanks to the efforts of researchers supported by the Fanconi Anemia Research Fund (FARF) and all the family and friends who’ve raised money for them to fund research over the years (including ours). Much of this research has shed light on, and improved treatments for, cancer as well as FA due to physiological pathways in common between the two and the higher determinism for FA.

Anyway, it’s been a long road, but we feel very lucky to have had Nina in our lives for part of it. Hug the ones you love.

Build Racing circa 2006

Found an old document where I’d written down some data on build timing and though it might be fun to share it.

Did some build racing of a fairly large codebase for a widely used macOS application from a company I was working for. Thought it might be fun to see the progression.

I loved the Quad G5 I bought for myself (employer wasn’t spending that kind of money) as an upgrade from the dual G5 I first bought. What an amazing jump in speed with the Quad G5! The intel based Macs were a significant jump in performance though and cheaper and sucked a lot less electricity (turning on the Quad G5 would trip my UPS about 50% of the time – it had a nasty initial surge).

—-

This is an ant build of {REDACTED}. Interestingly, the second build is faster
even though we do a clean before each build.. suggests our “clean” isn’t
really cleaning everything…? Maybe source file and system library caching in the file cache? Anyway, clearly not very carefully done, but amusing all the same. You can see why I didn’t work on my 17″ G4 laptop much – ouch!

Mac Mini 1.66 GHz core duo, 2G of RAM

1st build: 26 min 58 sec
2nd build: 25 min 6 sec

same machine but put source on an external firewire 400 drive:
remove objects directory (like 1st build):

3rd build: 30 min 4 sec
4th build: 27 min 10 sec

17″ Powerbook G4, 1.33 GHz, 1G RAM

1st build: 57 min 50 sec
2nd build: 55 min 26 sec

Dual G5 2Ghz, 1.5G RAM: (I think this hard drive must be fragmented or
something)

1st build: 22 minutes+
2nd build:

“Quad” G5 2.5GHz, 2.5G RAM:

1st build: 9 min 4 sec
2nd build: 8 min 16 sec

**WINNER *** (and it cost $800 less than the Quad G5!)
NEW Mac Pro (guessing: Dual 2.66GHz dual-core Xeon with 1G of RAM):

1st build: 8 min 4 sec
2nd build: 7 min 9 sec (+/-)

Making iOS 12 projects in Xcode 11

Some Xcode 11 iOS project templates aren’t iOS 12 compatible out of the box, but it’s relatively easy to make them work, here’s how:

  1. Select File > New… > Project…
  2. Select iOS and “Single View App” template, for example.
  3. Give the app a name, Swift, and be sure to select “Storyboard”, not “SwiftUI” (which needs some View and some requires iOS 13 according to the error message from Xcode), then select the “Next” to create the project.
  4. Select “AppDelegate.swift” and add @available(iOS 13, *) on the line above each of the func definitions in the “UISceneSession Lifecycle”
  5. Add an implementation of the window property inside the AppDelegate class like so: var window: UIWindow?
  6. Open “SceneDelegate.swift” and add @available(iOS 13, *) on the line above class SceneDelegate
  7. Select the project file in the Project Navigator to edit project settings and select the Project in the left pane of the editor
  8. In the “Info” tab, change the “iOS Deployment Target” at the top of the right pane to the appropriate 12.x deployment target for your project.
  9. Build and Run.  Good to go!

I’ve posted the two edited source files in a gist here

“We need more coders…”

In his excellent post Brandon Sneed responds to GM CEO’s “We need more coders” comment:  “Let’s talk about the real problem…”

I agree with his comments and would add:

Many large companies seem to waste an astonishing amount of developer productivity. So rather than saying they need more developers, these CEOs might start by fixing their current planning, processes, and methods of working.

Canceled projects/features, mismanaged and/or badly planned projects, developer time wasted in meetings they don’t need to be in or badly run meetings, stupid territorial struggles between upper managers, endless re-organizations, etc. etc.

These kind of things all makes developers less efficient which decreases their job satisfaction and makes them less likely to stick around.

Small companies do much much less of this because they simply can’t afford such waste.

One easy test:

If your company has meetings without clear agendas provided >24hrs in advance of the meeting, and shared post-meeting minutes, then you’re likely wasting developer time. A developer can’t know if they need to attend a meeting if they don’t know what it’s about (agenda) or if they feel like they have to be present to know what’s going on (lack of post-meeting minutes).

Attach an agenda to the meeting invite (>24hrs in advance!) and add only those developers (or anyone else for that matter) who you *must* have in the meeting to the TO/required list. Add anyone else who you want to inform about the meeting and what it’s about to the CC/optional list. Before you send the invite, do any pre-meeting work you can that will enable you to move developers (or anyone else) from the TO/required list to the CC/optional list; use email (don’t interrupt developers!) to ask those two questions you need to ask them before the meeting, for example.

See also @rands’ comment here

7DRL Challenge 2016: Arcana Command

My entry in the 2016 7DRL challenge is finished, a mere 1 minute before my time ran out! Arcana Command is based on

Download it here, or keep reading to find out more.

 

Arcana Commander Screenshot

Features:

  • Defend humanity from the mysterious Kyth and their demonic minions
  • Train four different classes of hero
  • Research advanced magic
  • Construct a mighty base of operations
  • Defeat the Kyth on their own turf to win the game
  • Simple controls make the game easy to play
  • Advanced ASCII graphics technology for a modern user experience

Controls:

  • Mouse only
  • Click to select units, click to move, click abilities at the bottom of the screen to use them, click to choose targets
  • Click to switch tabs in HQ
  • Click to select from menus
  • Essentially everything you can do in the game is done by clicking
  • Escape to quit

Known Bugs:

  • No in-game help is available.
  • Completely untested on any platforms other than Mac OS X.

Fix for spinning Pizza in Finder (10.9.5): remove dropbox contextual menus

Got  really tired for seeing the SPOD (Spinning Pizza of Death) in the Finder while trying to navigate in the folder hierarchy.  Happens off and on every 30 seconds or so.  Finally tracked it down to something dumb that Dropbox’s contextual menu code is doing (version 2.10.41).

It’s a bit of a pain to remove but here’s what you need to know:

/Library/DropboxHelperTools/

is where the nasty is.  Contents:

DropboxHelperInstaller
Dropbox_u###/
DropboxBundle.bundle
FinderLoadBundle
mach_inject_bundle_stub.bundle
dbfseventsd

The “###” is the user id number of the current OS X user (probably 501, 502, etc).

You need to move the “DropboxHelperInstaller” out of this folder or it’ll just keep re-installing the other stuff. I didn’t track down which of the two bundles are causing the problem, but it’s one of the “FinderLoadBundle”, or “DropboxBundle.bundle”. I removed both of these and the “mach_inject_bundle_stub.bundle” and that seems to solve the problem (after you quit Dropbox and relaunch the Finder).

Unfortunately Dropbox really wants to repair itself so it will keep prompting you every time it launches to put these back:

Screen Shot 2014-11-07 at 7.44.40 PM

Just select “Cancel” and it won’t be able to put these buggy files back.  Everything except the Finder integration seems to work fine and the Finder doesn’t keep dying inside dropbox contextual menu code for some indeterminate (but too long) amount of time.  I’ve told them on Twitter but they haven’t fixed this yet :-/

UPDATE:  As of Dropbox v2.10.52, and only when running on OS X 10.10.1, there’s a checkbox for “Enable Finder Integration” that might turn this stuff off more easily.  I haven’t tried it yet, but I’m hopeful.

7DRL 2014 – Day 7: In which everything is complete

Trinkets – the roguelike game I’ve spent the past week creating for the 7DRL competition – is finished, about 20 hours before the deadline! It’s a game about wandering an extra dimensional vault, acquiring trinkets and trying to get back home.

A build for mac is available here. Unfortunately, there’s no windows/linux build, but if you’re on one of those operating systems and want to play, the source is available here.

Screen Shot 2014-03-15 at 2.38.31 PM

… which turns out to be entirely justified.

My high score is 59 – can you beat it? If so, let me know in the comments below!

7DRL 2014 – Day 6: In which victory approaches at high velocity

One day remains, and I’m actually almost done. It would be nice to redo the map generator, and game balance can always be tweaked some more, but the plot and endgame are implemented, the boss-fights are done with basic AI, and there’s even a score feature. Shown below is the second of four boss fights:

You have a bad feeling about this level...
You have a bad feeling about this level…

… which turns out to be entirely justified.
… which turns out to be entirely justified.