Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/bugfix: update status bar methods to work with newer versions of iOS #806

Merged
merged 8 commits into from
Apr 3, 2018
3 changes: 1 addition & 2 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
$:.unshift("/Library/RubyMotion/lib")
$:.unshift("~/.rubymotion/rubymotion-templates")
require 'motion/project/template/ios'
require 'bundler'
Bundler.setup
Expand All @@ -10,8 +11,6 @@ require 'motion_print'
Motion::Project::App.setup do |app|
app.name = 'ProMotion'
app.device_family = [ :ipad ] # so we can test split screen capability
app.detect_dependencies = false
app.info_plist["UIViewControllerBasedStatusBarAppearance"] = false
app.deployment_target = "8.0"

# Adding file dependencies for tests
Expand Down
28 changes: 23 additions & 5 deletions docs/Reference/ProMotion Delegate.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The PM::Delegate gives you ProMotion's nice API for your AppDelegate class.
```ruby
# app/app_delegate.rb
class AppDelegate < PM::Delegate
status_bar false, animation: :none
status_bar :dark, animation: :none

def on_load(app, options)
open HomeScreen
Expand All @@ -25,7 +25,7 @@ If you need to inherit from a different AppDelegate superclass, do this:
```ruby
class AppDelegate < JHMyParentDelegate
include PM::DelegateModule
status_bar false, animation: :none
status_bar :dark, animation: :none

def on_load(app, options)
open HomeScreen
Expand Down Expand Up @@ -148,20 +148,38 @@ end

#### status_bar

Class method that allows hiding or showing the status bar. Setting this to `false` will hide it throughout the app.
This class method allows you to configure the default setting of whether or not to show the status bar and whether you want the status bar text to appear light or dark. You may also optionally specify the animation style when hiding/showing the status bar. These will become the default setting throughout the app. Note that if you specify `:light` as the status bar style, and the current screen uses a navigation bar, the bar style must have a dark style in order for the status bar to have white text.

**Style Options:**
- `:dark` (default)
- `:light`
- `:hidden`/`:none`

**Animation Options:**
- `:fade` (default)
- `:slide`
- `:none`

```ruby
class AppDelegate < PM::Delegate
status_bar true, animation: :none # :slide, :fade
status_bar :light, animation: :fade
end
```

If you want the status bar to be hidden on the splash screen you must set this in your rakefile.
**Configuring status bar appearance during app launch**

If you want the status bar to be initially hidden when the app launches, you must set this `info_plist` setting in your rakefile.

```ruby
app.info_plist['UIStatusBarHidden'] = true
```

To configure the style (light or dark text) of the status bar during app launch, you can configure the `status_bar_style` project config setting in your rakefile.

```ruby
app.status_bar_style = :light_content # or :default (dark)
```

#### tint_color

Class method that allows you to set the application's global tint color for iOS 7 apps.
Expand Down
36 changes: 31 additions & 5 deletions docs/Reference/ProMotion Screen.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ Runs just before the screen rotates.

#### set_nav_bar_button(side, args = {})

Set a nav bar button. `args` can be `image:`, `title:`, `system_item:`, `button:`, `custom_view:`.
Set a nav bar button. `args` can be `image:`, `title:` or `system_item:` (not both), `tint_color:`, `button:`, or `custom_view:`.

You can also set arbitrary attributes in the hash and they'll be applied to the button.

Expand All @@ -318,7 +318,7 @@ set_nav_bar_button :left, {
```ruby
:done,:cancel,:edit,:save,:add,:flexible_space,:fixed_space,:compose,
:reply,:action,:organize,:bookmarks,:search,:refresh,:stop,:camera,
:trash,:play,:pause,:rewind,:fast_forward,:undo,:redo,:page_curl
:trash,:play,:pause,:rewind,:fast_forward,:undo,:redo
```

`custom_view` can be any custom `UIView` subclass you initialize yourself
Expand Down Expand Up @@ -611,20 +611,46 @@ end

#### status_bar(style=nil, args={animation: UIStatusBarAnimationSlide})

Set the properties of the application's status bar. Options for style are: `:none`, `:light`, `:dark`, and `:default`. If a screen doesn't call `status_bar` and a `UIStatusBarStyle` is set on the application bundle, then that style will be used. Otherwise, `UIStatusBarStyleDefault` will be used. The animation argument should be a `UIStatusBarAnimation` (or `:none` / `:fade` / `:slide`) and is used to hide or show the status bar when appropriate and defaults to `:slide`. If `status_bar` is set to `false` in the app delegate this will default to hidden as well.
This method allows you to specify whether or not to show the status bar and whether you want the status bar text to appear light or dark. You may also optionally specify the animation style when hiding/showing the status bar. These settings will only affect the status bar for this screen. Note that if you specify `:light` as the status bar style, and the current screen uses a navigation bar, the bar style must have a dark style in order for the status bar to have white text.

**Style Options:**
- `:dark` (default)
- `:light`
- `:hidden`/`:none`

**Animation Options:**
- `:fade` (default)
- `:slide`
- `:none`

```ruby
class MyScreen < PM::Screen
status_bar :none, {animation: :fade}
status_bar :hidden
# ...
end

class MyScreenWithADarkColoredNavBar < PM::Screen
status_bar :light
status_bar :light, animation: :fade
# ...
end
```

#### hide_status_bar(args={animated: false})

If the status bar is currently displayed, but you want to hide it some time after the screen has already rendered, call `hide_status_bar`. You may optionally specify that the hiding should be animated. This will use the animation style that you already specified (either on the screen or globally on your AppDelegate). If you did not already specify an animation style, the default is `:fade`.

```ruby
hide_status_bar(animated: true)
```

#### show_status_bar(args={style: nil, animated: false})

If the status bar is currently hidden and the screen has already rendered, but now you want want to display it, call `show_status_bar`. You may optionally specify the status bar style (light or dark). If you do not specify a style, then the default style that you specified (either on the screen or globally on your AppDelegate) will be used. You may also optionally specify that the showing should be animated. This will use the animation style that you already specified (either on the screen or globally on your AppDelegate). If you did not already specify an animation style, the default is `:fade`.

```ruby
show_status_bar(style: :light, animated: true)
```

#### nav_bar(enabled, nav_bar_options={})

Add a navigation bar (and UINavigationController wrapper) to the current screen whenever it's opened.
Expand Down
43 changes: 23 additions & 20 deletions lib/ProMotion/delegate/delegate_module.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ def application(application, willFinishLaunchingWithOptions:launch_options)
end

def application(application, didFinishLaunchingWithOptions:launch_options)
apply_status_bar
on_load application, launch_options
# Requires 'ProMotion-push' gem.
check_for_push_notification(launch_options) if respond_to?(:check_for_push_notification)
Expand Down Expand Up @@ -66,37 +65,43 @@ def open(screen, args={})
alias :open_screen :open
alias :open_root_screen :open_screen

# DEPRECATED
def status_bar?
UIApplication.sharedApplication.statusBarHidden
mp "The default behavior of `status_bar?` has changed. Calling `status_bar?` on AppDelegate may not return the correct result.", force_color: :yellow
self.class.status_bar_style != :hidden
end

private
def status_bar_style
self.class.status_bar_style
end

def apply_status_bar
self.class.send(:apply_status_bar)
def status_bar_animation
self.class.status_bar_animation
end

public

module ClassMethods

def status_bar(visible = true, opts={})
@status_bar_visible = visible
@status_bar_opts = opts
def status_bar(visible = true, opts = {})
info_plist_setting = NSBundle.mainBundle.objectForInfoDictionaryKey('UIViewControllerBasedStatusBarAppearance')
if info_plist_setting == false && visible == false
mp "The default behavior of `status_bar` has changed. Calling `status_bar` will have no effect until you remove the 'UIViewControllerBasedStatusBarAppearance' setting from info_plist.", force_color: :yellow
end
@status_bar_style = case visible
when false then :hidden
when true then :default
else visible
end
@status_bar_animation = opts[:animation] || :default
end

def apply_status_bar
@status_bar_visible = true if @status_bar_visible.nil?
@status_bar_opts ||= { animation: :none }
UIApplication.sharedApplication.setStatusBarHidden(!@status_bar_visible, withAnimation:status_bar_animation(@status_bar_opts[:animation]))
def status_bar_style
@status_bar_style
end

def status_bar_animation(opt)
{
fade: UIStatusBarAnimationFade,
slide: UIStatusBarAnimationSlide,
none: UIStatusBarAnimationNone
}[opt] || UIStatusBarAnimationNone
def status_bar_animation
@status_bar_animation
end

def tint_color(c)
Expand All @@ -110,12 +115,10 @@ def tint_color=(c)
def get_tint_color
@tint_color || nil
end

end

def self.included(base)
base.extend(ClassMethods)
end

end
end
17 changes: 8 additions & 9 deletions lib/ProMotion/screen/nav_bar_module.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,6 @@ def set_nav_bar_buttons(side, buttons=[])
self.navigationItem.setRightBarButtonItems(buttons) if side == :right
end

# TODO: In PM 2.1+, entirely remove this deprecated method.
def set_nav_bar_left_button(title, args={})
mp "set_nav_bar_right_button and set_nav_bar_left_button have been removed. Use set_nav_bar_button :right/:left instead.", force_color: :yellow
end
alias_method :set_nav_bar_right_button, :set_nav_bar_left_button

def set_toolbar_items(buttons = [], animated = true)
if buttons
self.toolbarItems = Array(buttons).map{|b| b.is_a?(UIBarButtonItem) ? b : create_toolbar_button(b) }
Expand Down Expand Up @@ -81,7 +75,10 @@ def create_toolbar_button(args = {})
def bar_button_item(button_type, args)
return mp("`system_icon:` no longer supported. Use `system_item:` instead.", force_color: :yellow) if args[:system_icon]
return button_type if button_type.is_a?(UIBarButtonItem)
return bar_button_item_system_item(args) if args[:system_item]
if args[:system_item]
mp("Nav bar button specified both `system_item:` and `title:`. Title will be ignored.", force_color: :yellow) if args[:title]
return bar_button_item_system_item(args)
end
return bar_button_item_image(button_type, args) if button_type.is_a?(UIImage)
return bar_button_item_string(button_type, args) if button_type.is_a?(String)
return bar_button_item_custom(button_type) if button_type.is_a?(UIView)
Expand Down Expand Up @@ -111,6 +108,7 @@ def bar_button_item_custom(custom_view)
end

def map_bar_button_system_item(symbol)
mp("Nav bar button stytem item `:page_curl` has been deprecated.", force_color: :yellow) if symbol == :page_curl
{
done: UIBarButtonSystemItemDone,
cancel: UIBarButtonSystemItemCancel,
Expand All @@ -135,14 +133,15 @@ def map_bar_button_system_item(symbol)
fast_forward: UIBarButtonSystemItemFastForward,
undo: UIBarButtonSystemItemUndo,
redo: UIBarButtonSystemItemRedo,
page_curl: UIBarButtonSystemItemPageCurl
page_curl: UIBarButtonSystemItemPageCurl # DEPRECATED
}[symbol] || UIBarButtonSystemItemDone
end

def map_bar_button_item_style(symbol)
mp("Nav bar button style `:bordered` has been deprecated.", force_color: :yellow) if symbol == :bordered
{
plain: UIBarButtonItemStylePlain,
bordered: UIBarButtonItemStyleBordered,
bordered: UIBarButtonItemStyleBordered, # DEPRECATED
done: UIBarButtonItemStyleDone
}[symbol] || UIBarButtonItemStyleDone
end
Expand Down
48 changes: 3 additions & 45 deletions lib/ProMotion/screen/screen_module.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module ScreenModule
include ProMotion::ScreenNavigation
include ProMotion::Styling
include ProMotion::NavBarModule
include ProMotion::StatusBarModule
include ProMotion::Tabs
include ProMotion::SplitScreen if UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad || (UIDevice.currentDevice.systemVersion.to_i >= 8 )

Expand Down Expand Up @@ -41,7 +42,6 @@ def view_did_load

def view_will_appear(animated)
super
resolve_status_bar
self.will_appear

self.will_present if isMovingToParentViewController
Expand Down Expand Up @@ -179,38 +179,12 @@ def resolve_title
end
end

def resolve_status_bar
case self.class.status_bar_type
when :none
status_bar_hidden true
when :light
status_bar_hidden false
status_bar_style UIStatusBarStyleLightContent
when :dark
status_bar_hidden false
status_bar_style UIStatusBarStyleDefault
else
return status_bar_hidden true if UIApplication.sharedApplication.isStatusBarHidden
status_bar_hidden false
global_style = NSBundle.mainBundle.objectForInfoDictionaryKey("UIStatusBarStyle")
status_bar_style global_style ? Object.const_get(global_style) : UIStatusBarStyleDefault
end
end

def add_nav_bar_buttons
self.class.get_nav_bar_button.each do |button_args|
set_nav_bar_button(button_args[:side], button_args)
end
end

def status_bar_hidden(hidden)
UIApplication.sharedApplication.setStatusBarHidden(hidden, withAnimation:self.class.status_bar_animation)
end

def status_bar_style(style)
UIApplication.sharedApplication.setStatusBarStyle(style)
end

def apply_properties(args)
reserved_args = [ :nav_bar, :hide_nav_bar, :hide_tab_bar, :animated, :close_all, :in_tab, :in_detail, :in_master, :to_screen, :toolbar ]
set_attributes self, args.dup.delete_if { |k,v| reserved_args.include?(k) }
Expand All @@ -227,7 +201,6 @@ def check_ancestry
end
end

# Class methods
module ClassMethods
def title(t=nil)
if t && t.is_a?(String) == false
Expand All @@ -253,22 +226,6 @@ def title_view(t)
@title_type = :view
end

def status_bar(style=nil, args={})
if NSBundle.mainBundle.objectForInfoDictionaryKey('UIViewControllerBasedStatusBarAppearance').nil?
mp "status_bar will have no effect unless you set 'UIViewControllerBasedStatusBarAppearance' to false in your info.plist", force_color: :yellow
end
@status_bar_style = style
@status_bar_animation = args[:animation] if args[:animation]
end

def status_bar_type
@status_bar_style || :default
end

def status_bar_animation
@status_bar_animation || UIStatusBarAnimationSlide
end

def nav_bar(enabled, args={})
@nav_bar_args = ({ nav_bar: enabled }).merge(args)
end
Expand All @@ -291,7 +248,8 @@ def get_nav_bar_button

def self.included(base)
base.extend(ClassMethods)
base.extend(TabClassMethods) # TODO: Is there a better way?
base.extend(StatusBarModule::ClassMethods)
base.extend(Tabs::ClassMethods)
end
end
end
Loading