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
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