motion-wizard 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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