Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit e72ae485b57b736e3f4d3e521ce8eb47d3427e69 Jonathan Penn committed Jun 29, 2012
Showing with 1,973 additions and 0 deletions.
  1. +3 −0 .gitignore
  2. +47 −0 README.markdown
  3. +18 −0 Rakefile
  4. +43 −0 app/app_delegate.rb
  5. +2 −0 app/helpers/patchwork.rb
  6. +11 −0 app/helpers/patchwork/associated_objects.rb
  7. +30 −0 app/helpers/patchwork/constants.rb
  8. +52 −0 app/helpers/patchwork/gesture_listener.rb
  9. +30 −0 app/helpers/patchwork/timer.rb
  10. +36 −0 app/models/config.rb
  11. +41 −0 app/models/countdown.rb
  12. +79 −0 app/models/countdown_calculator.rb
  13. +56 −0 app/models/countdown_collection.rb
  14. +76 −0 app/models/countdown_date.rb
  15. +146 −0 app/view_controllers/countdown_collection_table_view_controller.rb
  16. +200 −0 app/view_controllers/countdown_editor_view_controller.rb
  17. +260 −0 app/view_controllers/countdown_view_controller.rb
  18. +37 −0 app/views/countdown_collection_table_view_cell.rb
  19. +17 −0 app/views/countdown_label.rb
  20. +74 −0 app/views/countdown_table_view_cell.rb
  21. +93 −0 app/views/countdown_week_table_view_cell.rb
  22. +16 −0 app/views/custom_label.rb
  23. +82 −0 app/views/date_picker_action_sheet.rb
  24. +9 −0 app/views/hovering_navigation_bar.rb
  25. +86 −0 app/views/swipe_to_go_back_instructions_label.rb
  26. +16 −0 app/views/title_label.rb
  27. BIN assets/Icon.opacity
  28. BIN resources/Icon-72.png
  29. BIN resources/Icon-AppStore.jpg
  30. BIN resources/Icon-Small-50.png
  31. BIN resources/Icon-Small.png
  32. BIN resources/Icon-Small@2x.png
  33. BIN resources/Icon.png
  34. BIN resources/Icon@2x.png
  35. BIN resources/gear.png
  36. BIN resources/gear@2x.png
  37. BIN resources/iTunesArtwork
  38. +61 −0 spec/helpers/constants_spec.rb
  39. +9 −0 spec/main_spec.rb
  40. +127 −0 spec/models/countdown_calculator_spec.rb
  41. +73 −0 spec/models/countdown_collection_spec.rb
  42. +82 −0 spec/models/countdown_date_spec.rb
  43. +61 −0 spec/models/countdown_spec.rb
@@ -0,0 +1,3 @@
+.repl_history
+build
+tags
@@ -0,0 +1,47 @@
+# Purpose
+
+This is an app I wrote to explore RubyMotion. It counts down the number of days
+to a date in the future and visualizes it with a scrollable week view. You can
+have as many countdowns as you want. When viewing a countdown, swipe to go back
+to the list. Double tap to edit.
+
+I wanted to avoid extra dependencies so I'm not using any of the DSLs for
+building table views or other cocoa touch help. The app makes use of:
+
+- Gesture recognizers
+- CoreAnimation effects
+- Scroll view parallaxing
+- Experiements with my own custome DSL, Patchwork.
+
+Patchwork is my initial attempt to provide objects you can mix in when you
+want to use extra features rather than patching core classes. In effect, I want
+to monkey patch in isolation on the fly rather than patching the whole system
+for the entire app run.
+
+# Future
+
+- Use CoreData
+- iCloud
+- Loading custom table view cell from a nib
+
+# License
+
+Copyright (c) 2012 Jonathan Penn
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
@@ -0,0 +1,18 @@
+$:.unshift("/Library/RubyMotion/lib")
+require 'motion/project'
+
+Motion::Project::App.setup do |app|
+ # Use `rake config' to see complete project settings.
+ app.name = 'Countdown'
+
+ # You'll need to set your own certificate here to install on a device
+ # app.codesign_certificate = <some cert name>
+
+ app.device_family = [:iphone]
+ app.icons = ['Icon']
+end
+
+task 'spec' do
+ # Close the simulator after running specs
+ sh "osascript -e 'tell application \"iphone simulator\" to quit'"
+end
@@ -0,0 +1,43 @@
+class AppDelegate
+ attr_accessor :window
+ attr_accessor :navViewController
+ attr_accessor :collection
+
+ def application(application, didFinishLaunchingWithOptions:launchOptions)
+ setupVisuals
+
+ self.window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
+
+ self.collection = Config.countdownCollection
+
+ controller = CountdownCollectionTableViewController.alloc.init
+ controller.collection = collection
+
+ self.navViewController = UINavigationController.alloc.initWithRootViewController(controller)
+
+ selectedIndex = Config.selectedCountdownIndex
+ if selectedIndex
+ controller.openCountdownAtIndex(selectedIndex)
+ end
+
+ window.rootViewController = navViewController
+
+ window.makeKeyAndVisible
+
+ true
+ end
+
+
+ private
+
+ def setupVisuals
+ UINavigationBar.appearance.tap do |bar|
+ color = UIColor.colorWithRed(0.217, green:0.231, blue:0.182, alpha:1.000)
+ bar.tintColor = color
+ end
+
+ UIApplication.sharedApplication.setStatusBarStyle(UIStatusBarStyleBlackTranslucent,
+ animated: true)
+ end
+
+end
@@ -0,0 +1,2 @@
+module Patchwork
+end
@@ -0,0 +1,11 @@
+module Patchwork
+
+ module AssociatedObjects
+ attr_reader :associations
+
+ def associations
+ @associations ||= Hash.new
+ end
+ end
+
+end
@@ -0,0 +1,30 @@
+module Patchwork
+
+ def UIViewAutoresizing *masks
+ values = masks.map do |sym|
+ case sym
+ when :left
+ UIViewAutoresizingFlexibleLeftMargin
+ when :right
+ UIViewAutoresizingFlexibleRightMargin
+ when :top
+ UIViewAutoresizingFlexibleTopMargin
+ when :bottom
+ UIViewAutoresizingFlexibleBottomMargin
+ when :width
+ UIViewAutoresizingFlexibleWidth
+ when :height
+ UIViewAutoresizingFlexibleHeight
+ when :all
+ UIViewAutoresizing(:left, :right, :top, :bottom, :width, :height)
+ else
+ raise ArgumentError.new("Unknown UIViewAutoresizing mask: :#{sym}")
+ end
+ end
+
+ values.inject(0) do |result, value|
+ result | value
+ end
+ end
+
+end
@@ -0,0 +1,52 @@
+module Patchwork
+
+ module GestureListener
+
+ class GestureHandler
+ def initialize callback
+ @callback = callback
+ end
+
+ def invoke recognizer
+ @callback.call(recognizer)
+ end
+ end
+
+ def onSwipe &block
+ handler = GestureHandler.new(block)
+ gesture = UISwipeGestureRecognizer.alloc.initWithTarget(
+ handler,
+ action: 'invoke:')
+ gesture.extend(AssociatedObjects)
+ gesture.associations["GestureListenerOnSwipe"] = handler
+ gesture.direction = UISwipeGestureRecognizerDirectionRight
+ addGestureRecognizer gesture
+ gesture
+ end
+
+ def onTap &block
+ handler = GestureHandler.new(block)
+ gesture = UITapGestureRecognizer.alloc.initWithTarget(
+ handler,
+ action: 'invoke:')
+ gesture.extend(AssociatedObjects)
+ gesture.associations["GestureListenerOnTap"] = handler
+ addGestureRecognizer gesture
+ gesture
+ end
+
+ def onDoubleTap &block
+ handler = GestureHandler.new(block)
+ gesture = UITapGestureRecognizer.alloc.initWithTarget(
+ handler,
+ action: 'invoke:')
+ gesture.numberOfTapsRequired = 2
+ gesture.extend(AssociatedObjects)
+ gesture.associations["GestureListenerOnDoubleTap"] = handler
+ addGestureRecognizer gesture
+ gesture
+ end
+
+ end
+
+end
@@ -0,0 +1,30 @@
+class Timer
+
+ def self.after seconds, &block
+ new seconds, &block
+ end
+
+ def initialize seconds, &block
+ @seconds = seconds
+ @block = block
+ @nstimer = NSTimer.scheduledTimerWithTimeInterval(
+ seconds,
+ target: self,
+ selector: 'call',
+ userInfo: nil,
+ repeats: false)
+ end
+
+ def stop
+ @nstimer.invalidate if @nstimer
+ @nstimer = nil
+ end
+
+ def call
+ return unless @nstimer
+ @nstimer.invalidate
+ @nstimer = nil
+ @block.call
+ end
+
+end
@@ -0,0 +1,36 @@
+class Config
+
+ def self.countdownCollection
+ CountdownCollection.deserialize(defaults['countdownCollection'] || [])
+ end
+
+ def self.countdownCollection= collection
+ defaults['countdownCollection'] = collection.serialize
+ defaults.synchronize
+ end
+
+ def self.selectedCountdownIndex
+ defaults['selectedCountdownIndex']
+ end
+
+ def self.selectedCountdownIndex= index
+ defaults['selectedCountdownIndex'] = index
+ defaults.synchronize
+ end
+
+ def self.whenLastShownSwipeInstructions
+ defaults['whenLastShownSwipeInstructions'] || NSDate.dateWithTimeIntervalSince1970(0)
+ end
+
+ def self.whenLastShownSwipeInstructions= date
+ defaults['whenLastShownSwipeInstructions'] = date
+ defaults.synchronize
+ end
+
+
+ private
+
+ def self.defaults
+ @defaults ||= NSUserDefaults.standardUserDefaults
+ end
+end
@@ -0,0 +1,41 @@
+class Countdown
+ include Comparable
+
+ attr_accessor :name, :endDate
+ attr_accessor :collection
+
+ def initialize
+ self.name = ''
+ self.endDate = CountdownDate.now
+ end
+
+ def self.newWithName name, endTime: time
+ c = new
+ c.name = name
+ c.endTime = time
+ c
+ end
+
+ def endTime= time
+ self.endDate = CountdownDate(time)
+ end
+
+ def serialize
+ {
+ 'endDate' => endDate.serialize,
+ 'name' => name
+ }
+ end
+
+ def self.deserialize data
+ c = new
+ c.name = data['name']
+ c.endDate = CountdownDate.deserialize(data['endDate'])
+ c
+ end
+
+ def <=> otherCountdown
+ endDate <=> otherCountdown.endDate
+ end
+
+end
Oops, something went wrong.

0 comments on commit e72ae48

Please sign in to comment.