ProMotion 0.7.8 → 1.0.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 (91) hide show
  1. data/.gitignore +2 -1
  2. data/.travis.yml +1 -1
  3. data/ProMotion.gemspec +2 -0
  4. data/README.md +51 -449
  5. data/Rakefile +11 -1
  6. data/app/screens/basic_screen.rb +0 -24
  7. data/lib/ProMotion/cocoatouch/{NavigationController.rb → navigation_controller.rb} +0 -0
  8. data/lib/ProMotion/cocoatouch/split_view_controller.rb +29 -0
  9. data/lib/ProMotion/cocoatouch/tab_bar_controller.rb +43 -0
  10. data/lib/ProMotion/cocoatouch/{TableViewCell.rb → table_view_cell.rb} +0 -1
  11. data/lib/ProMotion/cocoatouch/{TableViewController.rb → table_view_controller.rb} +0 -0
  12. data/lib/ProMotion/cocoatouch/{ViewController.rb → view_controller.rb} +6 -1
  13. data/lib/ProMotion/{screen_helpers → containers}/split_screen.rb +0 -2
  14. data/lib/ProMotion/containers/tabs.rb +95 -0
  15. data/lib/ProMotion/delegate/delegate.rb +2 -13
  16. data/lib/ProMotion/delegate/{delegate_helper.rb → delegate_module.rb} +29 -16
  17. data/lib/ProMotion/delegate/delegate_notifications.rb +17 -8
  18. data/lib/ProMotion/delegate/delegate_parent.rb +11 -0
  19. data/lib/ProMotion/extensions/conversions.rb +20 -0
  20. data/lib/ProMotion/{helpers/logger.rb → logger.rb} +0 -0
  21. data/lib/ProMotion/map/map_screen.rb +6 -0
  22. data/lib/ProMotion/map/map_screen_annotation.rb +56 -0
  23. data/lib/ProMotion/map/map_screen_module.rb +207 -0
  24. data/lib/ProMotion/{push_notifications → push_notification}/push_notification.rb +13 -6
  25. data/lib/ProMotion/{screens → screen}/screen.rb +1 -1
  26. data/lib/ProMotion/{screens/_screen_module.rb → screen/screen_module.rb} +76 -51
  27. data/lib/ProMotion/{screen_helpers → screen}/screen_navigation.rb +8 -12
  28. data/lib/ProMotion/{screens/_tables → table/cell}/table_view_cell_module.rb +18 -27
  29. data/lib/ProMotion/table/data/table_data.rb +98 -0
  30. data/lib/ProMotion/table/extensions/indexable.rb +9 -0
  31. data/lib/ProMotion/table/extensions/refreshable.rb +45 -0
  32. data/lib/ProMotion/table/extensions/searchable.rb +61 -0
  33. data/lib/ProMotion/table/grouped_table.rb +9 -0
  34. data/lib/ProMotion/table/grouped_table_screen.rb +6 -0
  35. data/lib/ProMotion/table/table.rb +312 -0
  36. data/lib/ProMotion/table/table_screen.rb +6 -0
  37. data/lib/ProMotion/{screens/_compatibility → thirdparty}/formotion_screen.rb +18 -5
  38. data/lib/ProMotion/version.rb +1 -1
  39. data/lib/ProMotion/view/styling.rb +137 -0
  40. data/lib/ProMotion/web/web_screen.rb +6 -0
  41. data/lib/ProMotion/web/web_screen_module.rb +155 -0
  42. data/resources/WebScreen.html +6 -0
  43. data/resources/test.jpeg +0 -0
  44. data/spec/functional/func_map_screen_spec.rb +105 -0
  45. data/spec/functional/func_screen_spec.rb +54 -7
  46. data/spec/functional/func_searchable_table_spec.rb +1 -1
  47. data/spec/functional/func_tab_bar_spec.rb +78 -0
  48. data/spec/functional/func_table_screen_spec.rb +61 -14
  49. data/spec/functional/func_web_screen_spec.rb +51 -0
  50. data/spec/helpers/map_screen.rb +51 -0
  51. data/spec/helpers/present_screen.rb +26 -0
  52. data/spec/helpers/tab_screen.rb +4 -0
  53. data/spec/helpers/table_screen.rb +12 -3
  54. data/spec/helpers/table_screen_formotion.rb +25 -0
  55. data/spec/helpers/table_screen_indexable.rb +13 -0
  56. data/spec/helpers/test_delegate.rb +28 -0
  57. data/spec/helpers/web_screen.rb +22 -0
  58. data/spec/unit/delegate_spec.rb +53 -4
  59. data/spec/unit/map_spec.rb +48 -0
  60. data/spec/unit/screen_helpers_spec.rb +24 -16
  61. data/spec/unit/screen_spec.rb +22 -18
  62. data/spec/unit/split_screen_in_tab_bar_spec.rb +2 -2
  63. data/spec/unit/split_screen_open_screen_spec.rb +15 -10
  64. data/spec/unit/split_screen_spec.rb +2 -2
  65. data/spec/unit/tab_spec.rb +41 -0
  66. data/spec/unit/tables/formotion_screen_spec.rb +16 -0
  67. data/spec/unit/tables/table_indexable_spec.rb +12 -0
  68. data/spec/unit/tables/table_module_spec.rb +24 -9
  69. data/spec/unit/tables/table_screen_spec.rb +1 -1
  70. data/spec/unit/tables/table_view_cell_spec.rb +9 -8
  71. data/spec/unit/view_helper_spec.rb +2 -2
  72. data/spec/unit/web_spec.rb +106 -0
  73. metadata +96 -35
  74. data/lib/ProMotion/cocoatouch/SplitViewController.rb +0 -23
  75. data/lib/ProMotion/helpers/console.rb +0 -29
  76. data/lib/ProMotion/helpers/measure_helper.rb +0 -20
  77. data/lib/ProMotion/helpers/system_helper.rb +0 -29
  78. data/lib/ProMotion/helpers/view_helper.rb +0 -82
  79. data/lib/ProMotion/screen_helpers/screen_elements.rb +0 -36
  80. data/lib/ProMotion/screen_helpers/screen_tabs.rb +0 -95
  81. data/lib/ProMotion/screens/_table_screen_module.rb +0 -47
  82. data/lib/ProMotion/screens/_tables/_refreshable_table.rb +0 -45
  83. data/lib/ProMotion/screens/_tables/_searchable_table.rb +0 -60
  84. data/lib/ProMotion/screens/_tables/_sectioned_table.rb +0 -5
  85. data/lib/ProMotion/screens/_tables/_table.rb +0 -169
  86. data/lib/ProMotion/screens/_tables/grouped_table.rb +0 -16
  87. data/lib/ProMotion/screens/_tables/plain_table.rb +0 -17
  88. data/lib/ProMotion/screens/_tables/table_data.rb +0 -175
  89. data/lib/ProMotion/screens/behaves_like_screen.rb +0 -10
  90. data/lib/ProMotion/screens/table_screen.rb +0 -16
  91. data/spec/unit/ios_version_spec.rb +0 -28
@@ -1,23 +0,0 @@
1
- class SplitViewController < UISplitViewController
2
- def master_screen
3
- s = self.viewControllers.first
4
- s.respond_to?(:visibleViewController) ? s.visibleViewController : s
5
- end
6
- def detail_screen
7
- s = self.viewControllers.last
8
- s.respond_to?(:visibleViewController) ? s.visibleViewController : s
9
- end
10
- def master_screen=(s)
11
- self.viewControllers = [s.pm_main_controller, self.viewControllers.last]
12
- end
13
- def detail_screen=(s)
14
- # set the button from the old detail screen to the new one
15
- button = detail_screen.navigationItem.leftBarButtonItem
16
- s.navigationItem.leftBarButtonItem = button
17
-
18
- self.viewControllers = [self.viewControllers.first, s.pm_main_controller]
19
- end
20
- def screens=(s_array)
21
- self.viewControllers = s_array
22
- end
23
- end
@@ -1,29 +0,0 @@
1
- module ProMotion
2
- class Console
3
- NAME = "RubyMotion::Console: "
4
- DEFAULT_COLOR = [ '', '' ]
5
- RED_COLOR = [ "\e[0;31m", "\e[0m" ] # Must be in double quotes
6
- GREEN_COLOR = [ "\e[0;32m", "\e[0m" ]
7
- PURPLE_COLOR = [ "\e[0;35m", "\e[0m" ]
8
-
9
- class << self
10
- def log(log, with_color:color)
11
- return if defined?(RUBYMOTION_ENV) && RUBYMOTION_ENV == "test"
12
- PM.logger.deprecated "ProMotion::Console.log is deprecated. Use PM.logger (see README)"
13
- puts color[0] + NAME + log + color[1]
14
- end
15
-
16
- def log(log, withColor:color)
17
- return if defined?(RUBYMOTION_ENV) && RUBYMOTION_ENV == "test"
18
- PM.logger.deprecated "ProMotion::Console.log is deprecated. Use PM.logger (see README)"
19
- self.log(log, with_color:color)
20
- end
21
-
22
- def log(log)
23
- return if defined?(RUBYMOTION_ENV) && RUBYMOTION_ENV == "test"
24
- PM.logger.deprecated "ProMotion::Console.log is deprecated. Use PM.logger (see README)"
25
- log(log, with_color: DEFAULT_COLOR)
26
- end
27
- end
28
- end
29
- end
@@ -1,20 +0,0 @@
1
- module ProMotion
2
- class MeasureHelper
3
- class << self
4
- def content_height(view)
5
- PM.logger.deprecated "`MeasureHelper.content_height` is deprecated. Include the module `ScreenElements` to get access to this method (already included in Screen)."
6
-
7
- height = 0
8
- view.subviews.each do |subview|
9
- next if subview.isHidden
10
- y = subview.frame.origin.y
11
- h = subview.frame.size.height
12
- if (y + h) > height
13
- height = y + h
14
- end
15
- end
16
- height
17
- end
18
- end
19
- end
20
- end
@@ -1,29 +0,0 @@
1
- module ProMotion
2
- module SystemHelper
3
- module_function
4
-
5
- def ios_version
6
- UIDevice.currentDevice.systemVersion
7
- end
8
-
9
- def ios_version_is?(version)
10
- ios_version == version
11
- end
12
-
13
- def ios_version_greater?(version)
14
- ios_version > version
15
- end
16
-
17
- def ios_version_greater_eq?(version)
18
- ios_version >= version
19
- end
20
-
21
- def ios_version_less?(version)
22
- ios_version < version
23
- end
24
-
25
- def ios_version_less_eq?(version)
26
- ios_version <= version
27
- end
28
- end
29
- end
@@ -1,82 +0,0 @@
1
- module ProMotion
2
- module ViewHelper
3
- def set_attributes(element, args = {})
4
- args.each { |k, v| set_attribute(element, k, v) }
5
- element
6
- end
7
-
8
- def set_attribute(element, k, v)
9
- return element unless element
10
-
11
- if v.is_a?(Hash) && element.respond_to?(k)
12
- sub_element = element.send(k)
13
- set_attributes(sub_element, v) if sub_element
14
- elsif element.respond_to?("#{k}=")
15
- element.send("#{k}=", v)
16
- elsif v.is_a?(Array) && element.respond_to?("#{k}") && element.method("#{k}").arity == v.length
17
- element.send("#{k}", *v)
18
- else
19
- # Doesn't respond. Check if snake case.
20
- if k.to_s.include?("_")
21
- set_attribute(element, objective_c_method_name(k), v)
22
- end
23
- end
24
- element
25
- end
26
-
27
- def objective_c_method_name(meth)
28
- meth.split('_').inject([]){ |buffer,e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
29
- end
30
-
31
- def set_easy_attributes(parent, element, args={})
32
- attributes = {}
33
-
34
- if args[:resize]
35
- attributes[:autoresizingMask] = UIViewAutoresizingNone
36
- attributes[:autoresizingMask] |= UIViewAutoresizingFlexibleLeftMargin if args[:resize].include?(:left)
37
- attributes[:autoresizingMask] |= UIViewAutoresizingFlexibleRightMargin if args[:resize].include?(:right)
38
- attributes[:autoresizingMask] |= UIViewAutoresizingFlexibleTopMargin if args[:resize].include?(:top)
39
- attributes[:autoresizingMask] |= UIViewAutoresizingFlexibleBottomMargin if args[:resize].include?(:bottom)
40
- attributes[:autoresizingMask] |= UIViewAutoresizingFlexibleWidth if args[:resize].include?(:width)
41
- attributes[:autoresizingMask] |= UIViewAutoresizingFlexibleHeight if args[:resize].include?(:height)
42
- end
43
-
44
- if [:left, :top, :width, :height].select{ |a| args[a] && args[a] != :auto }.length == 4
45
- attributes[:frame] = CGRectMake(args[:left], args[:top], args[:width], args[:height])
46
- end
47
-
48
- set_attributes element, attributes
49
- element
50
- end
51
-
52
- def frame_from_array(array)
53
- PM.logger.deprecated "`frame_from_array` is deprecated and will be removed. Use RubyMotion's built-in [[x, y], [width, height]] or CGRectMake(x, y, w, h)."
54
- return CGRectMake(array[0], array[1], array[2], array[3]) if array.length == 4
55
- PM.logger.error "frame_from_array expects an array with four elements: [x, y, width, height]"
56
- CGRectZero.dup
57
- end
58
-
59
- def content_height(view)
60
- height = 0
61
- view.subviews.each do |sub_view|
62
- next if sub_view.isHidden
63
- y = sub_view.frame.origin.y
64
- h = sub_view.frame.size.height
65
- if (y + h) > height
66
- height = y + h
67
- end
68
- end
69
- height
70
- end
71
-
72
- def closest_parent(type, this_view = nil)
73
- # iterate up the view hierarchy to find the parent element of "type" containing this view
74
- this_view ||= self.superview
75
- while this_view != nil do
76
- return this_view if this_view.is_a? type
77
- this_view = this_view.superview
78
- end
79
- nil
80
- end
81
- end
82
- end
@@ -1,36 +0,0 @@
1
- module ProMotion
2
- module ScreenElements
3
- include ProMotion::ViewHelper
4
-
5
- def add(element, attrs = {})
6
- add_to self.view, element, attrs
7
- end
8
- alias :add_element :add
9
- alias :add_view :add
10
-
11
- def remove(element)
12
- element.removeFromSuperview
13
- element = nil
14
- end
15
- alias :remove_element :remove
16
- alias :remove_view :remove
17
-
18
- def add_to(parent_element, element, attrs = {})
19
- parent_element.addSubview element
20
- if attrs && attrs.length > 0
21
- set_attributes(element, attrs)
22
- set_easy_attributes(parent_element, element, attrs)
23
- end
24
- element
25
- end
26
-
27
- def bounds
28
- return self.view.bounds
29
- end
30
-
31
- def frame
32
- return self.view.frame
33
- end
34
-
35
- end
36
- end
@@ -1,95 +0,0 @@
1
- module ProMotion
2
- module ScreenTabs
3
- def tab_bar_controller(*screens)
4
- tab_bar_controller = UITabBarController.alloc.init
5
-
6
- view_controllers = []
7
- tag_index = 0
8
-
9
- screens.map! { |s| s.respond_to?(:new) ? s.new : s } # Initialize any classes
10
-
11
- screens.each do |s|
12
- s = s.new if s.respond_to?(:new)
13
-
14
- s.tabBarItem.tag = tag_index
15
-
16
- s.parent_screen = self if self.is_a?(UIViewController) && s.respond_to?("parent_screen=")
17
- s.tab_bar = tab_bar_controller if s.respond_to?("tab_bar=")
18
-
19
- view_controllers << s.pm_main_controller
20
-
21
- tag_index += 1
22
-
23
- s.on_load if s.respond_to?(:on_load)
24
- end
25
-
26
- tab_bar_controller.viewControllers = view_controllers
27
- tab_bar_controller
28
- end
29
-
30
- # Open a UITabBarController with the specified screens as the
31
- # root view controller of the current app.
32
- # @param [Array] A comma-delimited list of screen classes or instances.
33
- # @return [UITabBarController]
34
- def open_tab_bar(*screens)
35
- tab_bar = tab_bar_controller(*screens)
36
-
37
- a = self.respond_to?(:open_root_screen) ? self : UIApplication.sharedApplication.delegate
38
-
39
- a.open_root_screen(tab_bar)
40
- tab_bar
41
- end
42
-
43
- def open_tab(tab)
44
- if tab.is_a? String
45
- return self.select(self.tab_bar, title: tab)
46
- elsif tab.is_a? Numeric
47
- tab_bar_controller.selectedIndex = tab
48
- return tab_bar_controller.viewControllers[tab]
49
- else
50
- $stderr.puts "Unable to open tab #{tab.to_s} because it isn't a string."
51
- end
52
- end
53
-
54
- def create_tab_bar_icon(icon, tag)
55
- return UITabBarItem.alloc.initWithTabBarSystemItem(icon, tag: tag)
56
- end
57
-
58
- def create_tab_bar_icon_custom(title, image_name, tag)
59
- icon_image = UIImage.imageNamed(image_name)
60
- return UITabBarItem.alloc.initWithTitle(title, image:icon_image, tag:tag)
61
- end
62
-
63
- def create_tab_bar_item(tab={})
64
- title = "Untitled"
65
- title = tab[:title] if tab[:title]
66
- tab[:tag] ||= @current_tag ||= 0
67
- @current_tag = tab[:tag] + 1
68
-
69
- tab_bar_item = create_tab_bar_icon(tab[:system_icon], tab[:tag]) if tab[:system_icon]
70
- tab_bar_item = create_tab_bar_icon_custom(title, tab[:icon], tab[:tag]) if tab[:icon]
71
-
72
- tab_bar_item.badgeValue = tab[:badge_number].to_s unless tab[:badge_number].nil? || tab[:badge_number] <= 0
73
-
74
- return tab_bar_item
75
- end
76
-
77
- def select(tab_bar_controller, title: title)
78
- root_controller = nil
79
- tab_bar_controller.viewControllers.each do |vc|
80
- if vc.tabBarItem.title == title
81
- tab_bar_controller.selectedViewController = vc
82
- root_controller = vc
83
- break
84
- end
85
- end
86
- root_controller
87
- end
88
-
89
- def replace_current_item(tab_bar_controller, view_controller: vc)
90
- controllers = NSMutableArray.arrayWithArray(tab_bar_controller.viewControllers)
91
- controllers.replaceObjectAtIndex(tab_bar_controller.selectedIndex, withObject: vc)
92
- tab_bar_controller.viewControllers = controllers
93
- end
94
- end
95
- end
@@ -1,47 +0,0 @@
1
- module ProMotion
2
- module TableScreenModule
3
- include PlainTable
4
- include SearchableTable
5
- include RefreshableTable
6
- include ScreenModule
7
-
8
- def update_table_data
9
- self.update_table_view_data(table_data)
10
- end
11
-
12
- module TableClassMethods
13
- # Searchable
14
- def searchable(params={})
15
- @searchable_params = params
16
- @searchable = true
17
- end
18
-
19
- def get_searchable_params
20
- @searchable_params ||= nil
21
- end
22
-
23
- def get_searchable
24
- @searchable ||= false
25
- end
26
-
27
- # Refreshable
28
- def refreshable(params = {})
29
- @refreshable_params = params
30
- @refreshable = true
31
- end
32
-
33
- def get_refreshable
34
- @refreshable ||= false
35
- end
36
-
37
- def get_refreshable_params
38
- @refreshable_params ||= nil
39
- end
40
-
41
- end
42
- def self.included(base)
43
- base.extend(ClassMethods)
44
- base.extend(TableClassMethods)
45
- end
46
- end
47
- end
@@ -1,45 +0,0 @@
1
- module ProMotion
2
- module RefreshableTable
3
- def make_refreshable(params={})
4
- pull_message = params[:pull_message] || "Pull to refresh"
5
- @refreshing = params[:refreshing] || "Refreshing data..."
6
- @updated_format = params[:updated_format] || "Last updated at %s"
7
- @updated_time_format = params[:updated_time_format] || "%l:%M %p"
8
- @refreshable_callback = params[:callback]|| :on_refresh
9
-
10
- @refresh_control = UIRefreshControl.alloc.init
11
- @refresh_control.attributedTitle = NSAttributedString.alloc.initWithString(pull_message)
12
- @refresh_control.addTarget(self, action:'refreshView:', forControlEvents:UIControlEventValueChanged)
13
- self.refreshControl = @refresh_control
14
- end
15
- alias :makeRefreshable :make_refreshable
16
-
17
- def start_refreshing
18
- return unless @refresh_control
19
-
20
- @refresh_control.beginRefreshing
21
- end
22
- alias :begin_refreshing :start_refreshing
23
-
24
- def end_refreshing
25
- return unless @refresh_control
26
-
27
- @refresh_control.attributedTitle = NSAttributedString.alloc.initWithString(sprintf(@updated_format, Time.now.strftime(@updated_time_format)))
28
- @refresh_control.endRefreshing
29
- end
30
- alias :stop_refreshing :end_refreshing
31
-
32
- ######### iOS methods, headless camel case #######
33
-
34
- # UIRefreshControl Delegates
35
- def refreshView(refresh)
36
- refresh.attributedTitle = NSAttributedString.alloc.initWithString(@refreshing)
37
- if @refreshable_callback && self.respond_to?(@refreshable_callback)
38
- self.send(@refreshable_callback)
39
- else
40
- PM.logger.warn "You must implement the '#{@refreshable_callback}' method in your TableScreen."
41
- end
42
- end
43
-
44
- end
45
- end
@@ -1,60 +0,0 @@
1
- module ProMotion
2
- module SearchableTable
3
-
4
- def make_searchable(params={})
5
- params = set_searchable_param_defaults(params)
6
-
7
- search_bar = create_search_bar(params)
8
-
9
- if params[:search_bar] && params[:search_bar][:placeholder]
10
- search_bar.placeholder = params[:search_bar][:placeholder]
11
- end
12
-
13
- @table_search_display_controller = UISearchDisplayController.alloc.initWithSearchBar(search_bar, contentsController: params[:content_controller])
14
- @table_search_display_controller.delegate = params[:delegate]
15
- @table_search_display_controller.searchResultsDataSource = params[:data_source]
16
- @table_search_display_controller.searchResultsDelegate = params[:search_results_delegate]
17
-
18
- self.table_view.tableHeaderView = search_bar
19
- end
20
- alias :makeSearchable :make_searchable
21
-
22
- def set_searchable_param_defaults(params)
23
- params[:content_controller] ||= params[:contentController]
24
- params[:data_source] ||= params[:searchResultsDataSource]
25
- params[:search_results_delegate] ||= params[:searchResultsDelegate]
26
-
27
- params[:frame] ||= CGRectMake(0, 0, 320, 44) # TODO: Don't hardcode this...
28
- params[:content_controller] ||= self
29
- params[:delegate] ||= self
30
- params[:data_source] ||= self
31
- params[:search_results_delegate] ||= self
32
- params
33
- end
34
-
35
- def create_search_bar(params)
36
- search_bar = UISearchBar.alloc.initWithFrame(params[:frame])
37
- search_bar.autoresizingMask = UIViewAutoresizingFlexibleWidth
38
- search_bar
39
- end
40
-
41
- ######### iOS methods, headless camel case #######
42
-
43
- def searchDisplayController(controller, shouldReloadTableForSearchString:search_string)
44
- @promotion_table_data.search(search_string)
45
- true
46
- end
47
-
48
- def searchDisplayControllerWillEndSearch(controller)
49
- @promotion_table_data.stop_searching
50
- @promotion_table_data_data = nil
51
- self.table_view.setScrollEnabled true
52
- self.table_view.reloadData
53
- end
54
-
55
- def searchDisplayControllerWillBeginSearch(controller)
56
- self.table_view.setScrollEnabled false
57
- end
58
-
59
- end
60
- end