Skip to content

PiXeL16/CountItApp

Repository files navigation

Banner Build Status codecov.io GitHub license

DownloadAppStore

Count It

Never lose the count again. Dead simple App with Apple Watch integration that lets you count anything.

  • Laps while exercising.
  • How many beers you drink at the pub.
  • Days since you quit smoking.
  • Glasses of water you drink during the day.
  • People that enter your restaurant or club.
  • Sheep while you sleep 😜

Count It has two way communication between the App and the Watch, meaning that you can start your count on your Watch and continue it on your Phone and vice versa.

Tapping anywhere on the App or Watch face adds to the counter and gives you haptic feedback. You don't have to look at your Watch while counting!

To decrement or clear the counter, force press on your watch face.

Includes a watch complication and glance that lets you easily check and access the count.

You can also modify the look to several color options to fit your style.

The step count can also be modify so you can count in higher numbers not just one by one.

Screenshots

Watch Screenshots

The Code

Installation

This project comes with a Makefile to simplify the onboarding of the project.

To bootstrap the project just clone the repo, navigate to the root directory on terminal and run the following command:

make bootstrap

This will install all the gems specified in the Gemfile as well as installing all the dependencies specified by the Podfile.

In case bundler is not detected the Makefile target will fail.

There are multiple targets supported by the Makefile which can be easily know by running:

make help

Details

The idea of the app was to play with WatchKit 2 and try to create something in a couple of days.

Perhaps, one of the most interesting parts its the two way communication between the App and the Watch.

TwoWayCommunication

All of these is wrapped into the WatchSessionManager.swift.

ApplicationContextChangedDelegate is use as a delegate pattern to let other objects 'register' to events from the WCSession.

//Add view model to the datasource delegate so we get application context changes
       watchSession.addDataSourceChangedDelegate(self)

This is the only thing something like a ViewModel will need to register to these events.

View Models

MVVM is use throughout the app. All of this ViewModels classes are shared along the iOS and Watch targets.

This makes it extremely easy to setup things like Glances and Interface Controllers in the WatchKit side of things.

All ViewModels expose RxSwift observables in the form of Drivers that are perfect to use in ViewModels because they:

  • can't error out
  • observe on main scheduler
  • sharing side effects (shareReplayLatestWhileConnected)

ViewControllers can later connect to this drivers and update UI Elements, for example:

viewModel.clickerCountDriver?
         .map { $0.description }
         .driveNext{ [weak self] count in

          self?.updateCountLabelWithAnimation(count)

         }.addDisposableTo(disposeBag)

This will update the counter label with an animation to latest information.

Data Storage

NSUserDefault is use as the Datastore since the data is really simple. All Model objects implement NSCoding and are saved by using the NSKeyedArchiver.

let data = NSKeyedArchiver.archivedDataWithRootObject(object)

defaults.setObject(data, forKey: key)

defaults.synchronize()

Protocols

There are several protocols like Dictionable and Timeable that encapsulates some good amount of functionality, making it very easy update models objects.

TODO

  • Set a Goal of counts, so you know when you are near your Goal.
  • Better code coverage
  • Improve animations on Watch
  • Watch UI Testing (Not supported by Apple)

👽 Author

Chris Jimenez - http://code.chrisjimenez.net, @chrisjimeneznat

🍺 Donate

If you want to buy me a beer, you can donate to my coin addresses below:

BTC

1BeGBew4CBdLgUSmvoyiU1LrM99GpkXgkj

ETH

0xa59a3793E3Cb5f3B1AdE6887783D225EDf67192d

LTC

Ld6FB3Tqjf6B8iz9Gn9sMr7BnowAjSUXaV

License

Count It is released under the MIT license. See LICENSE for details.