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.
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
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.
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.
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.
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()
There are several protocols like Dictionable
and Timeable
that encapsulates some good amount of functionality, making it very easy update models objects.
- 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)
Chris Jimenez - http://code.chrisjimenez.net, @chrisjimeneznat
If you want to buy me a beer, you can donate to my coin addresses below:
1BeGBew4CBdLgUSmvoyiU1LrM99GpkXgkj
0xa59a3793E3Cb5f3B1AdE6887783D225EDf67192d
Ld6FB3Tqjf6B8iz9Gn9sMr7BnowAjSUXaV
Count It
is released under the MIT license. See LICENSE for details.