bluepotion 0.1.5 → 0.1.6
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.
- 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:
|