formotion 1.3.1 → 1.4.0

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 (47) hide show
  1. checksums.yaml +8 -8
  2. data/.travis.yml +1 -0
  3. data/Formotion.gemspec +1 -1
  4. data/LIST_OF_ROW_TYPES.md +115 -3
  5. data/README.md +1 -0
  6. data/examples/KitchenSink/app/app_delegate.rb +16 -2
  7. data/lib/formotion.rb +9 -1
  8. data/lib/formotion/form/form.rb +7 -0
  9. data/lib/formotion/form/form_delegate.rb +2 -2
  10. data/lib/formotion/patch/ui_image.rb +45 -0
  11. data/lib/formotion/patch/ui_text_view_placeholder.rb +4 -1
  12. data/lib/formotion/row/row.rb +13 -1
  13. data/lib/formotion/row_type/base.rb +13 -4
  14. data/lib/formotion/row_type/button.rb +1 -0
  15. data/lib/formotion/row_type/check_row.rb +2 -1
  16. data/lib/formotion/row_type/date_row.rb +3 -0
  17. data/lib/formotion/row_type/image_row.rb +6 -1
  18. data/lib/formotion/row_type/map_row.rb +79 -0
  19. data/lib/formotion/row_type/multi_choice_row.rb +25 -0
  20. data/lib/formotion/row_type/object_row.rb +30 -0
  21. data/lib/formotion/row_type/options_row.rb +2 -2
  22. data/lib/formotion/row_type/paged_image_row.rb +257 -0
  23. data/lib/formotion/row_type/picker_row.rb +2 -0
  24. data/lib/formotion/row_type/slider_row.rb +2 -2
  25. data/lib/formotion/row_type/static_row.rb +1 -1
  26. data/lib/formotion/row_type/string_row.rb +3 -7
  27. data/lib/formotion/row_type/subform_row.rb +3 -1
  28. data/lib/formotion/row_type/switch_row.rb +2 -2
  29. data/lib/formotion/row_type/tags_row.rb +172 -0
  30. data/lib/formotion/row_type/template_row.rb +3 -3
  31. data/lib/formotion/row_type/text_row.rb +5 -1
  32. data/lib/formotion/row_type/web_view_row.rb +44 -0
  33. data/lib/formotion/version.rb +1 -1
  34. data/resources/tags_row-selected.png +0 -0
  35. data/resources/tags_row-selected@2x.png +0 -0
  36. data/resources/tags_row.png +0 -0
  37. data/resources/tags_row@2x.png +0 -0
  38. data/spec/form_spec.rb +26 -0
  39. data/spec/functional/date_row_spec.rb +6 -0
  40. data/spec/functional/picker_row_spec.rb +5 -0
  41. data/spec/row_type/back_spec.rb +1 -1
  42. data/spec/row_type/base_spec.rb +3 -3
  43. data/spec/row_type/string_spec.rb +14 -3
  44. data/spec/row_type/subform_spec.rb +1 -1
  45. data/spec/row_type/submit_spec.rb +1 -1
  46. data/spec/row_type/text_spec.rb +7 -0
  47. metadata +17 -6
@@ -8,7 +8,7 @@ module Formotion
8
8
  SLIDER_VIEW_TAG = 1200
9
9
 
10
10
  def build_cell(cell)
11
- cell.selectionStyle = UITableViewCellSelectionStyleNone
11
+ cell.selectionStyle = self.row.selection_style || UITableViewCellSelectionStyleNone
12
12
  slideView = UISlider.alloc.initWithFrame(CGRectZero)
13
13
  cell.accessoryView = cell.editingAccessoryView = slideView
14
14
  row.range ||= (1..10)
@@ -52,4 +52,4 @@ module Formotion
52
52
 
53
53
  end
54
54
  end
55
- end
55
+ end
@@ -8,4 +8,4 @@ module Formotion
8
8
  end
9
9
  end
10
10
  end
11
- end
11
+ end
@@ -21,6 +21,7 @@ module Formotion
21
21
  # Also does the layoutSubviews swizzle trick
22
22
  # to size the UITextField so it won't bump into the titleLabel.
23
23
  def build_cell(cell)
24
+ cell.selectionStyle = self.row.selection_style || UITableViewCellSelectionStyleBlue
24
25
  field = UITextField.alloc.initWithFrame(CGRectZero)
25
26
  field.tag = TEXT_FIELD_TAG
26
27
 
@@ -72,6 +73,7 @@ module Formotion
72
73
  end
73
74
  end
74
75
 
76
+ field.font = BW::Font.new(row.font) if row.font
75
77
  field.placeholder = row.placeholder
76
78
  field.text = row_value
77
79
  cell.addSubview(field)
@@ -131,13 +133,7 @@ module Formotion
131
133
  end
132
134
 
133
135
  def on_select(tableView, tableViewDelegate)
134
- super or _on_select(tableView, tableViewDelegate)
135
- end
136
-
137
- def _on_select(tableView, tableViewDelegate)
138
- if !row.editable?
139
- return
140
- else
136
+ if row.editable?
141
137
  row.text_field.becomeFirstResponder
142
138
  end
143
139
  end
@@ -7,6 +7,7 @@ module Formotion
7
7
  LABEL_TAG=1001
8
8
 
9
9
  def build_cell(cell)
10
+ cell.selectionStyle = self.row.selection_style || UITableViewCellSelectionStyleBlue
10
11
  cell.accessoryType = cell.editingAccessoryType = UITableViewCellAccessoryDisclosureIndicator
11
12
 
12
13
  cell.contentView.addSubview(self.display_key_label)
@@ -27,6 +28,7 @@ module Formotion
27
28
  end
28
29
 
29
30
  display_key_label.highlightedTextColor = cell.textLabel.highlightedTextColor
31
+ nil
30
32
  end
31
33
 
32
34
  def update_cell(cell)
@@ -52,4 +54,4 @@ module Formotion
52
54
  end
53
55
  end
54
56
  end
55
- end
57
+ end
@@ -6,7 +6,7 @@ module Formotion
6
6
  include BW::KVO
7
7
 
8
8
  def build_cell(cell)
9
- cell.selectionStyle = UITableViewCellSelectionStyleNone
9
+ cell.selectionStyle = self.row.selection_style || UITableViewCellSelectionStyleNone
10
10
  switchView = UISwitch.alloc.initWithFrame(CGRectZero)
11
11
  switchView.accessibilityLabel = (row.title || "") + " Switch"
12
12
  cell.accessoryView = cell.editingAccessoryView = switchView
@@ -27,4 +27,4 @@ module Formotion
27
27
 
28
28
  end
29
29
  end
30
- end
30
+ end
@@ -0,0 +1,172 @@
1
+ motion_require 'base'
2
+
3
+ # ideas and images taken from:
4
+ # https://github.com/davbeck/TURecipientBar
5
+ # License: https://github.com/davbeck/TURecipientBar/blob/master/LICENSE.md
6
+
7
+ module Formotion
8
+ module RowType
9
+ class TagsRow < Base
10
+ include BW::KVO
11
+
12
+ TAGS_VIEW_TAG=1110
13
+ TAGS_EDIT_VIEW_TAG=1111
14
+
15
+ def build_cell(cell)
16
+ # only show the "plus" when editable
17
+ add_plus_accessory(cell) if row.editable?
18
+
19
+ self.row.value = [] unless self.row.value.is_a?(Array)
20
+
21
+ @scroll_view = UIScrollView.alloc.init
22
+ @scroll_view.tag = row.editable? ? TAGS_EDIT_VIEW_TAG : TAGS_VIEW_TAG
23
+ @scroll_view.delegate = self
24
+ @scroll_view.pagingEnabled = false
25
+ @scroll_view.delaysContentTouches = true
26
+ @scroll_view.showsHorizontalScrollIndicator = false
27
+ @scroll_view.showsVerticalScrollIndicator = false
28
+ @btns = {}
29
+ cell.addSubview(@scroll_view)
30
+
31
+ row.value.each do |t|
32
+ add_tag(t)
33
+ end
34
+
35
+ cell.swizzle(:layoutSubviews) do
36
+ def layoutSubviews
37
+ old_layoutSubviews
38
+
39
+ # viewWithTag is terrible, but I think it's ok to use here...
40
+ edittable = false
41
+ formotion_field = self.viewWithTag(TAGS_VIEW_TAG)
42
+ # is an editable row
43
+ if formotion_field.nil?
44
+ edittable = true
45
+ formotion_field = self.viewWithTag(TAGS_EDIT_VIEW_TAG)
46
+ end
47
+ field_frame = formotion_field.frame
48
+
49
+ field_frame.origin.x = self.textLabel.frame.origin.x + self.textLabel.frame.size.width + Formotion::RowType::Base.field_buffer
50
+ edit_buffer = edittable ? 20.0 : 0.0
51
+ field_frame.size.width = self.frame.size.width - field_frame.origin.x - Formotion::RowType::Base.field_buffer - edit_buffer
52
+
53
+ # rearrange the tags
54
+ last = CGRectMake(0.0, 0.0, 0.0, 0.0)
55
+ formotion_field.subviews.each do |sv|
56
+ now = sv.frame
57
+ now.origin.x = (last.origin.x+last.size.width)+5.0
58
+ now.origin.y = last.origin.y
59
+ if (now.origin.x+now.size.width)+3.0 > field_frame.size.width
60
+ now.origin.x = 5.0
61
+ now.origin.y += last.size.height + 5.0
62
+ end
63
+ sv.frame = now
64
+ last = now
65
+ end
66
+
67
+ # set the height of the scroll box
68
+ max_height = self.frame.size.height - 3.0
69
+ field_frame.size.height = last.origin.y + last.size.height + 5.0
70
+ field_frame.size.height = max_height if field_frame.size.height > max_height
71
+ field_frame.origin.y = (self.frame.size.height - field_frame.size.height) / 2.0
72
+
73
+ formotion_field.frame = field_frame
74
+
75
+ end
76
+ end
77
+ end
78
+
79
+ def _on_select(tableView, tableViewDelegate)
80
+ end
81
+
82
+ def add_plus_accessory(cell)
83
+ @add_button ||= begin
84
+ button = UIButton.buttonWithType(UIButtonTypeContactAdd)
85
+ button.when(UIControlEventTouchUpInside) do
86
+ if row.on_tap_callback
87
+ row.on_tap_callback.call(self.row)
88
+ end
89
+ end
90
+ button
91
+ end
92
+ cell.accessoryView = cell.editingAccessoryView = @add_button
93
+ end
94
+
95
+ def image_for_state(state)
96
+ case state
97
+ when UIControlStateNormal
98
+ return UIImage.imageNamed("tags_row.png").stretchableImageWithLeftCapWidth(14, topCapHeight:0)
99
+
100
+ when UIControlStateHighlighted, UIControlStateSelected
101
+ return UIImage.imageNamed("tags_row-selected.png").stretchableImageWithLeftCapWidth(14, topCapHeight:0)
102
+
103
+ end
104
+ nil
105
+ end
106
+
107
+ def attrib_for_state(state)
108
+ case state
109
+ when UIControlStateNormal
110
+ return { NSFontAttributeName => UIFont.systemFontOfSize(14.0),
111
+ NSForegroundColorAttributeName => UIColor.blackColor }
112
+
113
+ when UIControlStateHighlighted, UIControlStateSelected
114
+ return { NSFontAttributeName => UIFont.systemFontOfSize(14.0),
115
+ NSForegroundColorAttributeName => UIColor.whiteColor }
116
+
117
+ end
118
+ end
119
+
120
+ def add_tag(text)
121
+ return if @btns.has_key?(text)
122
+ btn = UIButton.buttonWithType(UIButtonTypeCustom)
123
+ btn.adjustsImageWhenHighlighted = false
124
+ btn.contentEdgeInsets = UIEdgeInsetsMake(0.0, 5.0, 0.0, 5.0)
125
+ textsize = text.sizeWithFont(UIFont.systemFontOfSize(14.0))
126
+ width = textsize.width+14.0
127
+ btn.frame = CGRectMake(0.0, 0.0, width, 24.0)
128
+ [UIControlStateNormal, UIControlStateHighlighted, UIControlStateSelected].each do |state|
129
+ btn.setBackgroundImage(image_for_state(state), forState:state)
130
+ attr_text = NSAttributedString.alloc.initWithString(text, attributes:attrib_for_state(state))
131
+ btn.setAttributedTitle(attr_text, forState:state)
132
+ end
133
+
134
+ if row.editable?
135
+ btn.addTarget(self, action:'button_click:', forControlEvents:UIControlEventTouchUpInside)
136
+ end
137
+
138
+ btn.translatesAutoresizingMaskIntoConstraints = false
139
+ @scroll_view.addSubview(btn)
140
+ unless row.value.include?(text)
141
+ row.value << text
142
+ end
143
+ @btns[text] = btn
144
+ end
145
+
146
+ def button_click(btn)
147
+ @del_btn = btn
148
+ App.alert(BW.localized_string("Remove Tag?"), cancel_button_title: NO) do |alert|
149
+ alert.addButtonWithTitle(YES)
150
+ alert.delegate = self
151
+ end
152
+ end
153
+
154
+ YES = BW.localized_string("Yes", nil)
155
+ NO = BW.localized_string("No", nil)
156
+
157
+ def alertView(alert_view, clickedButtonAtIndex:button_index)
158
+ if alert_view.buttonTitleAtIndex(button_index)==NO
159
+ @del_btn = nil
160
+ return
161
+ end
162
+ @del_btn.removeFromSuperview
163
+ @btns.delete(@del_btn)
164
+ row.value.delete(@del_btn.currentAttributedTitle.string)
165
+ end
166
+
167
+ def scrollViewDidScroll(_scroll_view)
168
+ end
169
+
170
+ end
171
+ end
172
+ end
@@ -27,11 +27,11 @@ module Formotion
27
27
  end
28
28
 
29
29
  def build_cell(cell)
30
- cell.selectionStyle = UITableViewCellSelectionStyleBlue
30
+ cell.selectionStyle = self.row.selection_style || UITableViewCellSelectionStyleBlue
31
31
  @add_button ||= begin
32
32
  button = UIButton.buttonWithType(UIButtonTypeContactAdd)
33
33
  button.when(UIControlEventTouchUpInside) do
34
- self.on_select(nil, nil)
34
+ self._on_select(nil, nil)
35
35
  end
36
36
  button
37
37
  end
@@ -125,4 +125,4 @@ module Formotion
125
125
 
126
126
  end
127
127
  end
128
- end
128
+ end
@@ -10,6 +10,7 @@ module Formotion
10
10
  attr_accessor :field
11
11
 
12
12
  def build_cell(cell)
13
+ cell.selectionStyle = self.row.selection_style || UITableViewCellSelectionStyleBlue
13
14
 
14
15
  @field = UITextView.alloc.initWithFrame(CGRectZero)
15
16
  field.backgroundColor = UIColor.clearColor
@@ -21,6 +22,9 @@ module Formotion
21
22
  field.returnKeyType = row.return_key || UIReturnKeyDefault
22
23
  field.autocapitalizationType = row.auto_capitalization if row.auto_capitalization
23
24
  field.autocorrectionType = row.auto_correction if row.auto_correction
25
+
26
+ # must be set prior to placeholder!
27
+ field.font = BW::Font.new(row.font) if row.font
24
28
  field.placeholder = row.placeholder
25
29
  field.enabled = row.editable?
26
30
 
@@ -87,4 +91,4 @@ module Formotion
87
91
 
88
92
  end
89
93
  end
90
- end
94
+ end
@@ -0,0 +1,44 @@
1
+ motion_require 'base'
2
+
3
+ module Formotion
4
+ module RowType
5
+ class WebViewRow < Base
6
+
7
+ WEB_VIEW_TAG=1100
8
+
9
+ def build_cell(cell)
10
+ cell.selectionStyle = self.row.selection_style || UITableViewCellSelectionStyleBlue
11
+
12
+ @web_view = UIWebView.alloc.init
13
+ @web_view.loadHTMLString(row.value, baseURL:nil) if row.value
14
+ @web_view.tag = WEB_VIEW_TAG
15
+ @web_view.contentMode = UIViewContentModeScaleAspectFit
16
+ @web_view.backgroundColor = UIColor.clearColor
17
+ cell.addSubview(@web_view)
18
+
19
+ cell.swizzle(:layoutSubviews) do
20
+ def layoutSubviews
21
+ old_layoutSubviews
22
+
23
+ # viewWithTag is terrible, but I think it's ok to use here...
24
+ formotion_field = self.viewWithTag(WEB_VIEW_TAG)
25
+
26
+ field_frame = formotion_field.frame
27
+ field_frame.origin.y = 10
28
+ field_frame.origin.x = self.textLabel.frame.origin.x + self.textLabel.frame.size.width + Formotion::RowType::Base.field_buffer
29
+ field_frame.size.width = self.frame.size.width - field_frame.origin.x - Formotion::RowType::Base.field_buffer
30
+ field_frame.size.height = self.frame.size.height - Formotion::RowType::Base.field_buffer
31
+ formotion_field.frame = field_frame
32
+ end
33
+ end
34
+ end
35
+
36
+ def on_select(tableView, tableViewDelegate)
37
+ if !row.editable?
38
+ return
39
+ end
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -1,3 +1,3 @@
1
1
  module Formotion
2
- VERSION = "1.3.1"
2
+ VERSION = "1.4.0"
3
3
  end
Binary file
Binary file
Binary file
Binary file
data/spec/form_spec.rb CHANGED
@@ -52,6 +52,32 @@ describe "Forms" do
52
52
  row.title.should == "Label"
53
53
  row.subtitle.should == "Placeholder"
54
54
  end
55
+
56
+ it "should return row by key" do
57
+ @form = Formotion::Form.new(sections: [{
58
+ rows: [{
59
+ key: :email,
60
+ type: :email,
61
+ editable: true,
62
+ title: 'Email'
63
+ }]
64
+ }])
65
+
66
+ expected = @form.sections[0].rows[0]
67
+ @form.row(:email).should == expected
68
+ end
69
+
70
+ it "should return nil for row by key if key does not exist" do
71
+ @form = Formotion::Form.new(sections: [{
72
+ rows: [{
73
+ key: :email,
74
+ type: :email,
75
+ editable: true,
76
+ title: 'Email'
77
+ }]
78
+ }])
79
+ @form.row(:foobar).should.be.nil
80
+ end
55
81
 
56
82
  it "render works correctly" do
57
83
  @form = Formotion::Form.new(sections: [{
@@ -60,4 +60,10 @@ describe "FormController/DateRow" do
60
60
  end
61
61
  end
62
62
  end
63
+
64
+ it "doesn't have a clear button" do
65
+ tap("Date")
66
+ date_row.text_field.subviews.map(&:class).should.not.include UIButton
67
+ end
68
+
63
69
  end
@@ -58,4 +58,9 @@ describe "FormController/PickerRow" do
58
58
  end
59
59
  end
60
60
  end
61
+
62
+ it "doesn't have a clear button" do
63
+ tap("Picker")
64
+ picker_row.text_field.subviews.map(&:class).should.not.include UIButton
65
+ end
61
66
  end
@@ -8,7 +8,7 @@ describe "Back Row" do
8
8
  it "should pop subform on select" do
9
9
  form = FakeForm.new
10
10
  @row.instance_variable_set("@section", form)
11
- @row.object.on_select(nil, nil)
11
+ @row.object._on_select(nil, nil)
12
12
  form.controller.pop_subform_called.should == true
13
13
  end
14
14
  end
@@ -11,7 +11,7 @@ describe "Base Row Type" do
11
11
  tests_row :dummy
12
12
 
13
13
  it "should return false if callback is not defined" do
14
- @row.object.on_select(nil, nil).should == false
14
+ @row.object._on_select(nil, nil).should == false
15
15
  end
16
16
 
17
17
  describe 'when on_tap_callback is set' do
@@ -24,11 +24,11 @@ describe "Base Row Type" do
24
24
  end
25
25
 
26
26
  it "should return true" do
27
- @row.object.on_select(nil, nil).should == true
27
+ @row.object._on_select(nil, nil).should == true
28
28
  end
29
29
 
30
30
  it "should call the callback" do
31
- @row.object.on_select(nil, nil)
31
+ @row.object._on_select(nil, nil)
32
32
  @called.should == true
33
33
  end
34
34