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
data/Rakefile CHANGED
@@ -11,7 +11,8 @@ require 'ProMotion'
11
11
  Motion::Project::App.setup do |app|
12
12
  app.name = 'ProMotionTest'
13
13
  app.version = "0.99.0"
14
- app.redgreen_style = :focused # :focused, :full
14
+ app.redgreen_style = :full # :focused, :full
15
+ app.frameworks += %w(CoreLocation MapKit)
15
16
 
16
17
  # Devices
17
18
  app.deployment_target = "6.0"
@@ -40,6 +41,10 @@ namespace :spec do
40
41
  App.config.instance_variable_set("@spec_files", spec_files)
41
42
  Rake::Task["simulator"].invoke
42
43
  end
44
+
45
+ task :func do
46
+ Rake::Task["spec:functional"].invoke
47
+ end
43
48
 
44
49
  task :functional do
45
50
  App.config.spec_mode = true
@@ -48,4 +53,9 @@ namespace :spec do
48
53
  App.config.instance_variable_set("@spec_files", spec_files)
49
54
  Rake::Task["simulator"].invoke
50
55
  end
56
+
57
+ end
58
+
59
+ task :sim_close do
60
+ sh "osascript -e 'tell application \"iphone simulator\" to quit'"
51
61
  end
@@ -1,27 +1,3 @@
1
1
  class BasicScreen < PM::Screen
2
2
  title "Basic"
3
-
4
- def on_init
5
- # Fires right after the screen is initialized
6
- end
7
-
8
- def on_load
9
- # Fires just before a screen is opened for the first time.
10
- end
11
-
12
- def will_appear
13
- # Fires every time the screen will appear
14
- end
15
-
16
- def on_appear
17
- # Fires just after the screen appears somewhere (after animations are complete)
18
- end
19
-
20
- def will_disappear
21
- # Fires just before the screen will disappear
22
- end
23
-
24
- def on_disappear
25
- # Fires after the screen is fully hidden
26
- end
27
3
  end
@@ -0,0 +1,29 @@
1
+ module ProMotion
2
+ class SplitViewController < UISplitViewController
3
+ def master_screen
4
+ s = self.viewControllers.first
5
+ s.respond_to?(:visibleViewController) ? s.visibleViewController : s
6
+ end
7
+
8
+ def detail_screen
9
+ s = self.viewControllers.last
10
+ s.respond_to?(:visibleViewController) ? s.visibleViewController : s
11
+ end
12
+
13
+ def master_screen=(s)
14
+ self.viewControllers = [ (s.navigationController || s), self.viewControllers.last]
15
+ end
16
+
17
+ def detail_screen=(s)
18
+ # set the button from the old detail screen to the new one
19
+ button = detail_screen.navigationItem.leftBarButtonItem
20
+ s.navigationItem.leftBarButtonItem = button
21
+
22
+ self.viewControllers = [self.viewControllers.first, (s.navigationController || s)]
23
+ end
24
+
25
+ def screens=(s_array)
26
+ self.viewControllers = s_array
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,43 @@
1
+ module ProMotion
2
+ class TabBarController < UITabBarController
3
+
4
+ def self.new(*screens)
5
+ tab_bar_controller = alloc.init
6
+
7
+ view_controllers = []
8
+
9
+ screens = screens.flatten.map { |s| s.respond_to?(:new) ? s.new : s } # Initialize any classes
10
+
11
+ tag_index = 0
12
+ screens.each do |s|
13
+ s.tabBarItem.tag = tag_index
14
+ s.tab_bar = tab_bar_controller if s.respond_to?("tab_bar=")
15
+ view_controllers << (s.navigationController || s)
16
+ tag_index += 1
17
+ end
18
+
19
+ tab_bar_controller.viewControllers = view_controllers
20
+ tab_bar_controller
21
+ end
22
+
23
+ def open_tab(tab)
24
+ if tab.is_a? String
25
+ selected_tab_vc = find_tab(tab)
26
+ elsif tab.is_a? Numeric
27
+ selected_tab_vc = viewControllers[tab]
28
+ end
29
+
30
+ if selected_tab_vc
31
+ self.selectedViewController = selected_tab_vc if selected_tab_vc
32
+ else
33
+ PM.logger.error "Unable to open tab #{tab.to_s} -- not found."
34
+ nil
35
+ end
36
+ end
37
+
38
+ def find_tab(tab_title)
39
+ self.viewControllers.select{ |vc| vc.tabBarItem.title == tab_title }.first
40
+ end
41
+
42
+ end
43
+ end
@@ -15,6 +15,5 @@ module ProMotion
15
15
  self.imageView.frame = CGRectInset(f, size_inset_x, size_inset_y)
16
16
  end
17
17
  end
18
-
19
18
  end
20
19
  end
@@ -5,6 +5,11 @@ module ProMotion
5
5
  s.on_create(args) if s.respond_to?(:on_create)
6
6
  s
7
7
  end
8
+
9
+ def loadView
10
+ super
11
+ self.send(:on_load) if self.respond_to?(:on_load)
12
+ end
8
13
 
9
14
  def viewDidLoad
10
15
  super
@@ -49,4 +54,4 @@ module ProMotion
49
54
  self.on_rotate
50
55
  end
51
56
  end
52
- end
57
+ end
@@ -17,8 +17,6 @@ module ProMotion
17
17
  master = master.new if master.respond_to?(:new)
18
18
  detail = detail.new if detail.respond_to?(:new)
19
19
 
20
- [ master, detail ].map { |s| s.on_load if s.respond_to?(:on_load) }
21
-
22
20
  split = split_screen_controller master, detail
23
21
  if args.has_key?(:icon) or args.has_key?(:title)
24
22
  split.tabBarItem = create_tab_bar_item(args)
@@ -0,0 +1,95 @@
1
+ module ProMotion
2
+ module Tabs
3
+ include Conversions
4
+
5
+ attr_accessor :tab_bar, :tab_bar_item
6
+
7
+ def open_tab_bar(*screens)
8
+ self.tab_bar = PM::TabBarController.new(screens)
9
+
10
+ delegate = self.respond_to?(:open_root_screen) ? self : UIApplication.sharedApplication.delegate
11
+
12
+ delegate.open_root_screen(self.tab_bar)
13
+ self.tab_bar
14
+ end
15
+
16
+ def open_tab(tab)
17
+ self.tab_bar.open_tab(tab)
18
+ end
19
+
20
+ def set_tab_bar_item(args = {})
21
+ self.tab_bar_item = args
22
+ refresh_tab_bar_item
23
+ end
24
+
25
+ def refresh_tab_bar_item
26
+ self.tabBarItem = create_tab_bar_item(self.tab_bar_item) if self.tab_bar_item && self.respond_to?(:tabBarItem=)
27
+ end
28
+
29
+ def set_tab_bar_badge(number)
30
+ self.tab_bar_item[:badge] = number
31
+ refresh_tab_bar_item
32
+ end
33
+
34
+ def create_tab_bar_icon(icon, tag)
35
+ return UITabBarItem.alloc.initWithTabBarSystemItem(icon, tag: tag)
36
+ end
37
+
38
+ def create_tab_bar_icon_custom(title, image_name, tag)
39
+ icon_image = UIImage.imageNamed(image_name)
40
+ return UITabBarItem.alloc.initWithTitle(title, image:icon_image, tag:tag)
41
+ end
42
+
43
+ def create_tab_bar_item(tab={})
44
+ title = "Untitled"
45
+ title = tab[:title] if tab[:title]
46
+ tab[:tag] ||= @current_tag ||= 0
47
+ @current_tag = tab[:tag] + 1
48
+
49
+ tab_bar_item = create_tab_bar_icon(map_tab_symbol(tab[:system_icon]), tab[:tag]) if tab[:system_icon]
50
+ tab_bar_item = create_tab_bar_icon_custom(title, tab[:icon], tab[:tag]) if tab[:icon]
51
+
52
+ tab_bar_item.badgeValue = tab[:badge_number].to_s unless tab[:badge_number].nil? || tab[:badge_number] <= 0
53
+
54
+ return tab_bar_item
55
+ end
56
+
57
+ def replace_current_item(tab_bar_controller, view_controller: vc)
58
+ controllers = NSMutableArray.arrayWithArray(tab_bar_controller.viewControllers)
59
+ controllers.replaceObjectAtIndex(tab_bar_controller.selectedIndex, withObject: vc)
60
+ tab_bar_controller.viewControllers = controllers
61
+ end
62
+
63
+ def map_tab_symbol(symbol)
64
+ @_tab_symbols ||= {
65
+ more: UITabBarSystemItemMore,
66
+ favorites: UITabBarSystemItemFavorites,
67
+ featured: UITabBarSystemItemFeatured,
68
+ top_rated: UITabBarSystemItemTopRated,
69
+ recents: UITabBarSystemItemRecents,
70
+ contacts: UITabBarSystemItemContacts,
71
+ history: UITabBarSystemItemHistory,
72
+ bookmarks: UITabBarSystemItemBookmarks,
73
+ search: UITabBarSystemItemSearch,
74
+ downloads: UITabBarSystemItemDownloads,
75
+ most_recent: UITabBarSystemItemMostRecent,
76
+ most_viewed: UITabBarSystemItemMostViewed
77
+ }
78
+ @_tab_symbols[symbol] || symbol
79
+ end
80
+
81
+ module TabClassMethods
82
+ def tab_bar_item(args={})
83
+ @tab_bar_item = args
84
+ end
85
+ def get_tab_bar_item
86
+ @tab_bar_item
87
+ end
88
+ end
89
+
90
+ def self.included(base)
91
+ base.extend(TabClassMethods)
92
+ end
93
+
94
+ end
95
+ end
@@ -1,16 +1,5 @@
1
1
  module ProMotion
2
- class Delegate
3
-
4
- include ProMotion::ScreenTabs
5
- include ProMotion::SplitScreen if NSBundle.mainBundle.infoDictionary["UIDeviceFamily"].include?("2") # Only with iPad
6
- include ProMotion::DelegateHelper
7
- include ProMotion::DelegateNotifications
8
-
9
- end
10
-
11
- class AppDelegateParent < Delegate
12
- def self.inherited(klass)
13
- PM.logger.deprecated "PM::AppDelegateParent is deprecated. Use PM::Delegate."
14
- end
2
+ class Delegate < DelegateParent
3
+ include ProMotion::DelegateModule
15
4
  end
16
5
  end
@@ -1,28 +1,41 @@
1
1
  module ProMotion
2
- module DelegateHelper
2
+ module DelegateModule
3
+
4
+ include ProMotion::Tabs
5
+ include ProMotion::SplitScreen if NSBundle.mainBundle.infoDictionary["UIDeviceFamily"].include?("2") # Only with iPad
6
+ include ProMotion::DelegateNotifications
3
7
 
4
8
  attr_accessor :window, :aps_notification, :home_screen
5
9
 
6
- def application(application, didFinishLaunchingWithOptions:launch_options)
10
+ def application(application, willFinishLaunchingWithOptions:launch_options)
11
+ will_load(application, launch_options) if respond_to?(:will_load)
12
+ end
7
13
 
14
+ def application(application, didFinishLaunchingWithOptions:launch_options)
8
15
  apply_status_bar
9
-
10
16
  on_load application, launch_options
11
-
12
17
  check_for_push_notification launch_options
18
+ super rescue true # Can cause error message if no super is found, but it's harmless. Ignore.
19
+ end
13
20
 
14
- # This will work when RubyMotion fixes a bug.
15
- # defined?(super) ? super : true
21
+ def applicationDidBecomeActive(application)
22
+ on_activate if respond_to?(:on_activate)
23
+ end
16
24
 
17
- # Workaround for now. Will display a NoMethodError, but ignore.
18
- super rescue true
19
- PM.logger.info "You can ignore the NoMethodError -- this is a RubyMotion bug that should be fixed soon."
25
+ def applicationWillResignActive(application)
26
+ will_deactivate if respond_to?(:will_deactivate)
20
27
  end
21
28
 
22
- def applicationWillTerminate(application)
29
+ def applicationDidEnterBackground(application)
30
+ on_enter_background if respond_to?(:on_enter_background)
31
+ end
23
32
 
24
- on_unload if respond_to?(:on_unload)
33
+ def applicationWillEnterForeground(application)
34
+ will_enter_foreground if respond_to?(:will_enter_foreground)
35
+ end
25
36
 
37
+ def applicationWillTerminate(application)
38
+ on_unload if respond_to?(:on_unload)
26
39
  end
27
40
 
28
41
  def app_delegate
@@ -40,14 +53,14 @@ module ProMotion
40
53
  def open_screen(screen, args={})
41
54
 
42
55
  screen = screen.new if screen.respond_to?(:new)
43
- screen.send(:on_load) if screen.respond_to?(:on_load)
44
56
 
45
57
  self.home_screen = screen
46
58
 
47
59
  self.window ||= self.ui_window.alloc.initWithFrame(UIScreen.mainScreen.bounds)
48
- self.window.rootViewController = screen.pm_main_controller
60
+ self.window.rootViewController = (screen.navigationController || screen)
49
61
  self.window.makeKeyAndVisible
50
62
 
63
+ screen
51
64
  end
52
65
  alias :open :open_screen
53
66
  alias :open_root_screen :open_screen
@@ -76,9 +89,9 @@ module ProMotion
76
89
 
77
90
  def status_bar_animation(opt)
78
91
  {
79
- fade: UIStatusBarAnimationFade,
80
- slide: UIStatusBarAnimationSlide,
81
- none: UIStatusBarAnimationNone
92
+ fade: UIStatusBarAnimationFade,
93
+ slide: UIStatusBarAnimationSlide,
94
+ none: UIStatusBarAnimationNone
82
95
  }[opt] || UIStatusBarAnimationNone
83
96
  end
84
97
 
@@ -5,7 +5,7 @@ module ProMotion
5
5
 
6
6
  def check_for_push_notification(options)
7
7
  if options && options[UIApplicationLaunchOptionsRemoteNotificationKey]
8
- received_push_notification options[UIApplicationLaunchOptionsRemoteNotificationKey]
8
+ received_push_notification options[UIApplicationLaunchOptionsRemoteNotificationKey], true
9
9
  end
10
10
  end
11
11
 
@@ -14,10 +14,7 @@ module ProMotion
14
14
  notification_types = [ :badge, :sound, :alert, :newsstand ] if notification_types.include?(:all)
15
15
 
16
16
  types = UIRemoteNotificationTypeNone
17
- types = types | UIRemoteNotificationTypeBadge if notification_types.include?(:badge)
18
- types = types | UIRemoteNotificationTypeSound if notification_types.include?(:sound)
19
- types = types | UIRemoteNotificationTypeAlert if notification_types.include?(:alert)
20
- types = types | UIRemoteNotificationTypeNewsstandContentAvailability if notification_types.include?(:newsstand)
17
+ notification_types.each { |t| types = types | map_notification_symbol(t) }
21
18
 
22
19
  UIApplication.sharedApplication.registerForRemoteNotificationTypes types
23
20
  end
@@ -38,9 +35,9 @@ module ProMotion
38
35
  types
39
36
  end
40
37
 
41
- def received_push_notification(notification)
38
+ def received_push_notification(notification, was_launched)
42
39
  @aps_notification = PM::PushNotification.new(notification)
43
- on_push_notification(@aps_notification) if respond_to?(:on_push_notification)
40
+ on_push_notification(@aps_notification, was_launched) if respond_to?(:on_push_notification)
44
41
  end
45
42
 
46
43
  # CocoaTouch
@@ -54,7 +51,19 @@ module ProMotion
54
51
  end
55
52
 
56
53
  def application(application, didReceiveRemoteNotification:notification)
57
- received_push_notification(notification)
54
+ received_push_notification(notification, false)
55
+ end
56
+
57
+ protected
58
+
59
+ def map_notification_symbol(symbol)
60
+ {
61
+ none: UIRemoteNotificationTypeNone,
62
+ badge: UIRemoteNotificationTypeBadge,
63
+ sound: UIRemoteNotificationTypeSound,
64
+ alert: UIRemoteNotificationTypeAlert,
65
+ newsstand: UIRemoteNotificationTypeNewsstandContentAvailability
66
+ }[symbol] || UIRemoteNotificationTypeNone
58
67
  end
59
68
 
60
69
  end
@@ -0,0 +1,11 @@
1
+ module ProMotion
2
+ # This is a workaround to a RubyMotion bug that displays an error message when calling
3
+ # `super` from application:didFinishLaunchingWithOptions: (which you sometimes need to
4
+ # do when using a custom AppDelegate parent class).
5
+ # See issue: https://github.com/clearsightstudio/ProMotion/issues/116
6
+ class DelegateParent
7
+ def application(application, didFinishLaunchingWithOptions:options)
8
+ true
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ module ProMotion
2
+ module Conversions
3
+
4
+ # For converting, for example, from :contacts to UITabBarSystemItemContacts
5
+ # Unfortunately, this only works if the symbol is defined in your code.
6
+ # So, for now, we'll have to do it manually.
7
+ def convert_symbol(symbol, prefix)
8
+ Object.const_get("#{prefix}#{camel_case symbol}")
9
+ end
10
+
11
+ def objective_c_method_name(str)
12
+ str.split('_').inject([]){ |buffer,e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
13
+ end
14
+
15
+ def camel_case(str)
16
+ str.split('_').map(&:capitalize).join
17
+ end
18
+
19
+ end
20
+ end