ProMotion 0.6.5 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/README.md +79 -502
  2. data/Rakefile +30 -0
  3. data/app/app_delegate.rb +3 -1
  4. data/lib/ProMotion.rb +1 -1
  5. data/lib/ProMotion/cocoatouch/TableViewCell.rb +5 -1
  6. data/lib/ProMotion/delegate/delegate.rb +16 -0
  7. data/lib/ProMotion/delegate/delegate_helper.rb +88 -0
  8. data/lib/ProMotion/delegate/delegate_notifications.rb +61 -0
  9. data/lib/ProMotion/helpers/console.rb +3 -3
  10. data/lib/ProMotion/helpers/logger.rb +15 -15
  11. data/lib/ProMotion/helpers/view_helper.rb +7 -5
  12. data/lib/ProMotion/push_notifications/push_notification.rb +51 -0
  13. data/lib/ProMotion/screen_helpers/screen_elements.rb +2 -2
  14. data/lib/ProMotion/screen_helpers/screen_navigation.rb +5 -1
  15. data/lib/ProMotion/screen_helpers/screen_tabs.rb +2 -2
  16. data/lib/ProMotion/screens/_compatibility/formotion_screen.rb +65 -0
  17. data/lib/ProMotion/screens/_screen_module.rb +33 -20
  18. data/lib/ProMotion/screens/_table_screen_module.rb +4 -4
  19. data/lib/ProMotion/{screen_helpers → screens}/_tables/_refreshable_table.rb +2 -2
  20. data/lib/ProMotion/{screen_helpers → screens}/_tables/_searchable_table.rb +27 -34
  21. data/lib/ProMotion/screens/_tables/_sectioned_table.rb +5 -0
  22. data/lib/ProMotion/screens/_tables/_table.rb +149 -0
  23. data/lib/ProMotion/screens/_tables/grouped_table.rb +16 -0
  24. data/lib/ProMotion/screens/_tables/plain_table.rb +17 -0
  25. data/lib/ProMotion/screens/_tables/table_data.rb +148 -0
  26. data/lib/ProMotion/screens/_tables/table_view_cell_module.rb +156 -0
  27. data/lib/ProMotion/screens/table_screen.rb +3 -2
  28. data/lib/ProMotion/version.rb +1 -1
  29. data/spec/functional/func_screen_spec.rb +66 -0
  30. data/spec/functional/func_split_screen_spec.rb +66 -0
  31. data/spec/functional/func_table_screen_spec.rb +52 -0
  32. data/spec/helpers/functional_screen.rb +15 -0
  33. data/spec/helpers/table_screen.rb +32 -8
  34. data/spec/helpers/table_screen_refreshable.rb +1 -1
  35. data/spec/helpers/table_screen_searchable.rb +1 -1
  36. data/spec/helpers/test_delegate.rb +2 -0
  37. data/spec/unit/delegate_spec.rb +38 -0
  38. data/spec/{ios_version_spec.rb → unit/ios_version_spec.rb} +0 -0
  39. data/spec/{logger_spec.rb → unit/logger_spec.rb} +0 -0
  40. data/spec/{main_spec.rb → unit/main_spec.rb} +0 -0
  41. data/spec/{screen_helpers_spec.rb → unit/screen_helpers_spec.rb} +14 -6
  42. data/spec/{screen_module_spec.rb → unit/screen_module_spec.rb} +0 -0
  43. data/spec/{screen_spec.rb → unit/screen_spec.rb} +21 -3
  44. data/spec/{split_screen_in_tab_bar_spec.rb → unit/split_screen_in_tab_bar_spec.rb} +0 -0
  45. data/spec/{split_screen_open_screen_spec.rb → unit/split_screen_open_screen_spec.rb} +0 -0
  46. data/spec/{split_screen_spec.rb → unit/split_screen_spec.rb} +0 -0
  47. data/spec/unit/tables/table_module_spec.rb +108 -0
  48. data/spec/unit/tables/table_screen_spec.rb +92 -0
  49. data/spec/unit/tables/table_view_cell_spec.rb +106 -0
  50. data/spec/{view_helper_spec.rb → unit/view_helper_spec.rb} +0 -0
  51. metadata +50 -29
  52. data/lib/ProMotion/delegate.rb +0 -63
  53. data/lib/ProMotion/screen_helpers/_tables/_sectioned_table.rb +0 -270
  54. data/lib/ProMotion/screen_helpers/_tables/grouped_table.rb +0 -14
  55. data/lib/ProMotion/screen_helpers/_tables/plain_table.rb +0 -15
  56. data/spec/table_screen_spec.rb +0 -72
@@ -0,0 +1,16 @@
1
+ module ProMotion
2
+ module GroupedTable
3
+ include Table
4
+ include RefreshableTable
5
+
6
+ def table_view
7
+ @table_view ||= begin
8
+ t = UITableView.alloc.initWithFrame(self.view.frame, style:UITableViewStyleGrouped)
9
+ t.dataSource = self
10
+ t.delegate = self
11
+ t
12
+ end
13
+ end
14
+ alias :tableView :table_view
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module ProMotion
2
+ module PlainTable
3
+ include Table
4
+ include SearchableTable
5
+ include RefreshableTable
6
+
7
+ def table_view
8
+ @table_view ||= begin
9
+ t = UITableView.alloc.initWithFrame(self.view.frame, style:UITableViewStylePlain)
10
+ t.dataSource = self
11
+ t.delegate = self
12
+ t
13
+ end
14
+ end
15
+ alias :tableView :table_view
16
+ end
17
+ end
@@ -0,0 +1,148 @@
1
+ module ProMotion
2
+ class TableData
3
+ attr_accessor :data, :filtered_data, :filtered, :table_view
4
+
5
+ def initialize(data, table_view)
6
+ self.data = data
7
+ self.table_view = table_view
8
+ end
9
+
10
+ def section(index)
11
+ s = sections.at(index)
12
+ s || { title: nil, cells: [] }
13
+ end
14
+
15
+ def sections
16
+ self.filtered ? self.filtered_data : self.data
17
+ end
18
+
19
+ def section_length(index)
20
+ section(index)[:cells].length
21
+ end
22
+
23
+ def cell(params={})
24
+ if params[:index_path]
25
+ params[:section] = params[:index_path].section
26
+ params[:index] = params[:index_path].row
27
+ end
28
+
29
+ table_section = self.section(params[:section])
30
+ table_section[:cells].at(params[:index].to_i)
31
+ end
32
+
33
+ def delete_cell(params={})
34
+ if params[:index_path]
35
+ params[:section] = params[:index_path].section
36
+ params[:index] = params[:index_path].row
37
+ end
38
+
39
+ table_section = self.section(params[:section])
40
+ table_section[:cells].delete_at(params[:index].to_i)
41
+ end
42
+
43
+ def search(search_string)
44
+ self.filtered_data = []
45
+ self.filtered = true
46
+
47
+ search_string = search_string.downcase.strip
48
+
49
+ self.data.each do |section|
50
+ new_section = {}
51
+ new_section[:cells] = []
52
+
53
+ new_section[:cells] = section[:cells].map do |cell|
54
+ cell[:searchable] != false && "#{cell[:title]}\n#{cell[:search_text]}".downcase.strip.include?(search_string) ? cell : nil
55
+ end.compact
56
+
57
+ if new_section[:cells] && new_section[:cells].length > 0
58
+ new_section[:title] = section[:title]
59
+ self.filtered_data << new_section
60
+ end
61
+ end
62
+
63
+ self.filtered_data
64
+ end
65
+
66
+ def stop_searching
67
+ self.filtered_data = []
68
+ self.filtered = false
69
+ end
70
+
71
+ def table_view_cell(params={})
72
+ if params[:index_path]
73
+ params[:section] = params[:index_path].section
74
+ params[:index] = params[:index_path].row
75
+ end
76
+
77
+ data_cell = self.cell(section: params[:section], index: params[:index])
78
+ return UITableViewCell.alloc.init unless data_cell # No data?
79
+
80
+ data_cell = self.remap_data_cell(data_cell) # TODO: Deprecated, remove in version 1.0
81
+ data_cell = self.set_data_cell_defaults(data_cell)
82
+
83
+ table_cell = self.create_table_cell(data_cell)
84
+
85
+ table_cell
86
+ end
87
+
88
+ def set_data_cell_defaults(data_cell)
89
+ data_cell[:cell_style] ||= UITableViewCellStyleDefault
90
+ data_cell[:cell_identifier] ||= "Cell"
91
+ data_cell[:cell_class] ||= ProMotion::TableViewCell
92
+ data_cell
93
+ end
94
+
95
+ def remap_data_cell(data_cell)
96
+ # Re-maps legacy data cell calls
97
+ mappings = {
98
+ cell_style: :cellStyle,
99
+ cell_identifier: :cellIdentifier,
100
+ cell_class: :cellClass,
101
+ masks_to_bounds: :masksToBounds,
102
+ background_color: :backgroundColor,
103
+ selection_style: :selectionStyle,
104
+ cell_class_attributes: :cellClassAttributes,
105
+ accessory_view: :accessoryView,
106
+ accessory_type: :accessoryType,
107
+ accessory_checked: :accessoryDefault,
108
+ remote_image: :remoteImage,
109
+ subviews: :subViews
110
+ }
111
+
112
+ if data_cell[:masks_to_bounds]
113
+ PM.logger.deprecated "masks_to_bounds: (value) is deprecated. Use layer: { masks_to_bounds: (value) } instead."
114
+ data_cell[:layer] ||= {}
115
+ data_cell[:layer][:masks_to_bounds] = data_cell[:masks_to_bounds] # TODO: Deprecate and then remove this.
116
+ end
117
+
118
+ mappings.each_pair do |n, old|
119
+ if data_cell[old]
120
+ warn "[DEPRECATION] `:#{old}` is deprecated in TableScreens. Use `:#{n}`"
121
+ data_cell[n] = data_cell[old]
122
+ end
123
+ end
124
+
125
+ if data_cell[:styles] && data_cell[:styles][:textLabel]
126
+ warn "[DEPRECATION] `:textLabel` is deprecated in TableScreens. Use `:label`"
127
+ data_cell[:styles][:label] = data_cell[:styles][:textLabel]
128
+ end
129
+
130
+ data_cell
131
+ end
132
+
133
+ def create_table_cell(data_cell)
134
+ table_cell = table_view.dequeueReusableCellWithIdentifier(data_cell[:cell_identifier])
135
+
136
+ unless table_cell
137
+ table_cell = data_cell[:cell_class].alloc.initWithStyle(data_cell[:cell_style], reuseIdentifier:data_cell[:cell_identifier])
138
+ table_cell.extend ProMotion::TableViewCellModule unless table_cell.is_a?(ProMotion::TableViewCellModule)
139
+ table_cell.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin
140
+ end
141
+
142
+ table_cell.setup(data_cell)
143
+
144
+ table_cell
145
+ end
146
+
147
+ end
148
+ end
@@ -0,0 +1,156 @@
1
+ module ProMotion
2
+ module TableViewCellModule
3
+ include ViewHelper
4
+
5
+ attr_accessor :data_cell
6
+
7
+ def setup(data_cell)
8
+ self.data_cell = data_cell
9
+
10
+ # TODO: Some of these need to go away. Unnecessary overhead.
11
+ set_cell_attributes
12
+ set_background_color
13
+ set_class_attributes
14
+ set_accessory_view
15
+ set_subtitle
16
+ set_image
17
+ set_remote_image
18
+ set_subviews
19
+ set_details
20
+ set_styles
21
+ set_selection_style
22
+
23
+ self
24
+ end
25
+
26
+ def set_cell_attributes
27
+ set_attributes self, data_cell.dup.tap{ |h| h.delete(:image) }
28
+ self
29
+ end
30
+
31
+ def set_background_color
32
+ self.backgroundView = UIView.new.tap{|v| v.backgroundColor = data_cell[:background_color]} if data_cell[:background_color]
33
+ end
34
+
35
+ def set_class_attributes
36
+ if data_cell[:cell_class_attributes]
37
+ PM.logger.deprecated "`cell_class_attributes` is deprecated. Just add the attributes you want to set right into your cell hash."
38
+ set_attributes self, data_cell[:cell_class_attributes]
39
+ end
40
+ self
41
+ end
42
+
43
+ def set_accessory_view
44
+ if data_cell[:accessory_view]
45
+ self.accessoryView = data_cell[:accessory_view]
46
+ self.accessoryView.autoresizingMask = UIViewAutoresizingFlexibleWidth
47
+ end
48
+
49
+ if data_cell[:accessory] && data_cell[:accessory] == :switch
50
+ switch_view = UISwitch.alloc.initWithFrame(CGRectZero)
51
+ switch_view.addTarget(self, action: "accessory_toggled_switch:", forControlEvents:UIControlEventValueChanged)
52
+ switch_view.on = true if data_cell[:accessory_checked]
53
+ self.accessoryView = switch_view
54
+ end
55
+
56
+ self
57
+ end
58
+
59
+ def set_subtitle
60
+ if data_cell[:subtitle] && self.detailTextLabel
61
+ self.detailTextLabel.text = data_cell[:subtitle]
62
+ self.detailTextLabel.backgroundColor = UIColor.clearColor
63
+ self.detailTextLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth
64
+ end
65
+ self
66
+ end
67
+
68
+ def set_remote_image
69
+ if data_cell[:remote_image]
70
+ if self.imageView.respond_to?("setImageWithURL:placeholderImage:")
71
+ url = data_cell[:remote_image][:url]
72
+ url = NSURL.URLWithString(url) unless url.is_a?(NSURL)
73
+ placeholder = data_cell[:remote_image][:placeholder]
74
+ placeholder = UIImage.imageNamed(placeholder) if placeholder.is_a?(String)
75
+
76
+ self.image_size = data_cell[:remote_image][:size] if data_cell[:remote_image][:size] && self.respond_to?("image_size=")
77
+ self.imageView.setImageWithURL(url, placeholderImage: placeholder)
78
+ self.imageView.layer.masksToBounds = true
79
+ self.imageView.layer.cornerRadius = data_cell[:remote_image][:radius] if data_cell[:remote_image].has_key?(:radius)
80
+ else
81
+ PM.logger.error "ProMotion Warning: to use remote_image with TableScreen you need to include the CocoaPod 'SDWebImage'."
82
+ end
83
+ end
84
+ self
85
+ end
86
+
87
+ def set_image
88
+ if data_cell[:image]
89
+
90
+ cell_image = data_cell[:image].is_a?(Hash) ? data_cell[:image][:image] : data_cell[:image]
91
+ cell_image = UIImage.imageNamed(cell_image) if cell_image.is_a?(String)
92
+
93
+ self.imageView.layer.masksToBounds = true
94
+ self.imageView.image = cell_image
95
+ self.imageView.layer.cornerRadius = data_cell[:image][:radius] if data_cell[:image].is_a?(Hash) && data_cell[:image][:radius]
96
+ end
97
+ self
98
+ end
99
+
100
+ def set_subviews
101
+ tag_number = 0
102
+ Array(data_cell[:subviews]).each do |view|
103
+ # Remove an existing view at that tag number
104
+ tag_number += 1
105
+ existing_view = self.viewWithTag(tag_number)
106
+ existing_view.removeFromSuperview if existing_view
107
+
108
+ # Add the subview if it exists
109
+ if view
110
+ view.tag = tag_number
111
+ self.addSubview view
112
+ end
113
+ end
114
+ self
115
+ end
116
+
117
+ def set_details
118
+ if data_cell[:details]
119
+ self.addSubview data_cell[:details][:image]
120
+ end
121
+ self
122
+ end
123
+
124
+ def set_styles
125
+ if data_cell[:styles] && data_cell[:styles][:label] && data_cell[:styles][:label][:frame]
126
+ ui_label = false
127
+ self.contentView.subviews.each do |view|
128
+ if view.is_a? UILabel
129
+ ui_label = true
130
+ view.text = data_cell[:styles][:label][:text]
131
+ end
132
+ end
133
+
134
+ unless ui_label == true
135
+ label ||= UILabel.alloc.initWithFrame(CGRectZero)
136
+ set_attributes label, data_cell[:styles][:label]
137
+ self.contentView.addSubview label
138
+ end
139
+
140
+ # TODO: What is this and why is it necessary?
141
+ self.textLabel.textColor = UIColor.clearColor
142
+ else
143
+ cell_title = data_cell[:title]
144
+ cell_title ||= ""
145
+ self.textLabel.backgroundColor = UIColor.clearColor
146
+ self.textLabel.text = cell_title
147
+ end
148
+
149
+ self
150
+ end
151
+
152
+ def set_selection_style
153
+ self.selectionStyle = UITableViewCellSelectionStyleNone if data_cell[:no_select]
154
+ end
155
+ end
156
+ end
@@ -3,13 +3,14 @@ module ProMotion
3
3
  # Just make sure to implement the Obj-C methods in cocoatouch/TableViewController.rb.
4
4
  class TableScreen < TableViewController
5
5
  include ProMotion::TableScreenModule
6
+ # Includes PM::PlainTable already
6
7
  end
7
8
 
8
9
  class GroupedTableScreen < TableScreen
9
- include ProMotion::MotionTable::GroupedTable
10
+ include ProMotion::GroupedTable
10
11
  end
11
12
 
12
13
  class SectionedTableScreen < TableScreen
13
- include ProMotion::MotionTable::SectionedTable
14
+ include ProMotion::SectionedTable
14
15
  end
15
16
  end
@@ -1,3 +1,3 @@
1
1
  module ProMotion
2
- VERSION = "0.6.5" unless defined?(ProMotion::VERSION)
2
+ VERSION = "0.7.0" unless defined?(ProMotion::VERSION)
3
3
  end
@@ -0,0 +1,66 @@
1
+ describe "ProMotion::Screen functional" do
2
+ tests PM::Screen
3
+
4
+ # Override controller to properly instantiate
5
+ def controller
6
+ rotate_device to: :portrait, button: :bottom
7
+ @controller ||= FunctionalScreen.new(nav_bar: true)
8
+ @controller.main_controller
9
+ end
10
+
11
+ after do
12
+ @controller = nil
13
+ end
14
+
15
+ it "should have a navigation bar" do
16
+ view("Functional").should.be.kind_of UINavigationItemView
17
+ end
18
+
19
+ it "should allow setting a left nav bar button" do
20
+ @controller.set_nav_bar_button :left, title: "Cool", action: :triggered_button
21
+ tap("Cool")
22
+ @controller.button_was_triggered.should.be.true
23
+ end
24
+
25
+ it "should allow setting a right nav bar button" do
26
+ @controller.set_nav_bar_button :right, title: "Cool2", action: :triggered_button
27
+ tap("Cool2")
28
+ @controller.button_was_triggered.should.be.true
29
+ end
30
+
31
+ it "should allow opening another screen in the same nav bar and have a back button that is operational" do
32
+ @controller.open BasicScreen
33
+
34
+ wait 0.5 do
35
+
36
+ view("Basic").should.be.kind_of UINavigationItemView
37
+ view("Functional").should.be.kind_of UINavigationItemButtonView
38
+
39
+ tap("Functional")
40
+ wait 0.5 do
41
+ view("Functional").should.be.kind_of UINavigationItemView
42
+ end
43
+
44
+ end
45
+ end
46
+
47
+ it "should allow opening and closing a modal screen" do
48
+ @basic = BasicScreen.new(nav_bar: true)
49
+ wait 0.1 do
50
+ @controller.open_modal @basic
51
+
52
+ wait 0.6 do
53
+
54
+ view("Basic").should.be.kind_of UINavigationItemView
55
+ @basic.close
56
+
57
+ wait 0.6 do
58
+ @basic = nil
59
+ view("Functional").should.be.kind_of UINavigationItemView
60
+ end
61
+
62
+ end
63
+ end
64
+ end
65
+
66
+ end
@@ -0,0 +1,66 @@
1
+ describe "Split screen functional" do
2
+ tests PM::SplitViewController
3
+
4
+ # Override controller to properly instantiate
5
+ def controller
6
+ @app ||= TestDelegate.new
7
+ @master = MasterScreen.new(nav_bar: true)
8
+ @detail = DetailScreen.new(nav_bar: true)
9
+ @controller ||= @app.create_split_screen @master, @detail
10
+ end
11
+
12
+ before do
13
+ rotate_device to: :landscape, button: :right
14
+ end
15
+
16
+ after do
17
+ rotate_device to: :portrait, button: :bottom
18
+ end
19
+
20
+ it "should allow opening a detail view from the master view" do
21
+
22
+ @master.open BasicScreen.new(nav_bar: true), in_detail: true
23
+
24
+ wait 0.75 do
25
+ view("Master").should.be.kind_of UINavigationItemView
26
+ view("Basic").should.be.kind_of UINavigationItemView
27
+ views(UINavigationItemView).each { |v| v.title.should.not == "Detail" }
28
+ end
29
+
30
+ end
31
+
32
+ it "should allow opening another view from the master view" do
33
+
34
+ @master.open BasicScreen
35
+
36
+ wait 0.75 do
37
+ view("Basic").should.be.kind_of UINavigationItemView
38
+ view("Detail").should.be.kind_of UINavigationItemView
39
+ end
40
+
41
+ end
42
+
43
+ it "should allow opening a master view from the detail view" do
44
+
45
+ @detail.open BasicScreen.new(nav_bar: true), in_master: true
46
+
47
+ wait 0.75 do
48
+ view("Basic").should.be.kind_of UINavigationItemView
49
+ view("Detail").should.be.kind_of UINavigationItemView
50
+ views(UINavigationItemView).each { |v| v.title.should.not == "Master" }
51
+ end
52
+
53
+ end
54
+
55
+ it "should allow opening another view from the detail view" do
56
+
57
+ @detail.open BasicScreen
58
+
59
+ wait 0.75 do
60
+ view("Basic").should.be.kind_of UINavigationItemView
61
+ view("Master").should.be.kind_of UINavigationItemView
62
+ end
63
+
64
+ end
65
+
66
+ end