ProMotion 0.7.8 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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