mirror of
https://github.com/zhigang1992/ProMotion.git
synced 2026-06-04 14:49:05 +08:00
Merge branch 'version-0.7' of https://github.com/clearsightstudio/ProMotion into version-0.7
This commit is contained in:
123
CUSTOM_VIEW_CONTROLLERS.md
Normal file
123
CUSTOM_VIEW_CONTROLLERS.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# Using your own UIViewControllers with ProMotion
|
||||
|
||||
Sometimes you want to inherit from a different UIViewController other than that provided by ProMotion.
|
||||
**RubyMotion doesn't currently allow us to override built-in methods when including them as a module.**
|
||||
And we really need to override `viewDidLoad` and others.
|
||||
|
||||
### Formotion
|
||||
|
||||
If you're including [Formotion](https://github.com/clayallsopp/formotion), just use the built-in
|
||||
`PM::FormotionScreen` and provide a `table_data` method or a `form:` object on instantiation.
|
||||
|
||||
```ruby
|
||||
class MyFormScreen < PM::FormotionScreen
|
||||
title "My Form"
|
||||
|
||||
def table_data
|
||||
{
|
||||
sections: [{
|
||||
title: "Register",
|
||||
rows: [{
|
||||
title: "Email",
|
||||
key: :email,
|
||||
placeholder: "me@mail.com",
|
||||
type: :email,
|
||||
auto_correction: :no,
|
||||
auto_capitalization: :none
|
||||
}, {
|
||||
title: "Password",
|
||||
key: :password,
|
||||
placeholder: "required",
|
||||
type: :string,
|
||||
secure: true
|
||||
}
|
||||
}]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
# elsewhere...
|
||||
|
||||
open MyFormScreen.new(nav_bar: true)
|
||||
```
|
||||
|
||||
You can also instantiate the form screen with the form hash like Formotion is usually used:
|
||||
|
||||
```ruby
|
||||
open MyFormScreen.new nav_bar: true, form: {
|
||||
sections: [{
|
||||
title: "Register",
|
||||
rows: [{
|
||||
title: "Email",
|
||||
key: :email,
|
||||
placeholder: "me@mail.com",
|
||||
type: :email,
|
||||
auto_correction: :no,
|
||||
auto_capitalization: :none
|
||||
}, {
|
||||
title: "Password",
|
||||
key: :password,
|
||||
placeholder: "required",
|
||||
type: :string,
|
||||
secure: true
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### Custom UIViewController
|
||||
|
||||
```ruby
|
||||
class EventsScreen < UIViewController
|
||||
include PM::ScreenModule
|
||||
|
||||
# Required functions for ProMotion to work properly
|
||||
def self.new(args = {})
|
||||
s = self.alloc.initWithNibName(nil, bundle:nil) # Use your custom initializer if you want.
|
||||
s.on_create(args)
|
||||
s
|
||||
end
|
||||
|
||||
|
||||
def viewDidLoad
|
||||
super
|
||||
self.view_did_load if self.respond_to?(:view_did_load)
|
||||
end
|
||||
|
||||
def viewWillAppear(animated)
|
||||
super
|
||||
self.view_will_appear(animated) if self.respond_to?("view_will_appear:")
|
||||
end
|
||||
|
||||
def viewDidAppear(animated)
|
||||
super
|
||||
self.view_did_appear(animated) if self.respond_to?("view_did_appear:")
|
||||
end
|
||||
|
||||
def viewWillDisappear(animated)
|
||||
self.view_will_disappear(animated) if self.respond_to?("view_will_disappear:")
|
||||
super
|
||||
end
|
||||
|
||||
def viewDidDisappear(animated)
|
||||
self.view_did_disappear(animated) if self.respond_to?("view_did_disappear:")
|
||||
super
|
||||
end
|
||||
|
||||
def shouldAutorotateToInterfaceOrientation(orientation)
|
||||
self.should_rotate(orientation)
|
||||
end
|
||||
|
||||
def shouldAutorotate
|
||||
self.should_autorotate
|
||||
end
|
||||
|
||||
def willRotateToInterfaceOrientation(orientation, duration:duration)
|
||||
self.will_rotate(orientation, duration)
|
||||
end
|
||||
|
||||
def didRotateFromInterfaceOrientation(orientation)
|
||||
self.on_rotate
|
||||
end
|
||||
end
|
||||
```
|
||||
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
ProMotion (0.6.0)
|
||||
ProMotion (0.6.1)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
|
||||
10
PROMOTION_APPS.md
Normal file
10
PROMOTION_APPS.md
Normal file
@@ -0,0 +1,10 @@
|
||||
### BigDay! Reminder App
|
||||
Check out the free [BigDay! Reminder app](https://itunes.apple.com/us/app/bigday!/id571756685?ls=1&mt=8) on the
|
||||
App Store to see what's possible. ClearSight Studio built the app for Kijome Software, a small app investment company.
|
||||
|
||||
### TipCounter App
|
||||
[TipCounter](http://www.tipcounterapp.com) was built by [Matt Brewer](https://github.com/macfanatic/) for bartenders and servers to easily track their tips. Used ProMotion and the development was a lot of fun!
|
||||
|
||||
### Winston-Salem Crime Map
|
||||
Have an interest in crime statistics and locations? Live in Winston-Salem, NC? This hyper-local and [open source](https://github.com/markrickert/WSCrime) RubyMotion app uses a mixture custom UIViewControllers and ProMotion for ease of attribute setting and adding views. Check it out [on the App Store](http://www.mohawkapps.com/winston-salem-crime-map/download/) or [fork it and contribute](https://github.com/markrickert/WSCrime)!
|
||||
|
||||
158
README.md
158
README.md
@@ -56,15 +56,7 @@ This is pretty bare-bones, but we'll be building it out as we go along.
|
||||
|
||||
## Apps Built With ProMotion
|
||||
|
||||
### BigDay! Reminder App
|
||||
Check out the free [BigDay! Reminder app](https://itunes.apple.com/us/app/bigday!/id571756685?ls=1&mt=8) on the
|
||||
App Store to see what's possible. ClearSight Studio built the app for Kijome Software, a small app investment company.
|
||||
|
||||
### TipCounter App
|
||||
[TipCounter](http://www.tipcounterapp.com) was built by [Matt Brewer](https://github.com/macfanatic/) for bartenders and servers to easily track their tips. Used ProMotion and the development was a lot of fun!
|
||||
|
||||
### Winston-Salem Crime Map
|
||||
Have an interest in crime statistics and locations? Live in Winston-Salem, NC? This hyper-local and [open source](https://github.com/markrickert/WSCrime) RubyMotion app uses a mixture custom UIViewControllers and ProMotion for ease of attribute setting and adding views. Check it out [on the App Store](http://www.mohawkapps.com/winston-salem-crime-map/download/) or [fork it and contribute](https://github.com/markrickert/WSCrime)!
|
||||
[View apps built with ProMotion (feel free to submit yours in a pull request!)](https://github.com/clearsightstudio/ProMotion/blob/master/PROMOTION_APPS.md)
|
||||
|
||||
# Getting Started
|
||||
|
||||
@@ -116,7 +108,7 @@ Run `bundle install` in Terminal to install ProMotion.
|
||||
Go into your app/app_delegate.rb file and replace everything with the following:
|
||||
|
||||
```ruby
|
||||
class AppDelegate < ProMotion::Delegate
|
||||
class AppDelegate < PM::Delegate
|
||||
def on_load(app, options)
|
||||
open HomeScreen.new(nav_bar: true)
|
||||
end
|
||||
@@ -136,7 +128,7 @@ Create a folder in `/app` named `screens`. Create a file in that folder named `h
|
||||
Now drop in this code:
|
||||
|
||||
```ruby
|
||||
class HomeScreen < ProMotion::Screen
|
||||
class HomeScreen < PM::Screen
|
||||
title "Home"
|
||||
|
||||
def will_appear
|
||||
@@ -160,7 +152,7 @@ Run `rake`. You should now see the simulator open with your home screen and a na
|
||||
* Will auto-detect if you've loaded [motion-xray](https://github.com/colinta/motion-xray) and enable it.
|
||||
* Added `open_split_screen` for iPad-supported apps (thanks @rheoli for your contributions to this)
|
||||
* Added `refreshable` to TableScreens (thanks to @markrickert) for pull-to-refresh support.
|
||||
* `ProMotion::AppDelegateParent` renamed to `ProMotion::Delegate` (`AppDelegateParent` is an alias)
|
||||
* `PM::AppDelegateParent` renamed to `PM::Delegate` (`AppDelegateParent` is an alias)
|
||||
* `set_attributes` and `add` now apply nested attributes recursively
|
||||
* `set_attributes` and `add` now accept snake_case instead of camelCase methods (e.g., background_color)
|
||||
* Added `add_to` method for adding views to any parent view. `remove` works with this normally.
|
||||
@@ -172,7 +164,7 @@ Run `rake`. You should now see the simulator open with your home screen and a na
|
||||
## Creating a basic screen
|
||||
|
||||
```ruby
|
||||
class HomeScreen < ProMotion::Screen
|
||||
class HomeScreen < PM::Screen
|
||||
title "Home"
|
||||
|
||||
def on_load
|
||||
@@ -194,7 +186,7 @@ end
|
||||
|
||||
```ruby
|
||||
# In app/app_delegate.rb
|
||||
class AppDelegate < ProMotion::Delegate
|
||||
class AppDelegate < PM::Delegate
|
||||
def on_load(app, options)
|
||||
open MyHomeScreen.new(nav_bar: true)
|
||||
end
|
||||
@@ -205,7 +197,7 @@ end
|
||||
|
||||
```ruby
|
||||
# In app/app_delegate.rb
|
||||
class AppDelegate < ProMotion::Delegate
|
||||
class AppDelegate < PM::Delegate
|
||||
def on_load(app, options)
|
||||
open_split_screen MenuScreen, DetailScreen
|
||||
end
|
||||
@@ -249,20 +241,30 @@ end
|
||||
|
||||
## Add navigation bar buttons
|
||||
|
||||
These two methods add the buttons to the top navigation bar of a screen. The `action:` lets you specify a method to
|
||||
This method adds the buttons to the top navigation bar of a screen. The `action:` lets you specify a method to
|
||||
call when that button is tapped, and you can pass in a UIBarButton style using `type:`.
|
||||
|
||||
```ruby
|
||||
set_nav_bar_right_button "Save", action: :save_something, type: UIBarButtonItemStyleDone
|
||||
set_nav_bar_left_button "Cancel", action: :return_to_some_other_screen, type: UIBarButtonItemStylePlain
|
||||
set_nav_bar_button :right, title: "Save", action: :save_something, type: UIBarButtonItemStyleDone
|
||||
set_nav_bar_button :left, title: "Cancel", action: :return_to_some_other_screen, type: UIBarButtonItemStylePlain
|
||||
```
|
||||
|
||||
If you pass an instance of a `UIImage`, the `UIBarButton` will automatically display with that image instead of text. *Don't forget retina and landscape versions of your image!*
|
||||
|
||||
If you pass `:system` for the title, then you can get a system item. E.g.:
|
||||
You can pass in an image with `image:`. *Don't forget retina and landscape versions of your image!*
|
||||
|
||||
```ruby
|
||||
set_nav_bar_right_button nil, action: :add_something, system_icon: UIBarButtonSystemItemAdd
|
||||
set_nav_bar_button :left, image: UIImage.imageNamed("cancel-button"), action: :cancel_something
|
||||
```
|
||||
|
||||
You can also pass in a `system_icon` instead.
|
||||
|
||||
```ruby
|
||||
set_nav_bar_button :right, system_icon: UIBarButtonSystemItemAdd, action: :add_something
|
||||
```
|
||||
|
||||
Additionally, if you pass an instance of a `UIBarButtonItem`, the `UIBarButton` will automatically display that particular button item.
|
||||
|
||||
```ruby
|
||||
set_nav_bar_button :left, button: UIBarButtonItem.alloc.initWithCustomView(button)
|
||||
```
|
||||
|
||||
## Opening and closing screens
|
||||
@@ -285,12 +287,16 @@ You can also open a screen as a modal.
|
||||
|
||||
```ruby
|
||||
open SettingsScreen.new, modal: true
|
||||
|
||||
# Or... (this is equivalent)
|
||||
|
||||
open_modal SettingsScreen.new
|
||||
```
|
||||
|
||||
You can pass in arguments to other screens if they have accessors:
|
||||
|
||||
```ruby
|
||||
class HomeScreen < ProMotion::Screen
|
||||
class HomeScreen < PM::Screen
|
||||
# ...
|
||||
|
||||
def settings_button_tapped
|
||||
@@ -298,7 +304,7 @@ class HomeScreen < ProMotion::Screen
|
||||
end
|
||||
end
|
||||
|
||||
class ProfileScreen < ProMotion::Screen
|
||||
class ProfileScreen < PM::Screen
|
||||
attr_accessor :user
|
||||
|
||||
def on_load
|
||||
@@ -319,7 +325,7 @@ end
|
||||
You can close a screen (modal or in a nav controller) and pass back arguments to the previous screen's "on_return" method:
|
||||
|
||||
```ruby
|
||||
class ItemScreen < ProMotion::Screen
|
||||
class ItemScreen < PM::Screen
|
||||
# ...
|
||||
def save_and_close
|
||||
if @model.save
|
||||
@@ -328,7 +334,7 @@ class ItemScreen < ProMotion::Screen
|
||||
end
|
||||
end
|
||||
|
||||
class MainScreen < ProMotion::Screen
|
||||
class MainScreen < PM::Screen
|
||||
# ...
|
||||
def on_return(args = {})
|
||||
if args[:model_saved]
|
||||
@@ -344,7 +350,7 @@ It's common to want to open a screen in the same navigation controller if on iPh
|
||||
in a separate detail view when on iPad. Here's a good way to do that.
|
||||
|
||||
```ruby
|
||||
class MenuScreen < ProMotion::TableScreen
|
||||
class MenuScreen < PM::TableScreen
|
||||
# ...
|
||||
def some_action
|
||||
open SomeScreen.new, in_detail: true
|
||||
@@ -407,7 +413,7 @@ add_to @some_parent_view, UIView.alloc.initWithFrame(CGRectMake(0, 0, 20, 20)),
|
||||
You can create sectioned table screens easily with TableScreen, SectionedTableScreen, and GroupedTableScreen.
|
||||
|
||||
```ruby
|
||||
class SettingsScreen < ProMotion::GroupedTableScreen
|
||||
class SettingsScreen < PM::GroupedTableScreen
|
||||
title "Settings"
|
||||
|
||||
def on_load
|
||||
@@ -484,61 +490,7 @@ use only one section and set its value to `nil`. For example:
|
||||
|
||||
## Using your own UIViewController
|
||||
|
||||
Sometimes you want to inherit from a different UIViewController other than that provided by ProMotion,
|
||||
such as when using [Formotion](https://github.com/clayallsopp/formotion). **RubyMotion doesn't currently
|
||||
allow us to override built-in methods when including them as a module.** And we really need to override
|
||||
`viewDidLoad` and others.
|
||||
|
||||
Fortunately, there's a workaround for that.
|
||||
|
||||
```ruby
|
||||
class EventsScreen < Formotion::FormController # Can also be < UIViewController
|
||||
include ProMotion::ScreenModule # Not TableScreenModule since we're using Formotion for that
|
||||
|
||||
# Required functions for ProMotion to work properly
|
||||
|
||||
def viewDidLoad
|
||||
super
|
||||
self.view_did_load if self.respond_to?(:view_did_load)
|
||||
end
|
||||
|
||||
def viewWillAppear(animated)
|
||||
super
|
||||
self.view_will_appear(animated) if self.respond_to?("view_will_appear:")
|
||||
end
|
||||
|
||||
def viewDidAppear(animated)
|
||||
super
|
||||
self.view_did_appear(animated) if self.respond_to?("view_did_appear:")
|
||||
end
|
||||
|
||||
def viewWillDisappear(animated)
|
||||
self.view_will_disappear(animated) if self.respond_to?("view_will_disappear:")
|
||||
super
|
||||
end
|
||||
|
||||
def viewDidDisappear(animated)
|
||||
self.view_did_disappear(animated) if self.respond_to?("view_did_disappear:")
|
||||
super
|
||||
end
|
||||
|
||||
def shouldAutorotateToInterfaceOrientation(orientation)
|
||||
self.should_rotate(orientation)
|
||||
end
|
||||
|
||||
def shouldAutorotate
|
||||
self.should_autorotate
|
||||
end
|
||||
|
||||
def willRotateToInterfaceOrientation(orientation, duration:duration)
|
||||
self.will_rotate(orientation, duration)
|
||||
end
|
||||
|
||||
def didRotateFromInterfaceOrientation(orientation)
|
||||
self.on_rotate
|
||||
end
|
||||
end
|
||||
```
|
||||
[Using your own UIViewController with ProMotion](https://github.com/clearsightstudio/ProMotion/blob/master/CUSTOM_VIEW_CONTROLLERS.md)
|
||||
|
||||
# Reference
|
||||
|
||||
@@ -602,18 +554,15 @@ end
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>set_nav_bar_left_button(title, args = {})</td>
|
||||
<td>set_nav_bar_button(side, args = {})</td>
|
||||
<td>
|
||||
Set a left nav bar button.<br />
|
||||
`title` can be a `String` or a `UIImage`.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>set_nav_bar_right_button(title, args = {})</td>
|
||||
<td>
|
||||
Set a right nav bar button.<br />
|
||||
`title` can be a `String` or a `UIImage`.
|
||||
<img src="http://i.imgur.com/whbkc.png" />
|
||||
Set a nav bar button.<br />
|
||||
`side` can be :left or :right. `args` can include the following:<br />
|
||||
title: "Button Title"<br />
|
||||
image: (UIImage)<br />
|
||||
system_icon: (UIBarButtonSystemItem)<br />
|
||||
button: (UIBarButtonItem)<br />
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -727,6 +676,12 @@ end
|
||||
Any accessors in <code>screen</code> can also be set in this hash.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>open_modal(screen, args = {})</td>
|
||||
<td>
|
||||
Same as <code>open HomeScreen, modal: true</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>open_split_screen(master, detail)</td>
|
||||
<td>
|
||||
@@ -810,7 +765,7 @@ def table_data
|
||||
height: 50, # manually changes the cell's height
|
||||
cell_style: UITableViewCellStyleSubtitle,
|
||||
cell_identifier: "Cell",
|
||||
cell_class: ProMotion::TableViewCell,
|
||||
cell_class: PM::TableViewCell,
|
||||
masks_to_bounds: true,
|
||||
background_color: UIColor.whiteColor,
|
||||
selection_style: UITableViewCellSelectionStyleGray,
|
||||
@@ -916,7 +871,7 @@ end
|
||||
</td>
|
||||
<td>
|
||||
Class method to output a colored console message.<br />
|
||||
Example: <code>ProMotion::Console.log("This is red!", with_color: ProMotion::Console::RED_COLOR)</code>
|
||||
Example: <code>PM::Console.log("This is red!", with_color: PM::Console::RED_COLOR)</code>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -929,7 +884,9 @@ Opening a ticket is usually the best and we respond to those pretty quickly.
|
||||
# Contributing
|
||||
|
||||
I'm very open to ideas. Tweet me with your ideas or open a ticket (I don't mind!)
|
||||
and let's discuss.
|
||||
and let's discuss. **It's a good idea to run your idea by the committers before creating
|
||||
a pull request.** We'll always consider your ideas carefully but not all ideas will be
|
||||
incorporated.
|
||||
|
||||
## Working on Features
|
||||
|
||||
@@ -944,15 +901,16 @@ and let's discuss.
|
||||
1. Fork the project
|
||||
2. Create a feature branch
|
||||
3. Code
|
||||
4. Update or create new specs
|
||||
4. Update or create new specs ** NOTE: your PR is far more likely to be merged if you include comprehensive tests! **
|
||||
5. Make sure tests are passing by running `rake spec`
|
||||
6. Submit pull request
|
||||
7. Fame, adoration, kudos everywhere
|
||||
7. Make a million little nitpicky changes that @jamonholmgren wants
|
||||
8. Merged, then fame, adoration, kudos everywhere
|
||||
|
||||
## Primary Contributors
|
||||
|
||||
* Jamon Holmgren: [@jamonholmgren](https://twitter.com/jamonholmgren)
|
||||
* Silas Matson: [@silasjmatson](https://twitter.com/silasjmatson)
|
||||
* Matt Brewer: [@macfanatic](https://twitter.com/macfanatic)
|
||||
|
||||
* [Many others](https://github.com/clearsightstudio/ProMotion/graphs/contributors)
|
||||
|
||||
|
||||
@@ -10,10 +10,13 @@ module ProMotion
|
||||
screen.send(:on_load) if screen.respond_to?(:on_load)
|
||||
animated = args[:animated] || true
|
||||
|
||||
return self.split_screen.detail_screen = screen if args[:in_detail] && self.split_screen
|
||||
return self.split_screen.master_screen = screen if args[:in_master] && self.split_screen
|
||||
if args[:in_detail] && self.split_screen
|
||||
self.split_screen.detail_screen = screen
|
||||
|
||||
if args[:close_all]
|
||||
elsif args[:in_master] && self.split_screen
|
||||
self.split_screen.master_screen = screen
|
||||
|
||||
elsif args[:close_all]
|
||||
open_root_screen screen
|
||||
|
||||
elsif args[:modal]
|
||||
@@ -25,11 +28,8 @@ module ProMotion
|
||||
elsif self.navigation_controller
|
||||
push_view_controller screen
|
||||
|
||||
elsif screen.respond_to?(:main_controller)
|
||||
open_view_controller screen.main_controller
|
||||
|
||||
else
|
||||
open_view_controller screen
|
||||
open_root_screen screen
|
||||
|
||||
end
|
||||
|
||||
@@ -40,6 +40,10 @@ module ProMotion
|
||||
app_delegate.open_root_screen(screen)
|
||||
end
|
||||
|
||||
def open_modal(screen, args = {})
|
||||
open screen, args.merge({ modal: true })
|
||||
end
|
||||
|
||||
def app_delegate
|
||||
UIApplication.sharedApplication.delegate
|
||||
end
|
||||
@@ -72,8 +76,9 @@ module ProMotion
|
||||
end
|
||||
end
|
||||
|
||||
def open_view_controller(vc)
|
||||
app_delegate.load_root_view vc
|
||||
def open_view_controller(screen)
|
||||
PM.logger.deprecated "Use `open_root_screen` instead of the more ambiguous `open_view_controller`."
|
||||
open_root_screen screen
|
||||
end
|
||||
|
||||
def push_view_controller(vc, nav_controller=nil)
|
||||
@@ -129,6 +134,8 @@ module ProMotion
|
||||
screen.navigation_controller = vc if screen.respond_to?("navigation_controller=")
|
||||
push_view_controller(screen, vc)
|
||||
else
|
||||
# TODO: This should probably open the vc, shouldn't it?
|
||||
# This isn't well tested and needs to work better.
|
||||
self.tab_bar.selectedIndex = vc.tabBarItem.tag
|
||||
end
|
||||
|
||||
|
||||
@@ -19,7 +19,11 @@ module ProMotion
|
||||
|
||||
[ master, detail ].map { |s| s.on_load if s.respond_to?(:on_load) }
|
||||
|
||||
split_screen_controller master, detail
|
||||
split = split_screen_controller master, detail
|
||||
if args.has_key?(:icon) or args.has_key?(:title)
|
||||
split.tabBarItem = create_tab_bar_item(args)
|
||||
end
|
||||
split
|
||||
end
|
||||
|
||||
def open_split_screen(master, detail, args={})
|
||||
@@ -39,4 +43,4 @@ module ProMotion
|
||||
svc.detail_screen.navigationItem.leftBarButtonItem = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,13 +6,16 @@ module ProMotion
|
||||
include ProMotion::ScreenTabs
|
||||
include ProMotion::SplitScreen if NSBundle.mainBundle.infoDictionary["UIDeviceFamily"].include?("2")
|
||||
|
||||
attr_accessor :parent_screen, :first_screen, :tab_bar_item, :tab_bar, :modal, :split_screen
|
||||
attr_accessor :parent_screen, :first_screen, :tab_bar_item, :tab_bar, :modal, :split_screen, :title
|
||||
|
||||
def on_create(args = {})
|
||||
unless self.is_a?(UIViewController)
|
||||
raise StandardError.new("ERROR: Screens must extend UIViewController or a subclass of UIViewController.")
|
||||
end
|
||||
|
||||
|
||||
self.title = self.class.send(:get_title)
|
||||
|
||||
args.each do |k, v|
|
||||
self.send("#{k}=", v) if self.respond_to?("#{k}=")
|
||||
end
|
||||
@@ -72,29 +75,36 @@ module ProMotion
|
||||
set_nav_bar_button :left, args
|
||||
end
|
||||
|
||||
# If you call set_nav_bar_button with a nil title and system_icon: UIBarButtonSystemItemAdd (or any other
|
||||
# system icon), the button is initialized with a barButtonSystemItem instead of a title.
|
||||
def set_nav_bar_button(side, args={})
|
||||
args[:style] ||= UIBarButtonItemStyleBordered
|
||||
args[:target] ||= self
|
||||
args[:action] ||= nil
|
||||
button_type = args[:image] || args[:button] || args[:system_icon] || args[:title] || "Button"
|
||||
|
||||
button = case args[:title]
|
||||
when String
|
||||
UIBarButtonItem.alloc.initWithTitle(args[:title], style: args[:style], target: args[:target], action: args[:action])
|
||||
when UIImage
|
||||
UIBarButtonItem.alloc.initWithImage(args[:title], style: args[:style], target: args[:target], action: args[:action])
|
||||
when Symbol, NilClass
|
||||
UIBarButtonItem.alloc.initWithBarButtonSystemItem(args[:system_icon], target: args[:target], action: args[:action]) if args[:system_icon]
|
||||
else
|
||||
PM.logger.error("Please supply a title string, a UIImage or :system.")
|
||||
end
|
||||
button = bar_button_item button_type, args
|
||||
|
||||
self.navigationItem.leftBarButtonItem = button if side == :left
|
||||
self.navigationItem.rightBarButtonItem = button if side == :right
|
||||
|
||||
button
|
||||
end
|
||||
|
||||
def bar_button_item(button_type, args)
|
||||
case button_type
|
||||
when UIBarButtonItem
|
||||
button_type
|
||||
when UIImage
|
||||
UIBarButtonItem.alloc.initWithImage(button_type, style: args[:style], target: args[:target], action: args[:action])
|
||||
when String
|
||||
UIBarButtonItem.alloc.initWithTitle(button_type, style: args[:style], target: args[:target], action: args[:action])
|
||||
else
|
||||
if args[:system_icon]
|
||||
UIBarButtonItem.alloc.initWithBarButtonSystemItem(args[:system_icon], target: args[:target], action: args[:action])
|
||||
else
|
||||
PM.logger.error("Please supply a title string, a UIImage or :system.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# [DEPRECATED]
|
||||
def view_controller=(vc)
|
||||
@@ -136,15 +146,6 @@ module ProMotion
|
||||
end
|
||||
def on_disappear; end
|
||||
|
||||
def title
|
||||
self.class.send(:get_title)
|
||||
end
|
||||
|
||||
def title=(new_title)
|
||||
self.class.title = new_title
|
||||
super
|
||||
end
|
||||
|
||||
def main_controller
|
||||
self.navigation_controller || self
|
||||
end
|
||||
|
||||
65
lib/ProMotion/screens/compatibility/formotion_screen.rb
Normal file
65
lib/ProMotion/screens/compatibility/formotion_screen.rb
Normal file
@@ -0,0 +1,65 @@
|
||||
module ProMotion
|
||||
if defined?(Formotion) && defined?(Formotion::FormController)
|
||||
class FormotionScreen < Formotion::FormController
|
||||
include ProMotion::ScreenModule
|
||||
|
||||
def self.new(args = {})
|
||||
s = self.alloc.initWithStyle(UITableViewStyleGrouped)
|
||||
s.on_create(args) if s.respond_to?(:on_create)
|
||||
|
||||
if s.respond_to?(:table_data)
|
||||
s.form = s.table_data
|
||||
elsif args[:form]
|
||||
s.form = args[:form]
|
||||
else
|
||||
PM.logger.error "PM::FormotionScreen requires a `table_data` method or form: to be passed into `new`."
|
||||
end
|
||||
|
||||
s.tableView.allowsSelectionDuringEditing = true
|
||||
|
||||
s
|
||||
end
|
||||
|
||||
def viewDidLoad
|
||||
super
|
||||
self.view_did_load if self.respond_to?(:view_did_load)
|
||||
end
|
||||
|
||||
def viewWillAppear(animated)
|
||||
super
|
||||
self.view_will_appear(animated) if self.respond_to?(:view_will_appear)
|
||||
end
|
||||
|
||||
def viewDidAppear(animated)
|
||||
super
|
||||
self.view_did_appear(animated) if self.respond_to?(:view_did_appear)
|
||||
end
|
||||
|
||||
def viewWillDisappear(animated)
|
||||
self.view_will_disappear(animated) if self.respond_to?(:view_will_disappear)
|
||||
super
|
||||
end
|
||||
|
||||
def viewDidDisappear(animated)
|
||||
self.view_did_disappear(animated) if self.respond_to?(:view_did_disappear)
|
||||
super
|
||||
end
|
||||
|
||||
def shouldAutorotateToInterfaceOrientation(orientation)
|
||||
self.should_rotate(orientation)
|
||||
end
|
||||
|
||||
def shouldAutorotate
|
||||
self.should_autorotate
|
||||
end
|
||||
|
||||
def willRotateToInterfaceOrientation(orientation, duration:duration)
|
||||
self.will_rotate(orientation, duration)
|
||||
end
|
||||
|
||||
def didRotateFromInterfaceOrientation(orientation)
|
||||
self.on_rotate
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,3 +1,3 @@
|
||||
module ProMotion
|
||||
VERSION = "0.6.0" unless defined?(ProMotion::VERSION)
|
||||
VERSION = "0.6.1" unless defined?(ProMotion::VERSION)
|
||||
end
|
||||
|
||||
0
resources/list.png
Executable file → Normal file
0
resources/list.png
Executable file → Normal file
|
Before Width: | Height: | Size: 104 B After Width: | Height: | Size: 104 B |
@@ -1,2 +1,3 @@
|
||||
class BasicScreen < ProMotion::Screen
|
||||
title "Basic"
|
||||
end
|
||||
|
||||
3
spec/helpers/detail_screen.rb
Normal file
3
spec/helpers/detail_screen.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
class DetailScreen < PM::Screen
|
||||
title "Detail"
|
||||
end
|
||||
3
spec/helpers/master_screen.rb
Normal file
3
spec/helpers/master_screen.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
class MasterScreen < PM::Screen
|
||||
title "Master"
|
||||
end
|
||||
55
spec/helpers/screen_module_view_controller.rb
Normal file
55
spec/helpers/screen_module_view_controller.rb
Normal file
@@ -0,0 +1,55 @@
|
||||
class ScreenModuleViewController < UIViewController
|
||||
include PM::ScreenModule
|
||||
title 'Test Title'
|
||||
|
||||
# Get rid of such hackiness when RubyMotion bug is fixed...
|
||||
|
||||
def self.new(args = {})
|
||||
s = self.alloc.initWithNibName(nil, bundle:nil)
|
||||
s.on_create(args) if s.respond_to?(:on_create)
|
||||
s
|
||||
end
|
||||
|
||||
def viewDidLoad
|
||||
super
|
||||
self.view_did_load if self.respond_to?(:view_did_load)
|
||||
end
|
||||
|
||||
def viewWillAppear(animated)
|
||||
super
|
||||
self.view_will_appear(animated) if self.respond_to?("view_will_appear:")
|
||||
end
|
||||
|
||||
def viewDidAppear(animated)
|
||||
super
|
||||
self.view_did_appear(animated) if self.respond_to?("view_did_appear:")
|
||||
end
|
||||
|
||||
def viewWillDisappear(animated)
|
||||
self.view_will_disappear(animated) if self.respond_to?("view_will_disappear:")
|
||||
super
|
||||
end
|
||||
|
||||
def viewDidDisappear(animated)
|
||||
if self.respond_to?("view_did_disappear:")
|
||||
self.view_did_disappear(animated)
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
def shouldAutorotateToInterfaceOrientation(orientation)
|
||||
self.should_rotate(orientation)
|
||||
end
|
||||
|
||||
def shouldAutorotate
|
||||
self.should_autorotate
|
||||
end
|
||||
|
||||
def willRotateToInterfaceOrientation(orientation, duration:duration)
|
||||
self.will_rotate(orientation, duration)
|
||||
end
|
||||
|
||||
def didRotateFromInterfaceOrientation(orientation)
|
||||
self.on_rotate
|
||||
end
|
||||
end
|
||||
@@ -1,9 +1,4 @@
|
||||
class TestDelegate < ProMotion::Delegate
|
||||
def on_load(app, options)
|
||||
end
|
||||
|
||||
# Hack to make RM 2.0 work.
|
||||
# Ref: http://hipbyte.myjetbrains.com/youtrack/issue/RM-136
|
||||
def dealloc
|
||||
end
|
||||
end
|
||||
|
||||
@@ -68,6 +68,15 @@ describe "screen helpers" do
|
||||
@screen.navigationItem.leftBarButtonItem.image.should == image
|
||||
end
|
||||
|
||||
it "should add a left UIBarButtonItem" do
|
||||
@screen.set_nav_bar_left_button @screen.editButtonItem
|
||||
@screen.navigationItem.leftBarButtonItem.class.should == UIBarButtonItem
|
||||
end
|
||||
|
||||
it "should add a right UIBarButtonItem" do
|
||||
@screen.set_nav_bar_right_button @screen.editButtonItem
|
||||
@screen.navigationItem.rightBarButtonItem.class.should == UIBarButtonItem
|
||||
end
|
||||
end
|
||||
|
||||
describe "screen navigation" do
|
||||
@@ -132,7 +141,7 @@ describe "screen helpers" do
|
||||
|
||||
it "should open a root screen if :close_all is provided" do
|
||||
@screen.mock!(:open_root_screen) { |screen| screen.should.be.instance_of BasicScreen }
|
||||
@screen.open_screen BasicScreen, close_all: true
|
||||
@screen.open BasicScreen, close_all: true
|
||||
end
|
||||
|
||||
it "should present a modal screen if :modal is provided" do
|
||||
@@ -140,7 +149,15 @@ describe "screen helpers" do
|
||||
screen.should.be.instance_of BasicScreen
|
||||
animated.should == true
|
||||
end
|
||||
@screen.open_screen BasicScreen, modal: true
|
||||
@screen.open BasicScreen, modal: true
|
||||
end
|
||||
|
||||
it "should present a modal screen if open_modal is used" do
|
||||
@screen.mock!(:present_modal_view_controller) do |screen, animated|
|
||||
screen.should.be.instance_of BasicScreen
|
||||
animated.should == true
|
||||
end
|
||||
@screen.open_modal BasicScreen
|
||||
end
|
||||
|
||||
it "should open screen in tab bar if :in_tab is provided" do
|
||||
@@ -149,28 +166,18 @@ describe "screen helpers" do
|
||||
screen.should.be.instance_of BasicScreen
|
||||
tab_name.should == 'my_tab'
|
||||
end
|
||||
@screen.open_screen BasicScreen, in_tab: 'my_tab'
|
||||
@screen.open BasicScreen, in_tab: 'my_tab'
|
||||
end
|
||||
|
||||
it "should pop onto navigation controller if current screen is on nav stack already" do
|
||||
@screen.mock!(:push_view_controller) { |vc| vc.should.be.instance_of BasicScreen }
|
||||
@screen.open_screen BasicScreen
|
||||
@screen.open BasicScreen
|
||||
end
|
||||
|
||||
it "should open the main controller if no options are provided" do
|
||||
parent_screen = HomeScreen.new
|
||||
nav_controller = ProMotion::NavigationController.new
|
||||
new_screen = BasicScreen.new
|
||||
new_screen.stub! :main_controller, return: nav_controller
|
||||
|
||||
parent_screen.mock!(:open_view_controller) { |vc| vc.should.be == nav_controller }
|
||||
parent_screen.open_screen new_screen
|
||||
end
|
||||
|
||||
it "should open the provided view controller if no other conditions are met" do
|
||||
it "should open the provided view controller as root view if no other conditions are met" do
|
||||
parent_screen = HomeScreen.new
|
||||
new_screen = BasicScreen.new
|
||||
parent_screen.mock!(:open_view_controller) { |vc| vc.should.be == new_screen }
|
||||
parent_screen.mock!(:open_root_screen) { |vc| vc.should.be == new_screen }
|
||||
parent_screen.open_screen new_screen
|
||||
end
|
||||
|
||||
|
||||
13
spec/screen_module_spec.rb
Normal file
13
spec/screen_module_spec.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
describe "PM::ScreenModule" do
|
||||
|
||||
before { @subject = ScreenModuleViewController.new }
|
||||
|
||||
it 'should have PM::ScreenModule in ancestors' do
|
||||
@subject.class.ancestors.include?(PM::ScreenModule).should == true
|
||||
end
|
||||
|
||||
it 'should have a title from class method #title' do
|
||||
@subject.title.should == 'Test Title'
|
||||
end
|
||||
|
||||
end
|
||||
@@ -12,9 +12,18 @@ describe "screen properties" do
|
||||
HomeScreen.get_title.should == 'Home'
|
||||
end
|
||||
|
||||
it "should let the instance reset the title" do
|
||||
it "should set default title on new instances" do
|
||||
@screen.title.should == "Home"
|
||||
end
|
||||
|
||||
it "should let the instance set its title" do
|
||||
@screen.title = "instance method"
|
||||
HomeScreen.get_title.should == 'instance method'
|
||||
@screen.title.should == 'instance method'
|
||||
end
|
||||
|
||||
it "should not let the instance reset the default title" do
|
||||
@screen.title = "instance method"
|
||||
HomeScreen.get_title.should != 'instance method'
|
||||
end
|
||||
|
||||
it "should store debug mode" do
|
||||
|
||||
@@ -6,10 +6,14 @@ describe "split screen in tab bar functionality" do
|
||||
@master_screen = HomeScreen.new nav_bar: true
|
||||
@detail_screen = BasicScreen.new nav_bar: true
|
||||
|
||||
@split_screen = @app.create_split_screen @master_screen, @detail_screen
|
||||
@split_screen = @app.create_split_screen @master_screen, @detail_screen, icon: "list", title: "Spec"
|
||||
@tab = @app.open_tab_bar @split_screen, HomeScreen, BasicScreen
|
||||
end
|
||||
|
||||
after do
|
||||
@split_screen.delegate = nil # dereference to avoid memory issue
|
||||
end
|
||||
|
||||
it "should create a UISplitViewController" do
|
||||
@split_screen.is_a?(UISplitViewController).should == true
|
||||
end
|
||||
@@ -45,5 +49,18 @@ describe "split screen in tab bar functionality" do
|
||||
it "should set the tab bar first viewController to the split screen" do
|
||||
@tab.viewControllers.first.should == @split_screen
|
||||
end
|
||||
|
||||
it "should set the bar bar item for the split screen" do
|
||||
@split_screen.tabBarItem.is_a?(UITabBarItem).should == true
|
||||
end
|
||||
|
||||
it "should set the tab bar icon of the split screen" do
|
||||
@split_screen.tabBarItem.image.is_a?(UIImage).should == true
|
||||
end
|
||||
|
||||
it "should set the tab bar title of the split screen" do
|
||||
@split_screen.tabBarItem.title.is_a?(String).should == true
|
||||
@split_screen.tabBarItem.title.should == "Spec"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,6 +10,10 @@ describe "split screen `open` functionality" do
|
||||
@split_screen = @app.open_split_screen @master_screen, @detail_screen_1
|
||||
end
|
||||
|
||||
after do
|
||||
@split_screen.delegate = nil # dereference to avoid memory issue
|
||||
end
|
||||
|
||||
it "should open a new screen in the detail view" do
|
||||
@master_screen.open @detail_screen_2, in_detail: true
|
||||
@split_screen.detail_screen.should == @detail_screen_2
|
||||
@@ -43,4 +47,4 @@ describe "split screen `open` functionality" do
|
||||
home.navigation_controller.topViewController.should == child
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,12 +3,16 @@ describe "split screen functionality" do
|
||||
before do
|
||||
@app = TestDelegate.new
|
||||
|
||||
@master_screen = HomeScreen.new nav_bar: true
|
||||
@detail_screen = BasicScreen.new # no nav_bar on this one
|
||||
@master_screen = MasterScreen.new nav_bar: true
|
||||
@detail_screen = DetailScreen.new # no nav_bar on this one
|
||||
|
||||
@split_screen = @app.open_split_screen @master_screen, @detail_screen
|
||||
end
|
||||
|
||||
after do
|
||||
@split_screen.delegate = nil # dereference to avoid memory issue
|
||||
end
|
||||
|
||||
it "should have created a split screen" do
|
||||
@split_screen.should != nil
|
||||
@split_screen.is_a?(UISplitViewController).should == true
|
||||
@@ -22,14 +26,42 @@ describe "split screen functionality" do
|
||||
@app.window.rootViewController.should == @split_screen
|
||||
end
|
||||
|
||||
it "should set the first viewController to HomeScreen" do
|
||||
it "should set the first viewController to MasterScreen" do
|
||||
@split_screen.master_screen.should == @master_screen
|
||||
@split_screen.viewControllers.first.should == @master_screen.main_controller
|
||||
end
|
||||
|
||||
it "should set the second viewController to BasicScreen" do
|
||||
it "should set the second viewController to DetailScreen" do
|
||||
@split_screen.detail_screen.should == @detail_screen
|
||||
@split_screen.viewControllers.last.should == @detail_screen.main_controller
|
||||
end
|
||||
|
||||
end
|
||||
it "should set the title on both screens" do
|
||||
@master_screen.class.send(:get_title).should == "Master"
|
||||
@master_screen.title.should == "Master"
|
||||
@detail_screen.class.send(:get_title).should == "Detail"
|
||||
@detail_screen.title.should == "Detail"
|
||||
end
|
||||
end
|
||||
|
||||
# Regression test for https://github.com/clearsightstudio/ProMotion/issues/74
|
||||
describe "split screen with UIViewControllers with ScreenModule" do
|
||||
|
||||
before do
|
||||
@app = TestDelegate.new
|
||||
|
||||
@master_screen = ScreenModuleViewController.new
|
||||
@detail_screen = DetailScreen.new(nav_bar: true)
|
||||
|
||||
@split_screen = @app.open_split_screen @master_screen, @detail_screen
|
||||
end
|
||||
|
||||
it "should set the title on both screens" do
|
||||
@master_screen.class.send(:get_title).should == "Test Title"
|
||||
@master_screen.title.should == "Test Title"
|
||||
@detail_screen.class.send(:get_title).should == "Detail"
|
||||
@detail_screen.title.should == "Detail"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user