motion-wizard 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +74 -0
  6. data/Rakefile +1 -0
  7. data/lib/motion-wizard.rb +9 -0
  8. data/lib/motion-wizard/animation_strategy/base_animation_strategy.rb +25 -0
  9. data/lib/motion-wizard/animation_strategy/ios7_slide_left_to_right.rb +18 -0
  10. data/lib/motion-wizard/animation_strategy/ios7_slide_right_to_left.rb +18 -0
  11. data/lib/motion-wizard/animation_strategy/left_to_right.rb +10 -0
  12. data/lib/motion-wizard/animation_strategy/none.rb +11 -0
  13. data/lib/motion-wizard/animation_strategy/right_to_left.rb +10 -0
  14. data/lib/motion-wizard/animation_strategy/slide_animation.rb +21 -0
  15. data/lib/motion-wizard/controllers/content_controller.rb +17 -0
  16. data/lib/motion-wizard/controllers/wizard_view_controller.rb +143 -0
  17. data/lib/motion-wizard/lib/forwardable.rb +12 -0
  18. data/lib/motion-wizard/views/index_item_view.rb +53 -0
  19. data/lib/motion-wizard/views/wizard_navigation_bar.rb +55 -0
  20. data/motion-wizard.gemspec +22 -0
  21. data/samples/wizard-1/.gitignore +16 -0
  22. data/samples/wizard-1/Gemfile +8 -0
  23. data/samples/wizard-1/Rakefile +18 -0
  24. data/samples/wizard-1/app/app_delegate.rb +8 -0
  25. data/samples/wizard-1/app/controllers/steps_view_controller.rb +92 -0
  26. data/samples/wizard-1/app/controllers/wizard_1_view_controller.rb +28 -0
  27. data/samples/wizard-1/app/views/styles/steps.rb +128 -0
  28. data/samples/wizard-1/app/views/styles/wizard_1_view_controller.rb +42 -0
  29. data/samples/wizard-1/resources/Default-568h@2x.png +0 -0
  30. data/samples/wizard-1/spec/main_spec.rb +9 -0
  31. data/samples/wizard-2/.gitignore +16 -0
  32. data/samples/wizard-2/Gemfile +8 -0
  33. data/samples/wizard-2/Rakefile +22 -0
  34. data/samples/wizard-2/app/app_delegate.rb +10 -0
  35. data/samples/wizard-2/app/controllers/steps_view_controller.rb +59 -0
  36. data/samples/wizard-2/app/controllers/wizard_2_view_controller.rb +29 -0
  37. data/samples/wizard-2/app/views/my_custom_index_item_view.rb +25 -0
  38. data/samples/wizard-2/app/views/styles/handlers.rb +7 -0
  39. data/samples/wizard-2/app/views/styles/index_item.rb +36 -0
  40. data/samples/wizard-2/app/views/styles/steps.rb +67 -0
  41. data/samples/wizard-2/app/views/styles/wizard_view_controller.rb +4 -0
  42. data/samples/wizard-2/resources/Default-568h@2x.png +0 -0
  43. data/samples/wizard-2/resources/background-568h@2x.png +0 -0
  44. data/samples/wizard-2/resources/background.png +0 -0
  45. data/samples/wizard-2/resources/background@2x.png +0 -0
  46. data/samples/wizard-2/resources/button.png +0 -0
  47. data/samples/wizard-2/spec/main_spec.rb +9 -0
  48. data/wizard-1.gif +0 -0
  49. data/wizard-2.gif +0 -0
  50. metadata +120 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0b0eb05108f916b5e4a2379147a5517ab4f181dd
4
+ data.tar.gz: afcfe23fb17888d3afd67cb0170b0cf45cc6386b
5
+ SHA512:
6
+ metadata.gz: ebdb9eb94f462dcddf59ad992f40dff1adc1f1b6384e313ecb03f15cbfd6e2ee61fbff466d1cc9c1a25949e15561d2a93db945525470df763b02c2f23b6b9066
7
+ data.tar.gz: e19250b87f2322a6f8f16c6a5f8e543f739a9d349359b733fffd4cc75300d8e388ee234f6b7a5051fde87c7ef85b3e8e9e058b35db8e08b0a02b524fc50b22de
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in motion-wizard-wizard.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Ignacio Piantanida
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,74 @@
1
+ # Motion-Wizard
2
+
3
+ A small gem to create clean wizard-like views
4
+
5
+ ![Sample 1](https://raw.github.com/ijpiantanida/motion-wizard/master/wizard-1.gif)
6
+ ![Sample 2](https://raw.github.com/ijpiantanida/motion-wizard/master/wizard-2.gif)
7
+
8
+ #Installation
9
+ #How to use it
10
+ Your custom wizard view controller will inherit from `MotionWizard::WizardViewController`.
11
+
12
+ With the `steps` class method, you specify which view controllers will describe your wizard.
13
+
14
+ ``` ruby
15
+ class Wizard1ViewController < MotionWizard::WizardViewController
16
+ steps Step1ViewController,
17
+ Step2ViewController,
18
+ Step3ViewController,
19
+ Step4ViewController
20
+ end
21
+ ```
22
+ ##Moving through steps
23
+ The `WizardViewController` will create instances of your steps controllers which will then be extended with the `MotionWizard::ContentController` module. This module gives you the following methods which can be used inside your steps:
24
+ * **#next(data)**: Will move to the next step. It will call `#finish` if there is no following step.
25
+ * **#previous(data)**: Will move to the previous step. If already on the first step, this method will do nothing.
26
+ * **#go_to_step(step_number, data)**: Will go to the selected step.
27
+ * **#finish(data)**: Will call the `#when_finished` method on the wizard view controller
28
+
29
+ When moving through steps, you can pass an optional hash parameter with custom data that will get merged into a common wizard hash. You can access this hash inside your steps with the `#wizard_data` method.
30
+
31
+ ``` ruby
32
+ class Step1ViewController
33
+ ...
34
+
35
+ def viewWillAppear(animated)
36
+ super
37
+ @button.on(:touch){ self.next(step_1_text: "Awesome!") }
38
+ end
39
+
40
+ ...
41
+ end
42
+ ```
43
+
44
+ Your wizard view controller class can define a `#when_finished` method that will get called when any of the steps view controller call `#finish` or `#next` when already on the last step. Within this method you have also access to `wizard_data`.
45
+
46
+ ``` ruby
47
+ class Wizard1ViewController < MotionWizard::WizardViewController
48
+ def when_finished
49
+ NSLog "You can access your data here #{wizard_data}"
50
+ end
51
+ end
52
+ ```
53
+
54
+ ##Customizing Index Views
55
+ By default, index views will be instances of `MotionWizard::IndexItem`. This view has a `label_wrapper` (`UIView`) subview, which has a `label` (`UILabel`) subview.
56
+
57
+ It also defines two methods `when_selected` and `when_unselected` that allow to subscribe a block to be called whenever the current step changes.
58
+
59
+ You can customize the default index view appearance and behaviour by defining the `set_up_index_item_at(index_item, index)` method inside your `WizardViewController` subclass ([see sample Nr 1](samples/wizard-1)).
60
+
61
+ ``` ruby
62
+ class Wizard1ViewController < MotionWizard::WizardViewController
63
+ def setup_index_item_at(index_item, index)
64
+ layout(index_item, :index_item)
65
+ index_item.label.text = "ABCD"[index]
66
+ end
67
+ end
68
+ ```
69
+
70
+ If you would rather use a custom index item class instead of the default one, you can register it using the `index_item_view_class` class method inside your `WizardViewController` subclass definition.
71
+
72
+ Your custom class can define the methods `#select` and `#unselect` to be called whenever the wizard changes the current step.
73
+
74
+ ([see sample Nr 2](samples/wizard-2))
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,9 @@
1
+ unless defined?(Motion::Project::Config)
2
+ raise "This file must be required within a RubyMotion project Rakefile."
3
+ end
4
+
5
+ Motion::Project::App.setup do |app|
6
+ Dir.glob(File.join(File.dirname(__FILE__), 'motion-wizard/**/*.rb')).reverse.each do |file|
7
+ app.files.unshift file
8
+ end
9
+ end
@@ -0,0 +1,25 @@
1
+ module MotionWizard
2
+ module AnimationStrategy
3
+ class BaseAnimationStrategy
4
+ attr_accessor :already_on_final_position, :duration
5
+
6
+ def initialize
7
+ @duration = 0.5
8
+ end
9
+
10
+ def show_view(view, &after_block)
11
+ @show_view = view
12
+ @show_view_after_block = after_block
13
+ end
14
+
15
+ def hide_view(view, &after_block)
16
+ @hide_view = view
17
+ @hide_view_after_block = after_block
18
+ end
19
+
20
+ def animate
21
+ raise "Subclass responsability"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ module MotionWizard
2
+ module AnimationStrategy
3
+ class Ios7SlideLeftToRight < SlideAnimation
4
+ def initialize
5
+ super
6
+ @duration = 0.25
7
+ end
8
+
9
+ def animate
10
+ show_view_index = @show_view.superview.subviews.index(@show_view)
11
+ hide_view_index = @show_view.superview.subviews.index(@hide_view)
12
+ @show_view.superview.exchangeSubviewAtIndex(hide_view_index, withSubviewAtIndex: show_view_index) if show_view_index > hide_view_index
13
+ do_slide_animation(@show_view, -70, 0, @show_view_after_block)
14
+ do_slide_animation(@hide_view, 0, App.frame.size.width, @hide_view_after_block)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module MotionWizard
2
+ module AnimationStrategy
3
+ class Ios7SlideRightToLeft < SlideAnimation
4
+ def initialize
5
+ super
6
+ @duration = 0.25
7
+ end
8
+
9
+ def animate
10
+ show_view_index = @show_view.superview.subviews.index(@show_view)
11
+ hide_view_index = @show_view.superview.subviews.index(@hide_view)
12
+ @show_view.superview.exchangeSubviewAtIndex(hide_view_index, withSubviewAtIndex: show_view_index) if show_view_index < hide_view_index
13
+ do_slide_animation(@show_view, App.frame.size.width, 0, @show_view_after_block)
14
+ do_slide_animation(@hide_view, 0, -70, @hide_view_after_block)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ module MotionWizard
2
+ module AnimationStrategy
3
+ class LeftToRight < SlideAnimation
4
+ def initialize
5
+ super
6
+ @direction = -1
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module MotionWizard
2
+ module AnimationStrategy
3
+ class None < BaseAnimationStrategy
4
+ def initialize; end
5
+
6
+ def show_view(view); end
7
+ def hide_view(view); end
8
+ def animate; end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ module MotionWizard
2
+ module AnimationStrategy
3
+ class RightToLeft < SlideAnimation
4
+ def initialize
5
+ super
6
+ @direction = 1
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ module MotionWizard
2
+ module AnimationStrategy
3
+ class SlideAnimation < BaseAnimationStrategy
4
+ attr_accessor :direction
5
+
6
+ def animate
7
+ do_slide_animation(@show_view, @direction*App.frame.size.width, 0, @show_view_after_block)
8
+ do_slide_animation(@hide_view, 0, -@direction*App.frame.size.width, @hide_view_after_block)
9
+ end
10
+
11
+ def do_slide_animation(view, initial_position, final_position, after_block)
12
+ view.origin = [initial_position, view.origin.y]
13
+ UIView.animateWithDuration(@duration, animations: -> {
14
+ view.origin = [final_position, view.origin.y]
15
+ },completion: ->(finished) {
16
+ after_block.call(view) if after_block
17
+ })
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ module MotionWizard
2
+ module ContentController
3
+ extend Forwardable
4
+
5
+ attr_reader :wizard_view_controller
6
+ delegate :@wizard_view_controller, :next, :previous, :go_to_step, :wizard_data, :reset!, :finish
7
+
8
+ def viewDidLoad
9
+ super
10
+ self.view.clipsToBounds = true
11
+ end
12
+
13
+ def wizard_view_controller=(wizard_view_controller)
14
+ @wizard_view_controller = WeakRef.new(wizard_view_controller)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,143 @@
1
+ module MotionWizard
2
+ class WizardViewController < UIViewController
3
+ attr_reader :navigation_bar_view, :content_view, :wizard_data
4
+
5
+ DEFAULT_NAVIGATION_BAR_HEIGHT = 44
6
+
7
+ def self.steps(*steps)
8
+ @_wizard_steps = steps
9
+ end
10
+
11
+ def self.forward_animation_strategy(animation_strategy_class)
12
+ @_forward_animation_strategy_class = animation_strategy_class
13
+ end
14
+
15
+ def self.backward_animation_strategy(animation_strategy_class)
16
+ @_backward_animation_strategy_class = animation_strategy_class
17
+ end
18
+
19
+ def self.index_item_view_class(index_item_view_class)
20
+ @_index_item_view_class = index_item_view_class
21
+ end
22
+
23
+ def init
24
+ super
25
+ @steps_controllers_classes = self.class.instance_variable_get(:@_wizard_steps) || []
26
+ @forward_animation_strategy_class = self.class.instance_variable_get(:@_forward_animation_strategy_class) || AnimationStrategy::RightToLeft
27
+ @backward_animation_strategy_class = self.class.instance_variable_get(:@_backward_animation_strategy_class) || AnimationStrategy::LeftToRight
28
+ @index_item_view_class = self.class.instance_variable_get(:@_index_item_view_class) || IndexItem
29
+ @current_step = 0
30
+ @wizard_data = {}
31
+ @steps_controllers = []
32
+ self
33
+ end
34
+
35
+ def viewDidLoad
36
+ super
37
+
38
+ @content_view = UIView.alloc.init
39
+ @content_view.origin = [0,0]
40
+ @content_view.size = self.view.size
41
+ self.view.addSubview(@content_view)
42
+
43
+ @navigation_bar_view = WizardNavigationBar.alloc.init_with_number_of_steps(number_of_steps, self)
44
+ @navigation_bar_view.origin = [0,0]
45
+ @navigation_bar_view.size = [self.view.size.width, DEFAULT_NAVIGATION_BAR_HEIGHT]
46
+ self.view.addSubview(navigation_bar_view)
47
+
48
+ add_new_step_view(AnimationStrategy::None.new)
49
+ end
50
+
51
+ def reset!
52
+ @wizard_data = {}
53
+ @steps_controllers = []
54
+ @navigation_bar_view.reset!
55
+ navigation_bar_view.select(@current_step)
56
+ end
57
+
58
+ def add_new_step_view(animation_strategy)
59
+ @current_view_controller = get_current_step_view_controller
60
+ self.addChildViewController(@current_view_controller)
61
+ @content_view.addSubview(@current_view_controller.view)
62
+
63
+ @current_view_controller.view.origin = [0,0]
64
+ animation_strategy.show_view(@current_view_controller.view)
65
+ navigation_bar_view.select(@current_step)
66
+ end
67
+
68
+ def get_current_step_view_controller
69
+ @steps_controllers[@current_step] ||= begin
70
+ new_view_controller = @steps_controllers_classes[@current_step].alloc.init
71
+ new_view_controller.extend(MotionWizard::ContentController)
72
+ new_view_controller.wizard_view_controller = self
73
+ new_view_controller.view.size = @content_view.size
74
+ new_view_controller
75
+ end
76
+ end
77
+
78
+ def remove_current_step_view(animation_strategy)
79
+ current_local_view = @current_view_controller
80
+ animation_strategy.hide_view(@current_view_controller.view) do |view|
81
+ view.removeFromSuperview
82
+ current_local_view.removeFromParentViewController
83
+ end
84
+ end
85
+
86
+ def number_of_steps
87
+ @steps_controllers_classes.size
88
+ end
89
+
90
+ def next(data = {})
91
+ @wizard_data.merge! data
92
+ @current_step+=1
93
+ if @current_step >= number_of_steps
94
+ @current_step = number_of_steps - 1
95
+ self.finish
96
+ return
97
+ end
98
+ change_step_view(@forward_animation_strategy_class)
99
+ self
100
+ end
101
+
102
+ def previous(data = {})
103
+ @wizard_data.merge! data
104
+ @current_step-=1
105
+ return if @current_step < 0
106
+ change_step_view(@backward_animation_strategy_class)
107
+ self
108
+ end
109
+
110
+ def go_to_step(step_number, data = {})
111
+ @wizard_data.merge! data
112
+ animation_klass = @current_step > step_number ? @backward_animation_strategy_class : @forward_animation_strategy_class
113
+ @current_step = step_number
114
+ change_step_view(animation_klass)
115
+ self
116
+ end
117
+
118
+ def finish(data = {})
119
+ @wizard_data.merge! data
120
+ self.when_finished
121
+ end
122
+
123
+ def change_step_view(animation_strategy_klass)
124
+ animation_strategy = animation_strategy_klass.new
125
+ remove_current_step_view(animation_strategy)
126
+ add_new_step_view(animation_strategy)
127
+ animation_strategy.animate
128
+ end
129
+
130
+ def create_index_item_at(index)
131
+ index_item = @index_item_view_class.alloc.init
132
+ index_item.label.text = "%02d" % (index+1)
133
+ index_item
134
+ end
135
+
136
+ def setup_index_item_at(index_item, index)
137
+ index_item.label_wrapper.size = index_item.size
138
+ index_item.label.size = index_item.size
139
+ end
140
+
141
+ def when_finished;end
142
+ end
143
+ end
@@ -0,0 +1,12 @@
1
+ module MotionWizard
2
+ module Forwardable
3
+ def delegate(*methods)
4
+ to = methods.shift
5
+ methods.each do |method_name|
6
+ define_method(method_name) do |*args, &block|
7
+ self.instance_variable_get(to).send(method_name, *args, &block)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end