Categories
Uncategorized

The code for Tampa iOS Meetup’s “Pomodoro Timer” exercise

Last night, the Tampa iOS Meetup folks gathered to learn how to code an iPhone/iPad Pomodoro Timer in Swift, a timer that helps you use the Pomodoro technique, an ingeniously simple lifehack that many people have used to help them power past distraction, stay focused on their work, and be incredibly productive.

Pomodoro is the Italian word for “tomato” and refers to the tomato-shaped kitchen timer that the technique’s inventor, Francesco Cirillo, used in developing the technique. The technique itself is pretty simple:

  • Pick a task that you want to tackle.
  • Set a timer for 25 minutes. Because Cirillo used a tomato-shaped kitchen timer, he called this 25-minute interval a “pomodoro”.
  • Work on the task — and nothing but that task — until the timer rings.
  • After the timer rings, put a checkmark on a piece of paper.
  • If you have fewer than four checkmarks, take a five-minute break, then start another pomodoro.
  • If you have four checkmarks, take a longer break — typically 15 to 30 minutes — and reset your checkmark count back to zero. Then start a new pomodoro.

By breaking a large task or series of tasks into short, focused intervals, the Pomodoro Technique aims to have your brain to work in short sprints — which it’s evolved to do — and take regular breaks to help it recharge. The intended result is to ensure consistent productivity, motivation, and creativity.

The app we built last night is a timer for use with the Pomodoro technique that keeps track of pomodori (that’s the plural of pomodoro) and breaks.

The heart of the app

The key to writing an app like the Pomodoro timer is the Timer class. It can be used to instantiate timer objects, which:

  • Wait until a certain interval of time has passed, and when that happens,
  • Sends a message to a target object.

In the Pomodoro Timer app, we create a Timer object that fires every second. When it fires, it calls a method that:

  • Reduces the count of time remaining by one second
  • Updates a “time remaining” display
  • Checks to see if time has run out on the current interval and takes the appropriate actions

Our app has an instance variable called myTimer. To start a timer, we use this method:

myTimer = Timer.scheduledTimer(timeInterval: 1,
                               target: self,
                               selector: #selector(timerTick),
                               userInfo: nil,
                               repeats: true)

Here’s a quick explanation of the scheduledTimer method’s parameters:

  • timeInterval: The number of seconds to wait before the timer fires. We want the timer to fire every second, so we set this parameter to 1.
  • target: The object to send the message to when the timer fires. We want the message to be sent to the same object that this call lives in, so we set this parameter to self.
  • selector: The message we want to send to the target object when the timer fires. We want to call the timerTick method every time the timer fires, so we do this by setting the parameter to #selector(timerTick), which says “send a call to the timerTick method”.
  • userInfo: This is used to pass any additional information that might be needed when the timer fires. In this case, we don’t need any such additional information, so we set this parameter to nil.
  • repeats: If true, the timer is a repeating timer that fires once every timeInterval seconds. If false, the timer waits timeInterval seconds, fires once, and then stops. We want the timer in our app to be a repeating one, so we set this parameter to true.

Stopping a timer is pretty simple. If the timer instance variable is myTimer, here’s how you stop it:

myTimer.invalidate()

A couple of handy utility methods

The app keeps track of time by counting down from a given total number of seconds:

  • During a pomodoro, it starts a countdown timer of 25 minutes, which is 1500 seconds.
  • During a rest break, it starts a countdown timer of 5 minutes, which is 300 seconds.

This works just fine for internal code, but people don’t tell time in terms of hundreds of seconds, but in terms of hours, minutes, and seconds (we have the Babylonians to thank for this). So we use a method that converts a given number of seconds into minutes and seconds…

// Given a number of seconds, return it as (minutes, seconds).
func minutesAndSeconds(from seconds: Int) -> (Int, Int) {
  return (seconds / 60, seconds % 60)
}

We also need a method to display seconds (and optionally, minutes) as a two-digit number with a leading zero. That way, the app displays “one minute and three seconds” as 01:03 (or 1:03) and not 1:3. Here’s the method:

// Given a number, return it as a string of 2 digits,
// with a leading zero if necessary.
func formatMinuteOrSecond(_ number: Int) -> String {
  return String(format: "%02d", number)
}

…and we use both these methods like so:

let (minutes, seconds) = minutesAndSeconds(from: timeRemaining)
minutesLabel.text = formatMinuteOrSecond(minutes)
secondsLabel.text = formatMinuteOrSecond(seconds)

The code

This was the simplest app we’ll cover this year, and the code for the entire app lives in the view controller. Here it is:

import UIKit

class ViewController: UIViewController {

  // This app is a timer for use with the Pomodoro Technique.
  // (See https://en.wikipedia.org/wiki/Pomodoro_Technique for details.)

  // Intervals
  // ---------
  // The Pomodoro technique has two types of time intervals:
  //   1. The pomodoro, where you focus on a specific task for 25 minutes, and
  //   2. A rest break of 5 minutes.
  // These variables make it possible to tell what interval we're currently on,
  // and whether it’s a pomodoro or a rest break.

  enum IntervalType {
    case Pomodoro
    case RestBreak
  }
  let intervals: [IntervalType] = [.Pomodoro,
                                   .RestBreak,
                                   .Pomodoro,
                                   .RestBreak,
                                   .Pomodoro,
                                   .RestBreak,
                                   .Pomodoro]
  var currentInterval = 0

  // Interval lengths and time remaining
  // -----------------------------------
  // For testing purposes, I made the lengths of the pomodoro and rest break intervals
  // 20 seconds and 5 seconds, respectively. For the actual versions, use the
  // commented lengths.
  let pomodoroIntervalTime = 20 // Actual length: 25 * 60
  let restBreakIntervalTime = 5 // Actual length:  5 * 60
  var timeRemaining = 0

  // Timer
  // -----
  // The heart of the app.
  var myTimer = Timer()

  // UI controls
  // -----------
  @IBOutlet weak var minutesLabel: UILabel!
  @IBOutlet weak var secondsLabel: UILabel!
  @IBOutlet weak var intervalLabel: UILabel!
  @IBOutlet var tomatoIcons: [UIImageView]!
  @IBOutlet weak var startPauseButton: UIButton!
  @IBOutlet weak var resetButton: UIButton!


  override func viewDidLoad() {
    super.viewDidLoad()

    resetToBeginning()
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }

  func resetToBeginning() {
    currentInterval = 0
    setTomatoMeter(to: 1)
    intervalLabel.text = "Ready to work!"
    startPauseButton.setTitle("Start", for: .normal)
    resetButton.isEnabled = false
    timeRemaining = pomodoroIntervalTime
    updateDisplay()
  }

  @IBAction func startPauseButtonPressed(_ sender: UIButton) {
    if myTimer.isValid {
      // If the timer is currently running:
      //   1. Change the button’s title to “Resume”
      //   2. Enable the rest button
      //   3. Pause the timer
      startPauseButton.setTitle("Resume", for: .normal)
      resetButton.isEnabled = true
      pauseTimer()
    } else {
      // If the timer is currently stopped:
      //   1. Change the button’s title to “Pause”
      //   2. Disable the Reset button
      startPauseButton.setTitle("Pause", for: .normal)
      resetButton.isEnabled = false
      if currentInterval == 0 && timeRemaining == pomodoroIntervalTime {
        // If we’re currently at the very start of a set of pomodori (plural for pomodoro),
        // begin the cycle of intervals.
        startNextInterval()
      } else {
        // If we're in the middle of a set of pomodori,
        // simply resume the timer.
        startTimer()
      }
    }
  }

  @IBAction func resetButtonPressed(_ sender: UIButton) {
    if myTimer.isValid {
      // The timer shouldn’t be running if the Reset button is enabled,
      // but let’s make sure it’s stopped, just in case.
      myTimer.invalidate()
    }
    resetToBeginning()
  }

  func startNextInterval() {
    if currentInterval < intervals.count {
      // If we haven’t done all the intervals yet,
      // do the next one.
      if intervals[currentInterval] == .Pomodoro {
        // Pomodoro interval
        timeRemaining = pomodoroIntervalTime
        intervalLabel.text = "Pomodoro!"
        let tomatoes = (currentInterval + 2) / 2
        print("\(tomatoes) tomatoes")
        setTomatoMeter(to: tomatoes)
      } else {
        // Rest break interval
        timeRemaining = restBreakIntervalTime
        intervalLabel.text = "Rest break."
      }
      updateDisplay()
      startTimer()
      currentInterval += 1
    } else {
      // If we’ve done all the intervals,
      // reset the app.
      resetToBeginning()
    }
  }

  func updateDisplay() {
    let (minutes, seconds) = minutesAndSeconds(from: timeRemaining)
    minutesLabel.text = formatMinuteOrSecond(minutes)
    secondsLabel.text = formatMinuteOrSecond(seconds)
  }

  // Start the timer, which will call the timerTick() method every second.
  func startTimer() {
    myTimer = Timer.scheduledTimer(timeInterval: 1,
                                   target: self,
                                   selector: #selector(timerTick),
                                   userInfo: nil,
                                   repeats: true)
  }

  func timerTick() {
    if timeRemaining > 0 {
      timeRemaining -= 1
      print("time: \(timeRemaining)")
      updateDisplay()
    } else {
      myTimer.invalidate()
      startNextInterval()
    }
  }

  func pauseTimer() {
    myTimer.invalidate()
    intervalLabel.text = "Paused."
  }

  func setTomatoMeter(to tomatoes: Int) {
    var currentTomato = 1
    for tomatoIcon in tomatoIcons {
      tomatoIcon.alpha = currentTomato <= tomatoes ? 1.0 : 0.2
      currentTomato += 1
    }
  }

  // Given a number of seconds, return it as (minutes, seconds).
  func minutesAndSeconds(from seconds: Int) -> (Int, Int) {
    return (seconds / 60, seconds % 60)
  }

  // Given a number, return it as a string of 2 digits,
  // with a leading zero if necessary.
  func formatMinuteOrSecond(_ number: Int) -> String {
    return String(format: "%02d", number)
  }

}

Click here to download the completed project.

So what’s Tampa iOS Meetup, anyway?

Tampa iOS Meetup is the Tampa Bay area’s meetup for beginning programmers and developers new to iOS development. We take a hands-on approach because it’s our answer to a question that I’ve been asked again and again, and it goes something like this:

“I’ve been studying iOS development for some time, and I’m still having a problem writing apps. I know how to program specific features in iOS, but I don’t know how to turn a bunch of features into an app.”

It’s one thing to go through tutorials that show you how to program a specific feature. It’s a completely different thing to take the knowledge from those tutorials and then write an app. My goal for Tampa iOS Meetup in 2017 is to show you how to make that leap by walking you through the process of making apps.

If you’re in the Tampa area and you’ve always wanted to learn iOS development but needed some help getting started, Tampa iOS Meetup is for you! It’s a regular gathering aimed at people new to iOS development or software development in general where we cover all sorts of programming topics as we build applications together in a casual, fun, hands-on setting. Find out more at the Tampa iOS Meetup page.

Categories
Uncategorized

A time traveler from just 10 years ago would have no idea what this billboard is saying

Click the photo to see it at full size.

Lan Bui, who works at mobile marketing firm Leanplum, posted the photo above on LinkedIn, which I found through our mutual friend Analise Perry. It occurred to me that there’d be some people today who’d find it cryptic, and it would be a complete mystery to a reader from a mere ten years ago.

“Lit” has had a slang meaning for over a century, “AF” would make sense to someone from a decade ago once you expanded the acronym, and a designer from that time period might call refer to the little pictures of fire as “pictograms” rather than “emoji”.

It might take longer to explain what “mobile marketing” is to someone from 2007, because it’s hard to imagine doing marketing on the devices, network and software of that era:

A still from the “Stevenote” where the iPhone was introduced.

Categories
Uncategorized

Technology itself is NOT the real disrupter/disruptor [with addendum]

Click the photo to see it at full size.

The photo above has been making the rounds on LinkedIn and Twitter, and I thought that it was worth repeating here.

Here’s the text written on the whiteboard:

  • Amazon didn’t kill the retail industry. They did it to themselves with bad customer service.
  • Netflix did not kill Blockbuster. They did it to themselves with ridiculous late fees.
  • Uber did not kill the taxi industry. They did it to themselves by limiting the number of taxis and with fare control.
  • Apple did not kill the music industry. They did it to themselves by forcing people to buy full-length albums.
  • AirBnB did not kill the hotel industry. They did it to themselves by limited availability and pricing options.

Technology itself is not the real disrupter…

Being non-customer centric is the biggest threat to any business.

In case you were wondering “Is it spelled disrupter or disruptor?”, it appears that either is an acceptable spelling.

Garrett Serack’s good counterexamples

Garrett, whom I know from my days at Microsoft, pointed out a couple of counterexamples on Twitter:

And he followed up that tweet with this:

Categories
Current Events Tampa Bay Uncategorized

What’s happening in the Tampa Bay tech scene (Week of Monday, June 26, 2017)

Photo by Matthew Paulson. Click to see the source.

Every week, I compile a list of events for developers, technologists, and tech entrepreneurs in and around the Tampa Bay area. We’ve got a lot of events going on this week, and here they are!

Monday, June 26

Tuesday, June 27

Wednesday, June 28

Thursday, June 29

Friday, June 30

Saturday, July 1

Sunday, July 2

Let me know about your upcoming event!

Do you have an upcoming event that belongs on this list? Drop me a line at joey@globalnerdy.com and give me the details!

Categories
Uncategorized

What a cool girl, a kiss-ass, and a crank have to say about Travis Kalanick’s resignation

Creative Commons photo by Dan Taylor/Heisenberg Media. Click to see the source.

You can find out a lot of the Valley from the Twitter responses to the story about Travis Kalanick’s resignation as Uber’s C.E.Bro.

Alexia Tsotsis is Kalanick’s “Cool Tech Girl”

TechCrunch co-editor Alexia Tsotsis’ tweet reminded me of Sarah Stockdale’s recent (and brilliant) article titled The myth of the ‘cool tech girl’ (and why she’s dangerous), a warning about the women in tech who try to “fit in” by going along with the brogrammers and end up perpetuating tech’s most toxic problems.
Some key excerpts:

The cool girl in tech plays ping pong, drinks beer at work, is “one of the guys”, participates in inappropriate slack .gif threads, says things like “she’s overreacting”, “I don’t consider myself a feminist, I just work hard”, “I’ve never experienced discrimination at work”. The cool girl doesn’t call out sexist remarks, she laughs at your ‘jokes’, she defends you to other women, and helps silence them. The cool girl is ‘one of the boys’.

The cool tech girl is a toxic myth, she helps men feel safe in their sexism. She enables the persistent and perpetual gender discrimination in our field. She’s hurting you, and me, and she needs to fuck right off already.

Congrats, Alexia: you’re a cool tech girl!

Bill Gurley plays Smithers to Kalanick’s Mr. Burns

Note to Gurley: Dude, in the final analysis, he created an app that combined crowdsourcing, taxi services, and 21st century serfdom. This sort of hyperbolic praise reminds me of the “making the world a better place” bit from the finale of Silicon Valley’s first season:

Gurley’s skewed picture of history also reminds me of this New Yorker comic by Tom Toro:

Click the comic to see the source.

For a longer look at where this inflation-of-importance mindset in the Valley comes from, check out part one of the BBC documentary All Watched Over by Machines of Loving Grace, whose thesis is that computers have failed to liberate humanity, and instead have “distorted and simplified our view of the world around us”.

Michael Arrington is…well, Michael effing Arrington.

Stay classy, Mike.

As a reminder of the the company and culture created by the guy that Arrington is defending, allow me to refer you to these articles:

Categories
Uncategorized

Build a productivity-boosting Pomodoro timer app at the next Tampa iOS Meetup

If you’ve always wanted to learn how to write mobile apps, but never knew how to get started, you should join Tampa iOS Meetup! It’s a beginner-friendly gathering of people who are either new to programming or new to iOS development that learns it by building an app at a time.

In this Tampa iOS Meetup, we’re going to build a Pomodoro timer app — a tool that used with the Pomodoro Technique, an ingeniously simple lifehack that many people have used to help them power past distraction, stay focused on their work, and be incredibly productive.

What is the Pomodoro Technique?

Pomodoro is the Italian word for “tomato” and refers to the tomato-shaped kitchen timer that the technique’s inventor, Francesco Cirillo, used in developing the technique. The technique itself is pretty simple:

  • Pick a task that you want to tackle.
  • Set a timer for 25 minutes. Because Cirillo used a tomato-shaped kitchen timer, he called this 25-minute interval a “pomodoro”.
  • Work on the task — and nothing but that task — until the timer rings.
  • After the timer rings, put a checkmark on a piece of paper.
  • If you have fewer than four checkmarks, take a five-minute break, then start another pomodoro.
  • If you have four checkmarks, take a longer break — typically 15 to 30 minutes — and reset your checkmark count back to zero. Then start a new pomodoro.

By breaking a large task or series of tasks into short, focused intervals, the Pomodoro Technique aims to have your brain to work in short sprints — which it’s evolved to do — and take regular breaks to help it recharge. The intended result is to ensure consistent productivity, motivation, and creativity.

Want to know more about the Pomodoro technique? Check out this video…

…and these links:

What will we do at this meetup?

There are a number of Pomodoro apps out there, such Focus Keeper (pictured above). In this meetup, we’ll build one that you can then expand upon and maybe even put in the store!

You’ll learn how to:

  • Write code that is automatically at regularly-timed intervals
  • Get user input in the user-friendliest and appropriate way
  • Use sound and animations to make a polished-looking app

What will you need to bring?

If you’ve got a MacBook, you’ll want to bring it (make sure you’ve installed Xcode), because we’re going to code this app during the session! I’ll set you up with a starter project, and then write the actual code that powers it. By the end of the session, you’ll be able to write your own Pomodoro productivity app and tweak it to make it your very own.

(And yes, you can still come if you don’t bring a Mac laptop.)

Will there be food?

Yes! In addition to providing us with the space, the fine people at Wolters Kluwer (and their doubly-fine representative, John Wang) will provide food and drink for free. The food varies; sometimes it’s pizza, sometimes it’s pasta, sometimes it’s sandwiches. There’s usually a vegetarian option.

Let’s give Wolters Kluwer a golf clap for making the meetup possible!

When, where, and how do you register?

Categories
Current Events Tampa Bay Uncategorized

What’s happening in the Tampa Bay tech scene (Week of Monday, June 19, 2017)

Every week, I compile a list of events for developers, technologists, and tech entrepreneurs in and around the Tampa Bay area. We’ve got a lot of events going on this week, and here they are!

Monday, June 19

Tuesday, June 20

Wednesday, June 21

Thursday, June 22

Friday, June 23

Saturday, June 24

Sunday, June 25