bubble-wrap 1.1.2 → 1.1.3
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.
- data/Gemfile.lock +1 -1
- data/README.md +32 -9
- data/Rakefile +1 -5
- data/lib/bubble-wrap/all.rb +1 -1
- data/lib/bubble-wrap/http.rb +1 -0
- data/lib/bubble-wrap/media.rb +8 -0
- data/lib/bubble-wrap/version.rb +1 -1
- data/motion/core/app.rb +5 -0
- data/motion/core/device.rb +1 -1
- data/motion/core/json.rb +1 -0
- data/motion/core/ns_url_request.rb +4 -2
- data/motion/core/persistence.rb +7 -1
- data/motion/core/string.rb +2 -2
- data/motion/http.rb +81 -65
- data/motion/location/location.rb +2 -2
- data/motion/media/media.rb +15 -0
- data/motion/media/player.rb +139 -0
- data/motion/test_suite_delegate.rb +1 -0
- data/resources/test.mp3 +0 -0
- data/samples/camera/Gemfile +3 -0
- data/samples/camera/README.md +4 -0
- data/samples/camera/Rakefile +9 -0
- data/samples/camera/app/app_delegate.rb +8 -0
- data/samples/camera/app/controllers/camera_controller.rb +61 -0
- data/samples/camera/spec/main_spec.rb +9 -0
- data/samples/location/.gitignore +5 -0
- data/samples/location/Gemfile +3 -0
- data/samples/location/README.md +4 -0
- data/samples/location/Rakefile +10 -0
- data/samples/location/app/app_delegate.rb +8 -0
- data/samples/location/app/controllers/image_list_controller.rb +30 -0
- data/samples/location/app/models/places.rb +15 -0
- data/samples/location/spec/main_spec.rb +9 -0
- data/spec/motion/core/app_spec.rb +7 -1
- data/spec/motion/core/json_spec.rb +4 -0
- data/spec/motion/core/persistence_spec.rb +7 -3
- data/spec/motion/core/string_spec.rb +24 -0
- data/spec/motion/http_spec.rb +73 -61
- data/spec/motion/media/player_spec.rb +77 -0
- metadata +57 -14
data/motion/location/location.rb
CHANGED
@@ -117,8 +117,8 @@ module BubbleWrap
|
|
117
117
|
if @retries > @options[:retries]
|
118
118
|
error(Error::LOCATION_UNKNOWN)
|
119
119
|
else
|
120
|
-
self.
|
121
|
-
self.
|
120
|
+
self.location_manager.stopUpdatingLocation
|
121
|
+
self.location_manager.startUpdatingLocation
|
122
122
|
end
|
123
123
|
when KCLErrorNetwork
|
124
124
|
error(Error::NETWORK_FAILURE)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module BubbleWrap
|
2
|
+
module Media
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def play_modal(*args, &block)
|
6
|
+
Media::Player.new.retain.send(:play_modal, *args, &block)
|
7
|
+
end
|
8
|
+
|
9
|
+
def play(*args, &block)
|
10
|
+
Media::Player.new.retain.send(:play, *args, &block)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
::Media = BubbleWrap::Media
|
@@ -0,0 +1,139 @@
|
|
1
|
+
module BubbleWrap
|
2
|
+
module Media
|
3
|
+
module Error
|
4
|
+
class InvalidPlayerType < StandardError; end
|
5
|
+
class NilPlayerCallback < StandardError; end
|
6
|
+
end
|
7
|
+
|
8
|
+
class Player
|
9
|
+
attr_reader :media_player
|
10
|
+
############
|
11
|
+
# Playing Media
|
12
|
+
|
13
|
+
# Plays media in the system-default modal controller
|
14
|
+
# Takes same parameters as #play
|
15
|
+
# NOTE: If you don't supply a :controller option,
|
16
|
+
# the rootViewController will be used.
|
17
|
+
def play_modal(content_url, options = {})
|
18
|
+
play(content_url, options.merge(modal: true))
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param [String, NSURL] content_url is either a local or remote string
|
22
|
+
# for the location of the media you're playing.
|
23
|
+
# NOTE: if you're playing a remote file, your server needs to support
|
24
|
+
# range requests for that URL.
|
25
|
+
#
|
26
|
+
# @param [Hash] options to open the MPMoviePlayerController with
|
27
|
+
# the form {
|
28
|
+
# ### These are properties of MPMoviePlayerController
|
29
|
+
# allows_air_play: true/false; default false,
|
30
|
+
# control_style: [MPMovieControlStyle]; default MPMovieControlStyleDefault,
|
31
|
+
# end_playback_time: [Integer] end time (in seconds) for media; default is -1,
|
32
|
+
# initial_playback_time: [Integer] start time (in seconds) for media; default is -1,
|
33
|
+
# movie_source_type: [MPMovieSourceType] a "hint" so the player knows how to load the data type;
|
34
|
+
# either MPMovieSourceTypeFile or MPMovieSourceTypeStreaming; default is MPMovieSourceTypeUnknown
|
35
|
+
# which may delay playback,
|
36
|
+
# repeat_mode: [MPMovieRepeatMode] how the player repeats at the end of playback; defautl is
|
37
|
+
# MPMovieRepeatModeNone
|
38
|
+
# scaling_mode: [MPMovieScalingMode] scaling mode for movies; default is MPMovieScalingModeAspectFit
|
39
|
+
# should_autoplay: true/false; default true,
|
40
|
+
# use_application_audio_session: true/false; default true.
|
41
|
+
#
|
42
|
+
# ### These are properties of just the ::Player
|
43
|
+
# delay_play: true/false, default false. If false then you have to manually call
|
44
|
+
# @media_player.play in your code
|
45
|
+
# modal: true/false; default false,
|
46
|
+
# controller: [UIViewController] used to present the player modally;
|
47
|
+
# default uses root view controller of window
|
48
|
+
# }
|
49
|
+
#
|
50
|
+
# @block for when setup is done; use this block to present
|
51
|
+
# @media_player.view if options[:modal] == false
|
52
|
+
#
|
53
|
+
# EX
|
54
|
+
# From a local URL:
|
55
|
+
# file = File.join(App.resources_path, 'test.mp3')
|
56
|
+
# BW::Media::Player.play(NSURL.fileURLWithPath(file)) do |media_player|
|
57
|
+
# media_player.view.frame = some_view.bounds
|
58
|
+
# self.view.addSubview media_player.view
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# From a remote URL:
|
62
|
+
# BW::Media::Player.play("http://www.hrupin.com/wp-content/uploads/mp3/testsong_20_sec.mp3") do |media_player|
|
63
|
+
# media_player.view.frame = some_view.bounds
|
64
|
+
# self.view.addSubview media_player.view
|
65
|
+
# end
|
66
|
+
def play(content_url, options = {}, &block)
|
67
|
+
display_modal = !!options[:modal]
|
68
|
+
|
69
|
+
klass = display_modal ? MPMoviePlayerViewController : MPMoviePlayerController
|
70
|
+
|
71
|
+
content_url = content_url.is_a?(NSURL) ? content_url : NSURL.URLWithString(content_url)
|
72
|
+
@media_player = klass.alloc.initWithContentURL(content_url)
|
73
|
+
|
74
|
+
self.media_player.prepareToPlay if not display_modal
|
75
|
+
|
76
|
+
options[:delay_play] = false if not options.has_key? :delay_play
|
77
|
+
set_player_options(options)
|
78
|
+
|
79
|
+
NSNotificationCenter.defaultCenter.observe MPMoviePlayerPlaybackDidFinishNotification do |notification|
|
80
|
+
h = notification.userInfo
|
81
|
+
error = h["error"]
|
82
|
+
if error
|
83
|
+
p "BW::Media::Player error: #{error.userInfo.inspect}"
|
84
|
+
p "Code: #{error.code}, Domain: #{error.domain}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
if display_modal
|
89
|
+
@presenting_controller = options[:controller]
|
90
|
+
@presenting_controller ||= UIApplication.sharedApplication.keyWindow.rootViewController
|
91
|
+
@presenting_controller.presentMoviePlayerViewControllerAnimated(@media_player)
|
92
|
+
else
|
93
|
+
if block.nil?
|
94
|
+
raise Error::NilPlayerCallback, "no block callback given in #play; you need\
|
95
|
+
to supply one if options[:modal] == false"
|
96
|
+
end
|
97
|
+
block.call(@media_player)
|
98
|
+
end
|
99
|
+
|
100
|
+
if not display_modal and not options[:delay_play]
|
101
|
+
@media_player.play
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Stops playback for a Media::Player
|
106
|
+
def stop
|
107
|
+
if @media_player.is_a? MPMoviePlayerViewController
|
108
|
+
@presenting_controller.dismissMoviePlayerViewControllerAnimated
|
109
|
+
@presenting_controller = nil
|
110
|
+
else
|
111
|
+
@media_player.stop
|
112
|
+
end
|
113
|
+
@media_player = nil
|
114
|
+
end
|
115
|
+
|
116
|
+
def media_player
|
117
|
+
if @media_player.is_a? MPMoviePlayerViewController
|
118
|
+
return @media_player.moviePlayer
|
119
|
+
end
|
120
|
+
@media_player
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
# RubyMotion has a problem calling some objective-c methods at runtime, so we can't
|
125
|
+
# do any cool `camelize` tricks.
|
126
|
+
def set_player_options(options)
|
127
|
+
self.media_player.allowsAirPlay = options[:allows_air_play] if options.has_key? :allows_air_play
|
128
|
+
self.media_player.controlStyle = options[:control_style] if options.has_key? :control_style
|
129
|
+
self.media_player.endPlaybackTime = options[:end_playback_time] if options.has_key? :end_playback_time
|
130
|
+
self.media_player.initialPlaybackTime = options[:initial_playback_time] if options.has_key? :initial_playback_time
|
131
|
+
self.media_player.movieSourceType = options[:movie_source_type] if options.has_key? :movie_source_type
|
132
|
+
self.media_player.repeatMode = options[:repeat_mode] if options.has_key? :repeat_mode
|
133
|
+
self.media_player.scalingMode = options[:scaling_mode] if options.has_key? :scaling_mode
|
134
|
+
self.media_player.shouldAutoplay = options[:should_autoplay] if options.has_key? :should_autoplay
|
135
|
+
self.media_player.useApplicationAudioSession = options[:use_application_audio_session] if options.has_key? :use_application_audio_session
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -4,6 +4,7 @@ class TestSuiteDelegate
|
|
4
4
|
def application(application, didFinishLaunchingWithOptions:launchOptions)
|
5
5
|
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
|
6
6
|
@window.rootViewController = UIViewController.alloc.init
|
7
|
+
@window.makeKeyAndVisible
|
7
8
|
true
|
8
9
|
end
|
9
10
|
end
|
data/resources/test.mp3
ADDED
Binary file
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class AppDelegate
|
2
|
+
def application(application, didFinishLaunchingWithOptions:launchOptions)
|
3
|
+
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
|
4
|
+
camera_controller = CameraController.alloc.initWithNibName(nil, bundle:nil)
|
5
|
+
@window.rootViewController = camera_controller
|
6
|
+
@window.makeKeyAndVisible
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class CameraController < UIViewController
|
2
|
+
|
3
|
+
def viewDidLoad
|
4
|
+
super
|
5
|
+
|
6
|
+
@buttons = []
|
7
|
+
|
8
|
+
@library = UIButton.buttonWithType(UIButtonTypeRoundedRect)
|
9
|
+
@library.setTitle("Library", forState:UIControlStateNormal)
|
10
|
+
@library.sizeToFit
|
11
|
+
@library.when UIControlEventTouchUpInside do
|
12
|
+
BW::Device.camera.any.picture(media_types: [:image]) do |result|
|
13
|
+
image_view = UIImageView.alloc.initWithImage(result[:original_image])
|
14
|
+
add_image_view(image_view)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
self.view.addSubview(@library)
|
18
|
+
@buttons << @library
|
19
|
+
|
20
|
+
if BW::Device.camera.front?
|
21
|
+
@front = UIButton.buttonWithType(UIButtonTypeRoundedRect)
|
22
|
+
@front.setTitle("Front", forState:UIControlStateNormal)
|
23
|
+
@front.sizeToFit
|
24
|
+
last_button = @buttons.last
|
25
|
+
@front.frame = [[last_button.frame.origin.x, last_button.frame.origin.y + last_button.frame.size.height + 10], @front.frame.size]
|
26
|
+
@front.when UIControlEventTouchUpInside do
|
27
|
+
BW::Device.camera.front.picture(media_types: [:image]) do |result|
|
28
|
+
image_view = UIImageView.alloc.initWithImage(result[:original_image])
|
29
|
+
add_image_view(image_view)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
self.view.addSubview(@front)
|
33
|
+
@buttons << @front
|
34
|
+
end
|
35
|
+
|
36
|
+
if BW::Device.camera.rear?
|
37
|
+
@rear = UIButton.buttonWithType(UIButtonTypeRoundedRect)
|
38
|
+
@rear.setTitle("Read", forState:UIControlStateNormal)
|
39
|
+
@rear.sizeToFit
|
40
|
+
last_button = @buttons.last
|
41
|
+
@rear.frame = [[last_button.frame.origin.x, last_button.frame.origin.y + last_button.frame.size.height + 10], @rear.frame.size]
|
42
|
+
@rear.when UIControlEventTouchUpInside do
|
43
|
+
BW::Device.camera.rear.picture(media_types: [:image]) do |result|
|
44
|
+
image_view = UIImageView.alloc.initWithImage(result[:original_image])
|
45
|
+
add_image_view(image_view)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
self.view.addSubview(@rear)
|
49
|
+
@buttons << @rear
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_image_view(image_view)
|
54
|
+
image_view.frame = [CGPointZero, self.view.frame.size]
|
55
|
+
image_view.center = [self.view.frame.size.width / 2, self.view.frame.size.height / 2]
|
56
|
+
self.view.addSubview(image_view)
|
57
|
+
@buttons.each do |button|
|
58
|
+
self.view.bringSubviewToFront(button)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class AppDelegate
|
2
|
+
def application(application, didFinishLaunchingWithOptions:launchOptions)
|
3
|
+
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
|
4
|
+
places_list_controller = PlacesListController.alloc.init
|
5
|
+
@window.rootViewController = places_list_controller
|
6
|
+
@window.makeKeyAndVisible
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class PlacesListController < UITableViewController
|
2
|
+
attr_accessor :places_list
|
3
|
+
|
4
|
+
def viewDidLoad
|
5
|
+
@places_list = []
|
6
|
+
Places.load(self)
|
7
|
+
view.dataSource = view.delegate = self
|
8
|
+
end
|
9
|
+
|
10
|
+
def viewWillAppear(animated)
|
11
|
+
view.reloadData
|
12
|
+
end
|
13
|
+
|
14
|
+
def tableView(tableView, numberOfRowsInSection:section)
|
15
|
+
@places_list.size
|
16
|
+
end
|
17
|
+
|
18
|
+
def reloadData
|
19
|
+
view.reloadData
|
20
|
+
end
|
21
|
+
|
22
|
+
CellID = 'CellIdentifier'
|
23
|
+
def tableView(tableView, cellForRowAtIndexPath:indexPath)
|
24
|
+
cell = tableView.dequeueReusableCellWithIdentifier(CellID) || UITableViewCell.alloc.initWithStyle(UITableViewCellStyleSubtitle, reuseIdentifier:CellID)
|
25
|
+
placeItem= @places_list[indexPath.row]
|
26
|
+
cell.textLabel.text = placeItem
|
27
|
+
cell
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Places
|
2
|
+
API_KEY = ""
|
3
|
+
#See google places documentation at https://developers.google.com/places/documentation/ to obtain a key
|
4
|
+
|
5
|
+
def self.load(places_list_controller)
|
6
|
+
BW::Location.get do |result|
|
7
|
+
BW::Location.stop
|
8
|
+
BubbleWrap::HTTP.get("https://maps.googleapis.com/maps/api/place/search/json?location=#{result[:to].latitude},#{result[:to].longitude}&radius=500&sensor=false&key=#{API_KEY}") do |response|
|
9
|
+
names = BW::JSON.parse(response.body.to_str)["results"].map{|r| r["name"]}
|
10
|
+
places_list_controller.places_list = names
|
11
|
+
places_list_controller.reloadData
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -25,7 +25,7 @@ describe BubbleWrap::App do
|
|
25
25
|
|
26
26
|
describe '.alert' do
|
27
27
|
after do
|
28
|
-
@alert.
|
28
|
+
@alert.dismissWithClickedButtonIndex(@alert.cancelButtonIndex, animated: false)
|
29
29
|
end
|
30
30
|
|
31
31
|
describe "with only one string argument" do
|
@@ -176,6 +176,12 @@ describe BubbleWrap::App do
|
|
176
176
|
end
|
177
177
|
end
|
178
178
|
|
179
|
+
describe '.app' do
|
180
|
+
it 'returns UIApplication.sharedApplication' do
|
181
|
+
BW::App.shared.should == UIApplication.sharedApplication
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
179
185
|
describe '.run_after' do
|
180
186
|
class DelayedRunAfterTest; attr_accessor :test_value end
|
181
187
|
|
@@ -32,6 +32,10 @@ EOS
|
|
32
32
|
@parsed = BubbleWrap::JSON.parse(@json_string)
|
33
33
|
end
|
34
34
|
|
35
|
+
it "doesn't crash when data is nil" do
|
36
|
+
Proc.new { BW::JSON.parse(nil) }.should.not.raise Exception
|
37
|
+
end
|
38
|
+
|
35
39
|
it "should convert a top object into a Ruby hash" do
|
36
40
|
obj = @parsed
|
37
41
|
obj.class.should == Hash
|
@@ -1,7 +1,7 @@
|
|
1
1
|
describe BubbleWrap::Persistence do
|
2
2
|
|
3
3
|
describe '.app_key' do
|
4
|
-
|
4
|
+
|
5
5
|
it "caches the @app_key" do
|
6
6
|
BubbleWrap::Persistence.instance_variable_get(:@app_key).should.equal nil
|
7
7
|
BubbleWrap::Persistence.app_key
|
@@ -21,7 +21,7 @@ describe BubbleWrap::Persistence do
|
|
21
21
|
BubbleWrap::Persistence['arbitraryNumber'] = 42
|
22
22
|
end.
|
23
23
|
should.not.raise(Exception)
|
24
|
-
end
|
24
|
+
end
|
25
25
|
|
26
26
|
it "must call synchronize" do
|
27
27
|
storage = NSUserDefaults.standardUserDefaults
|
@@ -29,7 +29,7 @@ describe BubbleWrap::Persistence do
|
|
29
29
|
|
30
30
|
BubbleWrap::Persistence['arbitraryNumber'] = 42
|
31
31
|
storage.instance_variable_get(:@sync_was_called).should.equal true
|
32
|
-
end
|
32
|
+
end
|
33
33
|
end
|
34
34
|
|
35
35
|
describe "storing multiple objects" do
|
@@ -60,5 +60,9 @@ describe BubbleWrap::Persistence do
|
|
60
60
|
BubbleWrap::Persistence['arbitraryNumber'].should == 42
|
61
61
|
BubbleWrap::Persistence[:arbitraryString].should == 'test string'
|
62
62
|
end
|
63
|
+
|
64
|
+
it 'returns fully functional strings' do
|
65
|
+
BubbleWrap::Persistence[:arbitraryString].methods.should == 'test string'.methods
|
66
|
+
end
|
63
67
|
end
|
64
68
|
end
|