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

Always popover #17

Merged
merged 18 commits into from
Jul 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@ You can even use the `make_button` helper to create custom buttons to add:
rmq.app.alert(title: "Actions!", message: "Actions created with `make_button` helper.", actions: button_list)
```


If you want to present your alert in :sheet style and you are on iPad, you have to provide the `:source` for the popover (either a UIView or a UIBarButtonItem)
```ruby
rmq.append(UIButton, :my_button).on(:tap) do |sender|
rmq.app.alert(title: "Actions!", message: "Alert from a Popover.", actions: [:ok, :cancel], style:sheet, source: sender)
end
```

*iOS 8+ options*
These options work only on iOS 8+
* `:modal` will prevent the popover to be close by tapping outside the popover
* `:arrow_direction` will force the direction of the popover arrow. Valid values are `:up`, `:down`, `:left`, `:right` or `:any`


## Available Templates

Button templates are provided [HERE](https://github.com/GantMan/RedAlert/blob/master/lib/project/button_templates.rb)
Expand Down
1 change: 1 addition & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ Motion::Project::App.setup do |app|
app.identifier = 'com.gantlaborde.red_alert'
app.name = 'RedAlert'
app.deployment_target = ENV["DEPLOYMENT_TARGET"] if ENV["DEPLOYMENT_TARGET"]
app.device_family = [:iphone, :ipad]
end
27 changes: 17 additions & 10 deletions app/controllers/main_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ def viewDidLoad

# Simple action sheet example.
# OK button that doesn't care when pressed.
acs.append(UIButton, :alert_controller_four).on(:tap) do
rmq.app.alert(title: "Hey there!", message: "My style is :sheet", style: :sheet) do |action_type|
acs.append(UIButton, :alert_controller_four).on(:tap) do |sender|
rmq.app.alert(title: "Hey there!", message: "My style is :sheet", style: :sheet, source: sender) do |action_type|
puts "you clicked #{action_type}"
end
end

# Sheet with no message
acs.append(UIButton, :alert_controller_no_message).on(:tap) do
rmq.app.alert(message: nil, style: :sheet, actions: :yes_no_cancel ) do |action_type|
acs.append(UIButton, :alert_controller_no_message).on(:tap) do |sender|
rmq.app.alert(message: nil, style: :sheet, actions: :yes_no_cancel, source: sender) do |action_type|
puts "you clicked #{action_type}"
end
end
Expand All @@ -59,14 +59,14 @@ def viewDidLoad
# Text field example with :input style.
acs.append(UIButton, :alert_controller_fields_one).on(:tap) do
rmq.app.alert(title: "Text Field", message: "My style is :input", style: :input) do |action_type, fields|
puts "you entered '#{fields[:text].text}"
puts "you entered '#{fields[:text].text}'"
end
end

# Text field example with :input style and placeholder.
acs.append(UIButton, :alert_controller_fields_two).on(:tap) do
rmq.app.alert(title: "Text Field", message: "My style is :input", style: :input, placeholder: "Some Placeholder") do |action_type, fields|
puts "you entered '#{fields[:text].text}"
puts "you entered '#{fields[:text].text}'"
end
end

Expand Down Expand Up @@ -129,7 +129,7 @@ def viewDidLoad
end

# Alert example with 4 buttons, each made with `make_button` helper.
acs.append(UIButton, :custom_actions_helper_sheet).on(:tap) do
acs.append(UIButton, :custom_actions_helper_sheet).on(:tap) do |sender|
ok = rmq.app.make_button {
puts "OK pressed"
}
Expand All @@ -148,7 +148,14 @@ def viewDidLoad

button_list = [ok, yes, cancel, destructive]

rmq.app.alert(title: "Actions!", message: "Actions created with `make_button` helper.", actions: button_list, style: :sheet)
rmq.app.alert(title: "Actions!", message: "Actions created with `make_button` helper.", actions: button_list, style: :sheet, source: sender)
end

# Alert from popover
acs.append(UIButton, :alert_from_popover).on(:tap) do |sender|
label = rmq.find(:template_tour).get
label.sizeToFit
rmq.app.alert(title: "Popover", message: "Presented from popover (if iPad)", actions: [:ok], style: :sheet, source: label, arrow_direction: [:left,:right])
end

acs.append(UILabel, :template_tour)
Expand All @@ -166,8 +173,8 @@ def viewDidLoad
end
end

acs.append(UIButton, :alert_controller_yesnocancel).on(:tap) do
rmq.app.alert(message: "Would you like a sandwich?", actions: :yes_no_cancel, style: :sheet) do |title|
acs.append(UIButton, :alert_controller_yesnocancel).on(:tap) do |sender|
rmq.app.alert(message: "Would you like a sandwich?", actions: :yes_no_cancel, style: :sheet, source: sender) do |title|
case title
when :yes
puts "Here's your Sandwich!"
Expand Down
5 changes: 5 additions & 0 deletions app/stylesheets/main_stylesheet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ def custom_actions_helper_sheet st
st.text = "Custom Sheet Actions"
end

def alert_from_popover st
basic_button(st)
st.text = "Alert From Popover on iPad"
end

def usage_tour st
st.frame = {bp: 10, w: screen_width - 20, l: 10, h:20}
st.clips_to_bounds = false
Expand Down
14 changes: 13 additions & 1 deletion lib/project/action_sheet_provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ def build(actions, fieldset=nil, opts={})
@actions = actions
@opts = opts

raise ArgumentError.new "Please provide a :source view to use :sheet on iPad" if rmq.device.ipad? and !@opts[:source]

# grab the first cancel action
cancel_action = actions.find { |action| action.cancel? }

Expand Down Expand Up @@ -43,7 +45,17 @@ def build(actions, fieldset=nil, opts={})
def show
# when we show, the view controller will disappear because a different _UIAlertOverlayWindow window will take its place
@view_controller = rmq.view_controller
@action_sheet.showInView(@view_controller.view)

if rmq.device.ipad?
source = @opts[:source]
if source.is_a?(UIBarButtonItem)
@action_sheet.showFromBarButtonItem(source, animated: true)
else
@action_sheet.showFromRect(source.frame, inView: @view_controller.view, animated: true)
end
else
@action_sheet.showInView(@view_controller.view)
end
end

private
Expand Down
10 changes: 9 additions & 1 deletion lib/project/alert_constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,13 @@ module AlertConstants
destructive: UIAlertActionStyleDestructive
}

ALERT_POPOVER_ARROW_DIRECTION = {
up: UIPopoverArrowDirectionUp,
down: UIPopoverArrowDirectionDown,
left: UIPopoverArrowDirectionLeft,
right: UIPopoverArrowDirectionRight,
any: UIPopoverArrowDirectionAny
}

end
end
end
28 changes: 28 additions & 0 deletions lib/project/alert_controller_provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,34 @@ def build(actions, fieldset = nil, opts={})
@alert_controller.addAction action
end

# popover
if @opts[:style] == :sheet and rmq.device.ipad?
raise ArgumentError.new "Please provide a :source view to use :sheet on iPad" unless @opts[:source]
source = @opts[:source]
@alert_controller.setModalPresentationStyle(UIModalPresentationPopover)
if @opts[:modal]
@alert_controller.setModalInPopover(true)
end
if source.is_a?(UIBarButtonItem)
@alert_controller.popoverPresentationController.barButtonItem = source
else
@alert_controller.popoverPresentationController.sourceView = source
end
@alert_controller.popoverPresentationController.sourceRect = source.bounds

if @opts[:arrow_direction]
directions = @opts[:arrow_direction]
unless directions.is_a?(Array)
directions = [directions]
end
arrow_direction = 0
directions.each do |direction|
arrow_direction |= RubyMotionQuery::AlertConstants::ALERT_POPOVER_ARROW_DIRECTION[direction]
end
@alert_controller.popoverPresentationController.permittedArrowDirections = arrow_direction
end
end

self
end

Expand Down
5 changes: 4 additions & 1 deletion lib/project/red_alert.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@ def alert(opts={}, &block)
# ------------------------------------
opts = {message: opts} if opts.is_a? String
opts = {style: :alert, animated: true, show_now: true}.merge(opts)

# Ability to make no message
opts[:message] = if opts.has_key?(:message)
opts[:message].nil? ? nil : opts[:message].to_s
else
NSLocalizedString("Alert!", nil)
end

opts[:style] = VALID_STYLES.include?(opts[:style]) ? opts[:style] : :alert
if opts[:style] == :sheet and rmq.device.ipad? and opts[:source].nil?
raise ArgumentError.new "Please provide a :source view to use :sheet on iPad"
end
opts[:fields] = opts[:style] == :custom && opts[:fields] ? opts[:fields] : {text: {placeholder: ''}}
api = rmq.device.ios_at_least?(8) ? :modern : :deprecated
api = :deprecated if rmq.device.ios_at_least?(8) && opts[:api] == :deprecated
Expand Down
4 changes: 2 additions & 2 deletions resources/fr.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"Yes" = "Oui";
"No" = "Pas";
"No" = "Non";
"Cancel" = "Annuler";
"OK" = "OK";
"Delete" = "Effacer";
"Alert!" = "Alerte!";
"Login" = "S'identifier";
"Login" = "Identifiant";
"Password" = "Mot De Passe";
"Current Password" = "Mot De Passe Actuel";
"New Password" = "Nouveau Mot De Passe";
12 changes: 9 additions & 3 deletions spec/action_sheet_provider_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
@ok = RubyMotionQuery::AlertAction.new(title: "OK", tag: :ok, style: :default)
@cancel = RubyMotionQuery::AlertAction.new(title: "Cancel", tag: :cancel, style: :cancel)
@boom = RubyMotionQuery::AlertAction.new(title: "Boom!", tag: :boom, style: :destructive)
@view = UIView.new
end

it "should prevent nil actions" do
Expand All @@ -16,10 +17,15 @@
Proc.new { @p.build([]) }.should.raise(ArgumentError)
end

it "should raise an error on iPad but not on iPhone" do
Proc.new { @p.build([@ok], nil, style: :sheet) }.should.raise(ArgumentError) if rmq.device.ipad?
Proc.new { @p.build([@ok], nil, style: :sheet) }.should.not.raise(ArgumentError) if rmq.device.iphone?
end

describe "action sheet with ok button" do

before do
@p.build [@ok], nil, title: "title"
@p.build [@ok], nil, title: "title", source: @view
end

it "should have the right title" do
Expand Down Expand Up @@ -51,7 +57,7 @@
describe "action sheet with a cancel button" do

before do
@p.build [@cancel], nil, title: "title"
@p.build [@cancel], nil, title: "title", source: @view
end

it "should have 1 button" do
Expand All @@ -75,7 +81,7 @@
describe "action sheet with a destructive button" do

before do
@p.build [@boom], nil, title: "title"
@p.build [@boom], nil, title: "title", source: @view
end

it "should have 1 button" do
Expand Down
7 changes: 6 additions & 1 deletion spec/alert_controller_provider_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@
Proc.new { @p.build([]) }.should.raise(ArgumentError)
end

it "should raise an error on iPad but not on iPhone" do
Proc.new { @p.build([@ok], nil, style: :sheet) }.should.raise(ArgumentError) if rmq.device.ipad?
Proc.new { @p.build([@ok], nil, style: :sheet) }.should.not.raise(ArgumentError) if rmq.device.iphone?
end

context 'without fields' do

describe "alert controller with ok button" do
Expand All @@ -119,7 +124,7 @@
describe "alert controller with a cancel button" do

before do
@p.build [@cancel], nil, title: "title", style: :sheet
@p.build [@cancel], nil, title: "title", style: :sheet, source: UIView.new
end

behaves_like "an alert controller with a cancel button"
Expand Down
4 changes: 2 additions & 2 deletions spec/i18n_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,15 @@ def NSLocalizedString(key, comment)
end

it "should have an english No button" do
@ac.actions[1].title.should == "Pas"
@ac.actions[1].title.should == "Non"
end

it "should have an english Cancel button" do
@ac.actions[2].title.should == "Annuler"
end

it 'should have French placeholder text for the first field' do
@ac.textFields[0].placeholder.should == "S'identifier"
@ac.textFields[0].placeholder.should == "Identifiant"
end

it 'should have French placeholder text for the second field' do
Expand Down
20 changes: 13 additions & 7 deletions spec/red_alert_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@
before do
wait TEST_DELAY do
UIView.setAnimationsEnabled false
@view = UIView.new
@vc = rmq.view_controller
@provider = rmq.app.alert(message: "hello", show_now: false, animated: false, style: :sheet, api: :deprecated)
@provider = rmq.app.alert(message: "hello", show_now: false, animated: false, style: :sheet, api: :deprecated, source: @view)
end
end

Expand All @@ -70,20 +71,25 @@
@provider.action_sheet.class.should == UIActionSheet
end

it "should raise an error on iPad but not on iPhone" do
Proc.new { rmq.app.alert(style: :sheet) }.should.raise(ArgumentError) if rmq.device.ipad?
Proc.new { rmq.app.alert(style: :sheet) }.should.not.raise(ArgumentError) if rmq.device.iphone?
end

it "has a valid blank title" do
rmq.app.alert(show_now: false, animated: false, style: :sheet, api: :deprecated).action_sheet.title.should == "Alert!"
rmq.app.alert(show_now: false, animated: false, style: :sheet, api: :deprecated, source: @view).action_sheet.title.should == NSLocalizedString("Alert!", nil)
end

it "has a valid title when given" do
rmq.app.alert(title: "hi", show_now: false, animated: false, style: :sheet, api: :deprecated).action_sheet.title.should == "hi"
rmq.app.alert(title: "hi", show_now: false, animated: false, style: :sheet, api: :deprecated, source: @view).action_sheet.title.should == "hi"
end

it "should transfer message over to title when there is no title" do
rmq.app.alert(message: "hi", show_now: false, animated: false, style: :sheet, api: :deprecated).action_sheet.title.should == "hi"
rmq.app.alert(message: "hi", show_now: false, animated: false, style: :sheet, api: :deprecated, source: @view).action_sheet.title.should == "hi"
end

it "should never overwrite title with message" do
rmq.app.alert(title: "1", message: "2", show_now: false, animated: false, style: :sheet, api: :deprecated).action_sheet.title.should == "1"
rmq.app.alert(title: "1", message: "2", show_now: false, animated: false, style: :sheet, api: :deprecated, source: @view).action_sheet.title.should == "1"
end

it "should be visible at the right time" do
Expand Down Expand Up @@ -167,8 +173,8 @@
end

it 'has the correct placeholder text for the change password template fields' do
@provider.alert_view.textFieldAtIndex(0).placeholder.should == "Current Password"
@provider.alert_view.textFieldAtIndex(1).placeholder.should == "New Password"
@provider.alert_view.textFieldAtIndex(0).placeholder.should == NSLocalizedString("Current Password", nil)
@provider.alert_view.textFieldAtIndex(1).placeholder.should == NSLocalizedString("New Password", nil)
end

end
Expand Down