bluepotion 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/project/alert_dialog/alert_dialog.rb +62 -0
- data/lib/project/blue_potion_net.rb +1 -1
- data/lib/project/potion.rb +2 -0
- data/lib/project/pro_motion/activities/pm_activity.rb +13 -1
- data/lib/project/pro_motion/activities/pm_navigation_activity.rb +1 -1
- data/lib/project/pro_motion/activities/pm_single_fragment_activity.rb +6 -0
- data/lib/project/pro_motion/fragments/pm_list_screen.rb +1 -36
- data/lib/project/pro_motion/fragments/pm_screen.rb +1 -36
- data/lib/project/pro_motion/fragments/pm_screen_module.rb +64 -12
- data/lib/project/pro_motion/pm_application.rb +16 -0
- data/lib/project/progress_hud/progress_hud.rb +38 -0
- data/lib/project/ruby_motion_query/rmq/base.rb +2 -2
- data/lib/project/ruby_motion_query/rmq/selectors.rb +1 -1
- data/lib/project/ruby_motion_query/rmq/traverse.rb +4 -0
- data/lib/project/ruby_motion_query/rmq_validation.rb +219 -0
- data/lib/project/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fdb0d8c6161c235baac6480838e5e1cabe94c6fa
|
4
|
+
data.tar.gz: b908f87be8c23fd810d18a48052bca355ad6c731
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: caf24b6c2f5646512dff78031b1e02e3ff7149013f15da9ec9daaee3aa51329f45ef14c5eaed5a26a12c587732e90e38a2e82e673e36155f986eee5bbce865da
|
7
|
+
data.tar.gz: def61d81138b2120c82ac3745a59e96879d7076b2f9b8810e4a0c188b31060ac8fb992f2f5f07789f3c11f63631d5f692ecbda79aaf7e1d14f4f8d0417bd6eeb
|
@@ -0,0 +1,62 @@
|
|
1
|
+
######################################################
|
2
|
+
# Example usage - since this is in PMApplication
|
3
|
+
######################################################
|
4
|
+
# app.alert(title: "Hey There", message: "Want a sandwich?") do |choice|
|
5
|
+
# case choice
|
6
|
+
# when "OK"
|
7
|
+
# mp "Here's your sandwich"
|
8
|
+
# when "Cancel"
|
9
|
+
# mp "Fine!"
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
|
13
|
+
# Generic AlertDialog
|
14
|
+
class AlertDialog < Android::App::DialogFragment
|
15
|
+
|
16
|
+
def initialize(options={}, &block)
|
17
|
+
|
18
|
+
# Defaults
|
19
|
+
@options = {
|
20
|
+
theme: Android::App::AlertDialog::THEME_HOLO_LIGHT,
|
21
|
+
title: "Alert!",
|
22
|
+
message: "",
|
23
|
+
positive_button: "OK",
|
24
|
+
negative_button: "Cancel",
|
25
|
+
positive_button_handler: self,
|
26
|
+
negative_button_handler: self,
|
27
|
+
show: true
|
28
|
+
}.merge(options)
|
29
|
+
|
30
|
+
@callback = block
|
31
|
+
|
32
|
+
self.show if @options[:show]
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def show(activity=rmq.activity)
|
37
|
+
super(activity.fragmentManager, "alert_dialog")
|
38
|
+
end
|
39
|
+
|
40
|
+
def onCreateDialog(saved_instance_state)
|
41
|
+
builder = Android::App::AlertDialog::Builder.new(getActivity(), @options[:theme])
|
42
|
+
|
43
|
+
builder.title = @options[:title]
|
44
|
+
builder.message = @options[:message]
|
45
|
+
|
46
|
+
# Add buttons if they are set
|
47
|
+
builder.setPositiveButton(@options[:positive_button], @options[:positive_button_handler]) if @options[:positive_button]
|
48
|
+
builder.setNegativeButton(@options[:negative_button], @options[:negative_button_handler]) if @options[:negative_button]
|
49
|
+
|
50
|
+
# Add custom view?
|
51
|
+
builder.view = @options[:view] if @options[:view]
|
52
|
+
|
53
|
+
# DONE!
|
54
|
+
builder.create()
|
55
|
+
end
|
56
|
+
|
57
|
+
def onClick(dialog, id)
|
58
|
+
button_text = (id == Android::App::AlertDialog::BUTTON_POSITIVE) ? @options[:positive_button] : @options[:negative_button]
|
59
|
+
@callback.call(button_text) if @callback
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -13,7 +13,7 @@
|
|
13
13
|
# @example
|
14
14
|
# # Create a session and do a single HTML get. It's better
|
15
15
|
# # to use the shared session below.
|
16
|
-
# app.net.get("http://google.com")do |response|
|
16
|
+
# app.net.get("http://google.com") do |response|
|
17
17
|
# mp response.object # <- HTML
|
18
18
|
# end
|
19
19
|
#
|
data/lib/project/potion.rb
CHANGED
@@ -9,6 +9,7 @@ module Potion
|
|
9
9
|
Bundle = Android::Os::Bundle
|
10
10
|
Environment = Android::Os::Environment
|
11
11
|
Uri = Android::Net::Uri
|
12
|
+
Url = Java::Net::URL
|
12
13
|
ArrayAdapter = Android::Widget::ArrayAdapter
|
13
14
|
BaseAdapter = Android::Widget::BaseAdapter
|
14
15
|
Dialog = Android::App::Dialog
|
@@ -37,6 +38,7 @@ module Potion
|
|
37
38
|
|
38
39
|
# Media
|
39
40
|
File = Java::Io::File
|
41
|
+
FileOutputStream = Java::Io::FileOutputStream
|
40
42
|
MediaStore = Android::Provider::MediaStore
|
41
43
|
Contacts = Android::Provider::ContactsContract::Contacts
|
42
44
|
end
|
@@ -18,6 +18,15 @@
|
|
18
18
|
mp "PMActivity on_create", debugging_only: true
|
19
19
|
end
|
20
20
|
|
21
|
+
# These 2 methods are needed to pass on to inherited activities
|
22
|
+
def onActivityResult(request_code, result_code, data)
|
23
|
+
on_activity_result(request_code, result_code, data)
|
24
|
+
end
|
25
|
+
|
26
|
+
def on_activity_result(request_code, result_code, data)
|
27
|
+
# Abstract
|
28
|
+
end
|
29
|
+
|
21
30
|
def onResume
|
22
31
|
super
|
23
32
|
on_resume
|
@@ -44,8 +53,11 @@
|
|
44
53
|
def on_create_menu(_); end
|
45
54
|
|
46
55
|
def onOptionsItemSelected(item)
|
56
|
+
home_const = 16908332 # R.id.home
|
57
|
+
return onBackPressed if item.getItemId == home_const
|
47
58
|
# Don't call super if method returns false
|
48
|
-
|
59
|
+
return true if on_options_item_selected(item) == false
|
60
|
+
super
|
49
61
|
end
|
50
62
|
|
51
63
|
def open(screen, options={})
|
@@ -22,7 +22,7 @@
|
|
22
22
|
def open_fragment(frag, options={})
|
23
23
|
mp frag
|
24
24
|
mgr = fragmentManager.beginTransaction
|
25
|
-
mgr.
|
25
|
+
mgr.replace(@fragment_container.getId, frag, "screen-#{fragmentManager.getBackStackEntryCount + 1}")
|
26
26
|
mgr.addToBackStack(nil)
|
27
27
|
mgr.commit
|
28
28
|
frag
|
@@ -54,5 +54,11 @@
|
|
54
54
|
self.fragment.on_options_item_selected(item) if self.fragment
|
55
55
|
end
|
56
56
|
|
57
|
+
def on_activity_result(request_code, result_code, data)
|
58
|
+
if @fragment && @fragment.respond_to?(:handle_activity_result)
|
59
|
+
@fragment.activity_result(request_code, result_code, data)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
57
63
|
end
|
58
64
|
#end
|
@@ -90,7 +90,7 @@
|
|
90
90
|
@view.setId Potion::ViewIdGenerator.generate
|
91
91
|
end
|
92
92
|
|
93
|
-
|
93
|
+
set_up_action_bar(self.class.action_bar_options)
|
94
94
|
|
95
95
|
on_create_view(inflater, parent, saved_instance_state)
|
96
96
|
|
@@ -155,41 +155,6 @@
|
|
155
155
|
end
|
156
156
|
def on_detach; end
|
157
157
|
|
158
|
-
def set_title
|
159
|
-
self.title = self.class.bars_title
|
160
|
-
end
|
161
|
-
|
162
|
-
def title
|
163
|
-
@title
|
164
|
-
end
|
165
|
-
def title=(value)
|
166
|
-
@title = value
|
167
|
-
|
168
|
-
if a = self.activity
|
169
|
-
if a_bar = self.action_bar
|
170
|
-
a_bar.title = value
|
171
|
-
end
|
172
|
-
a.title = value
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
private
|
177
|
-
|
178
|
-
def build_and_tag_xml_views
|
179
|
-
return unless @xml_resource
|
180
|
-
|
181
|
-
self.rmq.all.each do |view|
|
182
|
-
if ren = view.resource_entry_name
|
183
|
-
self.rmq.build(view).tag(ren.to_sym)
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
def hide_action_bar?
|
189
|
-
# RM-???: comparing nil to false causes ART crash
|
190
|
-
!self.class.show_action_bar.nil? && self.class.show_action_bar == false
|
191
|
-
end
|
192
|
-
|
193
158
|
end
|
194
159
|
|
195
160
|
#end
|
@@ -27,7 +27,7 @@
|
|
27
27
|
@view.setId Potion::ViewIdGenerator.generate
|
28
28
|
end
|
29
29
|
|
30
|
-
|
30
|
+
set_up_action_bar(self.class.action_bar_options)
|
31
31
|
|
32
32
|
on_create_view(inflater, parent, saved_instance_state)
|
33
33
|
|
@@ -90,41 +90,6 @@
|
|
90
90
|
end
|
91
91
|
def on_detach; end
|
92
92
|
|
93
|
-
def set_title
|
94
|
-
self.title = self.class.bars_title
|
95
|
-
end
|
96
|
-
|
97
|
-
def title
|
98
|
-
@title
|
99
|
-
end
|
100
|
-
def title=(value)
|
101
|
-
@title = value
|
102
|
-
|
103
|
-
if a = self.activity
|
104
|
-
if a_bar = self.action_bar
|
105
|
-
a_bar.title = value
|
106
|
-
end
|
107
|
-
a.title = value
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
private
|
112
|
-
|
113
|
-
def build_and_tag_xml_views
|
114
|
-
return unless @xml_resource
|
115
|
-
|
116
|
-
self.rmq.all.each do |view|
|
117
|
-
if ren = view.resource_entry_name
|
118
|
-
self.rmq.build(view).tag(ren.to_sym)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def hide_action_bar?
|
124
|
-
# RM-???: comparing nil to false causes ART crash
|
125
|
-
!self.class.show_action_bar.nil? && self.class.show_action_bar == false
|
126
|
-
end
|
127
|
-
|
128
93
|
end
|
129
94
|
|
130
95
|
#end
|
@@ -6,9 +6,7 @@
|
|
6
6
|
end
|
7
7
|
|
8
8
|
module ClassMethods
|
9
|
-
attr_reader :xml_resource, :
|
10
|
-
|
11
|
-
@show_action_bar = true
|
9
|
+
attr_reader :xml_resource, :bars_title
|
12
10
|
|
13
11
|
def stylesheet(style_sheet_class)
|
14
12
|
@rmq_style_sheet_class = style_sheet_class
|
@@ -23,12 +21,22 @@
|
|
23
21
|
end
|
24
22
|
alias_method :uses_xml, :xml_layout
|
25
23
|
|
26
|
-
|
27
|
-
|
24
|
+
# Sets up the action bar for this screen.
|
25
|
+
#
|
26
|
+
# Example:
|
27
|
+
# action_bar true, back: true, icon: true,
|
28
|
+
# custom_icon: "resourcename", custom_back: "custombackicon"
|
29
|
+
#
|
30
|
+
def action_bar(show_action_bar, opts={})
|
31
|
+
@action_bar_options = ({show:true, back: true, icon: false}).merge(opts).merge({show: show_action_bar})
|
28
32
|
end
|
29
33
|
alias_method :nav_bar, :action_bar
|
30
34
|
alias_method :uses_action_bar, :action_bar
|
31
35
|
|
36
|
+
def action_bar_options
|
37
|
+
@action_bar_options ||= action_bar(true, {})
|
38
|
+
end
|
39
|
+
|
32
40
|
def title(new_title)
|
33
41
|
@bars_title = new_title
|
34
42
|
#self.activity.title = new_title
|
@@ -69,9 +77,9 @@
|
|
69
77
|
self.getView
|
70
78
|
end
|
71
79
|
|
72
|
-
|
73
|
-
|
74
|
-
end
|
80
|
+
# abstract methods
|
81
|
+
def on_load; end
|
82
|
+
def on_return(opts={}); end
|
75
83
|
|
76
84
|
def color(*params)
|
77
85
|
RMQ.color(*params)
|
@@ -175,6 +183,12 @@
|
|
175
183
|
else
|
176
184
|
# Closing current screen or activity if no screens left
|
177
185
|
act.close_fragment if act.fragment
|
186
|
+
end
|
187
|
+
|
188
|
+
if act.fragment
|
189
|
+
act.fragment.set_up_action_bar
|
190
|
+
act.fragment.on_return(options)
|
191
|
+
else
|
178
192
|
act.finish unless act.fragment
|
179
193
|
end
|
180
194
|
end
|
@@ -196,19 +210,29 @@
|
|
196
210
|
|
197
211
|
def hide_keyboard
|
198
212
|
input_manager = activity.getSystemService(Android::Content::Context::INPUT_METHOD_SERVICE)
|
199
|
-
input_manager.hideSoftInputFromWindow(view.getWindowToken(), 0)
|
213
|
+
input_manager.hideSoftInputFromWindow(view.getWindowToken(), 0)
|
200
214
|
end
|
201
215
|
|
202
216
|
def action_bar
|
203
|
-
|
204
|
-
a.getActionBar
|
205
|
-
end
|
217
|
+
activity && activity.getActionBar
|
206
218
|
end
|
207
219
|
|
208
220
|
def menu
|
209
221
|
activity.menu
|
210
222
|
end
|
211
223
|
|
224
|
+
def set_up_action_bar(options={})
|
225
|
+
if options[:show]
|
226
|
+
action_bar.show
|
227
|
+
action_bar.setDisplayHomeAsUpEnabled(!!options[:back])
|
228
|
+
action_bar.setDisplayShowHomeEnabled(!!options[:icon])
|
229
|
+
action_bar.setIcon(image.resource(options[:custom_icon].to_s)) if options[:custom_icon]
|
230
|
+
action_bar.setHomeAsUpIndicator(image.resource(options[:custom_back].to_s)) if options[:custom_back]
|
231
|
+
else
|
232
|
+
action_bar.hide
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
212
236
|
# Example: add_action_bar_button(title: "My text", show: :if_room)
|
213
237
|
def add_action_bar_button(options={})
|
214
238
|
@action_bar ||= { button_actions: {} }
|
@@ -245,5 +269,33 @@
|
|
245
269
|
end
|
246
270
|
end
|
247
271
|
|
272
|
+
def build_and_tag_xml_views
|
273
|
+
return unless @xml_resource
|
274
|
+
|
275
|
+
self.rmq.all.each do |view|
|
276
|
+
if ren = view.resource_entry_name
|
277
|
+
self.rmq.build(view).tag(ren.to_sym)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def set_title
|
283
|
+
self.title = self.class.bars_title
|
284
|
+
end
|
285
|
+
|
286
|
+
def title
|
287
|
+
@title
|
288
|
+
end
|
289
|
+
def title=(value)
|
290
|
+
@title = value
|
291
|
+
|
292
|
+
if a = self.activity
|
293
|
+
if a_bar = self.action_bar
|
294
|
+
a_bar.title = value
|
295
|
+
end
|
296
|
+
a.title = value
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
248
300
|
end
|
249
301
|
#end
|
@@ -25,6 +25,14 @@
|
|
25
25
|
context.applicationInfo
|
26
26
|
end
|
27
27
|
|
28
|
+
def package_manager
|
29
|
+
context.getPackageManager
|
30
|
+
end
|
31
|
+
|
32
|
+
def name
|
33
|
+
application_info.loadLabel(package_manager)
|
34
|
+
end
|
35
|
+
|
28
36
|
def identifier
|
29
37
|
application_info.packageName
|
30
38
|
end
|
@@ -81,6 +89,10 @@
|
|
81
89
|
RMQResource
|
82
90
|
end
|
83
91
|
|
92
|
+
def r
|
93
|
+
RMQResource
|
94
|
+
end
|
95
|
+
|
84
96
|
def net
|
85
97
|
BluePotionNet
|
86
98
|
end
|
@@ -99,6 +111,10 @@
|
|
99
111
|
Android::Widget::Toast.makeText(rmq.activity, message, message_length).show
|
100
112
|
end
|
101
113
|
|
114
|
+
def alert(options={}, &block)
|
115
|
+
AlertDialog.new(options, &block)
|
116
|
+
end
|
117
|
+
|
102
118
|
class << self
|
103
119
|
attr_accessor :current_application, :home_screen_class
|
104
120
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
###### EXAMPLE USAGE #######
|
2
|
+
#@phud = ProgressHUD.new("Loading Widgets")
|
3
|
+
#@phud.show
|
4
|
+
#@phud.title = "Widgets Almost Completed!"
|
5
|
+
#@phud.dismiss
|
6
|
+
|
7
|
+
class ProgressHUD < Android::App::DialogFragment
|
8
|
+
|
9
|
+
def initialize(title="Loading")
|
10
|
+
@title = title
|
11
|
+
end
|
12
|
+
|
13
|
+
def show(activity=rmq.activity)
|
14
|
+
super(activity.fragmentManager, "progress")
|
15
|
+
end
|
16
|
+
|
17
|
+
def onCreateDialog(saved_instance_state)
|
18
|
+
builder = Android::App::AlertDialog::Builder.new(activity,
|
19
|
+
Android::App::AlertDialog::THEME_HOLO_LIGHT)
|
20
|
+
|
21
|
+
progress = Android::Widget::ProgressBar.new(activity)
|
22
|
+
progress.setBackgroundColor(Android::Graphics::Color::TRANSPARENT)
|
23
|
+
builder.setView(progress)
|
24
|
+
.setTitle(@title)
|
25
|
+
|
26
|
+
@created_dialog = builder.create()
|
27
|
+
end
|
28
|
+
|
29
|
+
def title=(new_title)
|
30
|
+
@created_dialog.title = new_title if @created_dialog
|
31
|
+
end
|
32
|
+
|
33
|
+
def hide
|
34
|
+
self.dismiss
|
35
|
+
end
|
36
|
+
alias_method :close, :hide
|
37
|
+
|
38
|
+
end
|
@@ -66,10 +66,10 @@ class RMQ
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
def wrap(*views)
|
69
|
+
def wrap(view_one, *views) # These strange params is because of RMA bug
|
70
70
|
views = [views] unless views.is_a?(Potion::ArrayList) # TODO, WTF, RM bug?
|
71
|
+
views.unshift(view_one)
|
71
72
|
views.flatten!
|
72
|
-
|
73
73
|
views.select!{ |v| v.is_a?(Potion::View) }
|
74
74
|
RMQ.create_with_array_and_selectors(views, views, @originated_from, self)
|
75
75
|
end
|
@@ -110,6 +110,10 @@ class RMQ
|
|
110
110
|
|
111
111
|
end
|
112
112
|
|
113
|
+
def find!(*args) # Do not alias this, strange bugs happen where classes don't have methods
|
114
|
+
self.find(*args).get
|
115
|
+
end
|
116
|
+
|
113
117
|
# @return [RMQ] A new rmq instance reducing selected views to those that match selectors provided
|
114
118
|
#
|
115
119
|
# @param selectors your selector
|
@@ -0,0 +1,219 @@
|
|
1
|
+
module RubyMotionQuery
|
2
|
+
class RMQ
|
3
|
+
|
4
|
+
# @return [Validation]
|
5
|
+
def self.validation
|
6
|
+
Validation
|
7
|
+
end
|
8
|
+
|
9
|
+
# @return [Validation]
|
10
|
+
def validation
|
11
|
+
Validation
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [RMQ]
|
15
|
+
def validates(rule, options={})
|
16
|
+
selected.each do |view|
|
17
|
+
view.rmq_data.validations << Validation.new(rule, options)
|
18
|
+
end
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [RMQ]
|
23
|
+
def clear_validations!
|
24
|
+
selected.each do |view|
|
25
|
+
view.rmq_data.validations = []
|
26
|
+
end
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
# This method validates all the selected and is responsible
|
31
|
+
# for calling invalid/valid events
|
32
|
+
#
|
33
|
+
# @return [Boolean] false if any validations fail
|
34
|
+
def valid?
|
35
|
+
result = true
|
36
|
+
|
37
|
+
selected.each do |view|
|
38
|
+
view.rmq_data.validations.each do |validation|
|
39
|
+
|
40
|
+
has_events = view.rmq_data.events
|
41
|
+
|
42
|
+
if validation.valid?(rmq(view).data)
|
43
|
+
if has_events && view.rmq_data.events.has_event?(:valid)
|
44
|
+
view.rmq_data.events[:valid].fire!
|
45
|
+
end
|
46
|
+
else
|
47
|
+
if has_events && view.rmq_data.events.has_event?(:invalid)
|
48
|
+
view.rmq_data.events[:invalid].fire!
|
49
|
+
end
|
50
|
+
result = false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
return result
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [Array] of error messages for failed validations
|
58
|
+
def validation_errors
|
59
|
+
errors = []
|
60
|
+
selected.each do |view|
|
61
|
+
view.rmq_data.validations.each do |validation|
|
62
|
+
unless validation.valid_status
|
63
|
+
default_error = "Validation Error - input requires valid #{validation.rule_name}."
|
64
|
+
rule_message = view.rmq_data.validation_errors[validation.rule_name] || default_error
|
65
|
+
errors.push(rule_message)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
return errors
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [Array] of views where validations have failed
|
73
|
+
def invalid
|
74
|
+
selected.reject do |view|
|
75
|
+
view.rmq_data.validations.map{ |validation| validation.valid_status }.reduce(:&)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [Array] of views where validations have not failed
|
80
|
+
def valid
|
81
|
+
selected.select do |view|
|
82
|
+
view.rmq_data.validations.map{ |validation| validation.valid_status }.reduce(:&)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end # End RMQ
|
87
|
+
|
88
|
+
class Validation
|
89
|
+
attr_reader :valid_status, :rule_name
|
90
|
+
|
91
|
+
####################################################
|
92
|
+
# THIS IS SIGNIFICANTLY DIFFERENT FROM iOS BECAUSE
|
93
|
+
# Regexp object is not available - but Java is
|
94
|
+
####################################################
|
95
|
+
|
96
|
+
# Validation Regex from jQuery validation -> https://github.com/jzaefferer/jquery-validation/blob/master/src/core.js#L1094-L1200
|
97
|
+
EMAIL = '^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$'
|
98
|
+
URL = '^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&\'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&\'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&\'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&\'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&\'\(\)\*\+,;=]|:|@)|\/|\?)*)?$'
|
99
|
+
DATEISO = '^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$'
|
100
|
+
NUMBER = '^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$'
|
101
|
+
DIGITS = '^\d+$'
|
102
|
+
# Other Fun by http://www.freeformatter.com/regex-tester.html
|
103
|
+
IPV4 = '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
|
104
|
+
TIME = '^(20|21|22|23|[01]\d|\d)((:[0-5]\d){1,2})$'
|
105
|
+
# Future Password strength validations -> http://stackoverflow.com/questions/5142103/regex-for-password-strength
|
106
|
+
USZIP = '^\d{5}(-\d{4})?$'
|
107
|
+
# UK Postal Code regex from: http://stackoverflow.com/a/7259020/814123
|
108
|
+
UKZIP = '^(GIR ?0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]([0-9ABEHMNPRV-Y])?)|[0-9][A-HJKPS-UW]) ?[0-9][ABD-HJLNP-UW-Z]{2})$'
|
109
|
+
# 7 or 10 digit number, delimiters are spaces, dashes, or periods
|
110
|
+
USPHONE = '^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})$'
|
111
|
+
# International Phone numbers
|
112
|
+
INTLPHONE = '^(\(?\+?[0-9]*\)?)?[0-9_\- \(\)]*$'
|
113
|
+
# Strong password (at least [8 chars, 1 upper, 1 lower, 1 number])
|
114
|
+
STRONGPW = '^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).{8,}$'
|
115
|
+
# Has at least 1 uppercase letter
|
116
|
+
HASUPPER = '^(?=.*[A-Z]).+$'
|
117
|
+
# Has at least 1 lowercase letter
|
118
|
+
HASLOWER = '^(?=.*[a-z]).+$'
|
119
|
+
# Has some kind of value not just whitespace (doesn't require data to be stripped)
|
120
|
+
PRESENCE = '\S+'
|
121
|
+
|
122
|
+
@@validation_methods = {
|
123
|
+
:email => lambda { |value, opts| value.toString.matches(EMAIL)},
|
124
|
+
:url => lambda { |value, opts| value.toString.matches(URL)},
|
125
|
+
:dateiso => lambda { |value, opts| value.toString.matches(DATEISO)},
|
126
|
+
:number => lambda { |value, opts| value.toString.matches(NUMBER)},
|
127
|
+
:digits => lambda { |value, opts| value.toString.matches(DIGITS)},
|
128
|
+
:ipv4 => lambda { |value, opts| value.toString.matches(IPV4)},
|
129
|
+
:time => lambda { |value, opts| value.toString.matches(TIME)},
|
130
|
+
:uszip => lambda { |value, opts| value.toString.matches(USZIP)},
|
131
|
+
:ukzip => lambda { |value, opts| value.toString.matches(UKZIP)},
|
132
|
+
:usphone => lambda { |value, opts| value.toString.matches(USPHONE)},
|
133
|
+
:intlphone => lambda { |value, opts| value.toString.matches(INTLPHONE)},
|
134
|
+
:strong_password => lambda { |value, opts| value.toString.matches(STRONGPW)},
|
135
|
+
:has_upper => lambda { |value, opts| value.toString.matches(HASUPPER)},
|
136
|
+
:has_lower => lambda { |value, opts| value.toString.matches(HASLOWER)},
|
137
|
+
:presence => lambda { |value, opts| value.toString.matches(PRESENCE)},
|
138
|
+
:length => lambda { |value, opts|
|
139
|
+
opts = {
|
140
|
+
exact_length: nil,
|
141
|
+
max_length: Float::INFINITY,
|
142
|
+
min_length: 0,
|
143
|
+
strip: false
|
144
|
+
}.merge(opts)
|
145
|
+
|
146
|
+
# Range magic 8..16
|
147
|
+
if opts[:exact_length].is_a? Range
|
148
|
+
opts[:min_length] = opts[:exact_length].begin
|
149
|
+
opts[:max_length] = opts[:exact_length].end
|
150
|
+
opts[:exact_length] = nil
|
151
|
+
end
|
152
|
+
|
153
|
+
# allowing option to strip input before assessing length
|
154
|
+
value.strip! if opts[:strip]
|
155
|
+
|
156
|
+
# check length validation
|
157
|
+
v = if opts[:exact_length] then (value.length == opts[:exact_length]) else true end
|
158
|
+
v = v && value.length <= opts[:max_length]
|
159
|
+
v = v && value.length >= opts[:min_length]
|
160
|
+
},
|
161
|
+
:custom => lambda { |value, opts| value.toString.matches(opts[:regex])},
|
162
|
+
}
|
163
|
+
|
164
|
+
|
165
|
+
def initialize(rule, options={})
|
166
|
+
@rule = @@validation_methods[rule]
|
167
|
+
raise "RMQ validation error: :#{rule} is not one of the supported validation methods." unless @rule
|
168
|
+
@rule_name = rule
|
169
|
+
@options = options
|
170
|
+
@valid_status = true
|
171
|
+
end
|
172
|
+
|
173
|
+
def valid?(data, options={})
|
174
|
+
@options = options.merge(@options)
|
175
|
+
|
176
|
+
# shortcircuit for universal validation parameters
|
177
|
+
return true if universal_validation_checks(data, @options)
|
178
|
+
|
179
|
+
@valid_status = @rule.call(data, @options)
|
180
|
+
end
|
181
|
+
|
182
|
+
# this method shortcuts specific validation rules. As such it should only be
|
183
|
+
# added to for universal validation needs. It must be kept as efficient as possible.
|
184
|
+
def universal_validation_checks (data, options={})
|
185
|
+
# shortcircuit if debugging
|
186
|
+
return true if RubyMotionQuery::RMQ.debugging?
|
187
|
+
# allow blank data if specified
|
188
|
+
return true if (options[:allow_blank] && (data.nil? || data.empty?))
|
189
|
+
# allow whitelist data if specified
|
190
|
+
return true if (options[:white_list] && options[:white_list].include?(data))
|
191
|
+
|
192
|
+
false
|
193
|
+
end
|
194
|
+
|
195
|
+
class << self
|
196
|
+
|
197
|
+
# Add tags
|
198
|
+
# @example
|
199
|
+
# rmq.validation.valid?('test@test.com', :email)
|
200
|
+
# rmq.validation.valid?(53.8, :number)
|
201
|
+
# rmq.validation.valid?(54, :digits)
|
202
|
+
# rmq.validation.valid?('https://www.tacoland.com', :url)
|
203
|
+
# rmq.validation.valid?('2014-03-02', :dateiso)
|
204
|
+
# rmq.validation.valid?('', :email, allow_blank: true)
|
205
|
+
#
|
206
|
+
# @return [Boolean]
|
207
|
+
def valid?(value, rule, options={})
|
208
|
+
Validation.new(rule).valid?(value, options)
|
209
|
+
end
|
210
|
+
|
211
|
+
def add_validator(rule, &block)
|
212
|
+
raise(ArgumentError, "add_validator requires a block") if block.nil?
|
213
|
+
|
214
|
+
@@validation_methods[rule] = block
|
215
|
+
end
|
216
|
+
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
data/lib/project/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bluepotion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- InfiniteRed
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-07-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -41,6 +41,7 @@ files:
|
|
41
41
|
- bin/bluepotion_add_line_numbers
|
42
42
|
- bin/bluepotion_remove_line_numbers
|
43
43
|
- lib/bluepotion.rb
|
44
|
+
- lib/project/alert_dialog/alert_dialog.rb
|
44
45
|
- lib/project/blue_potion_net.rb
|
45
46
|
- lib/project/compatibility/dispatch.rb
|
46
47
|
- lib/project/compatibility/motion_keychain.rb
|
@@ -64,6 +65,7 @@ files:
|
|
64
65
|
- lib/project/pro_motion/fragments/pm_screen_module.rb
|
65
66
|
- lib/project/pro_motion/pm_application.rb
|
66
67
|
- lib/project/pro_motion/support/pm_hash_bundle.rb
|
68
|
+
- lib/project/progress_hud/progress_hud.rb
|
67
69
|
- lib/project/ruby_motion_query/rmq/actions.rb
|
68
70
|
- lib/project/ruby_motion_query/rmq/base.rb
|
69
71
|
- lib/project/ruby_motion_query/rmq/data.rb
|
@@ -93,6 +95,7 @@ files:
|
|
93
95
|
- lib/project/ruby_motion_query/rmq_resource.rb
|
94
96
|
- lib/project/ruby_motion_query/rmq_screen_data.rb
|
95
97
|
- lib/project/ruby_motion_query/rmq_stylesheet.rb
|
98
|
+
- lib/project/ruby_motion_query/rmq_validation.rb
|
96
99
|
- lib/project/ruby_motion_query/rmq_view_data.rb
|
97
100
|
- lib/project/ruby_motion_query/stylers/rmq_button_styler.rb
|
98
101
|
- lib/project/ruby_motion_query/stylers/rmq_image_button_styler.rb
|
@@ -133,10 +136,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
133
136
|
version: '0'
|
134
137
|
requirements: []
|
135
138
|
rubyforge_project:
|
136
|
-
rubygems_version: 2.4.
|
139
|
+
rubygems_version: 2.4.5
|
137
140
|
signing_key:
|
138
141
|
specification_version: 4
|
139
142
|
summary: BluePotion - Just like RedPotion, but for Android. The best combination of
|
140
143
|
RubyMotion tools and libraries for Android
|
141
144
|
test_files: []
|
142
|
-
has_rdoc:
|