formotion 1.6 → 1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.travis.yml +0 -3
  4. data/Gemfile +4 -1
  5. data/LIST_OF_ROW_TYPES.md +58 -6
  6. data/Rakefile +6 -2
  7. data/app/app_delegate.rb +6 -0
  8. data/examples/KitchenSink/Gemfile +2 -1
  9. data/examples/KitchenSink/Rakefile +9 -4
  10. data/examples/KitchenSink/app/app_delegate.rb +20 -5
  11. data/examples/KitchenSink/resources/arrow-up.png +0 -0
  12. data/examples/KitchenSink/resources/arrow-up@2x.png +0 -0
  13. data/examples/KitchenSink/resources/email.png +0 -0
  14. data/examples/KitchenSink/resources/email@2x.png +0 -0
  15. data/examples/Persistence/app/app_delegate.rb +2 -0
  16. data/examples/Persistence/app/controller.rb +66 -0
  17. data/lib/formotion/controller/form_controller.rb +1 -1
  18. data/lib/formotion/form/form.rb +14 -5
  19. data/lib/formotion/model/formable.rb +8 -6
  20. data/lib/formotion/patch/ui_text_field.rb +15 -1
  21. data/lib/formotion/row/row.rb +19 -3
  22. data/lib/formotion/row/row_cell_builder.rb +48 -2
  23. data/lib/formotion/row_type/button.rb +2 -2
  24. data/lib/formotion/row_type/date_row.rb +8 -1
  25. data/lib/formotion/row_type/image_row.rb +2 -2
  26. data/lib/formotion/row_type/map_row.rb +60 -23
  27. data/lib/formotion/row_type/object_row.rb +2 -2
  28. data/lib/formotion/row_type/picker_row.rb +32 -0
  29. data/lib/formotion/row_type/string_row.rb +5 -2
  30. data/lib/formotion/row_type/web_link_row.rb +48 -0
  31. data/lib/formotion/version.rb +1 -1
  32. data/resources/camera.png +0 -0
  33. data/resources/camera@2x.png +0 -0
  34. data/spec/functional/map_row_spec.rb +151 -4
  35. data/spec/functional/web_link_row_spec.rb +35 -0
  36. data/spec/row_spec.rb +109 -1
  37. data/spec/row_type/web_link_spec.rb +23 -0
  38. metadata +13 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3407c939ef975c1f7e97164c26689e0110507891
4
- data.tar.gz: 996472e335ea5b2be05e62fccc4499402e21b6a0
3
+ metadata.gz: 71061dad41a80a78a4e7b26faa6fb78d284beaee
4
+ data.tar.gz: 4d6462cfe38e455077bf4736376beb84ef1ba46a
5
5
  SHA512:
6
- metadata.gz: ac0469bebf08738e7ec88465b6b72fce94625f02b65eb5815f85650a5671046266f90beee6100f6cf16d8849ebcd6100eb58f9c74d23ac2b669238de29a233c5
7
- data.tar.gz: e16aeb3fbd30d8407bb19b7bd102b04b90274c2f1540056d110371bfbab3a4709ee0afb33838267ebf4b214b16a2772b0b6e460471e8fd808903d10e37cc6948
6
+ metadata.gz: 0217c216bf843420d86d38f2ef6120af5f4057d68328cae4bb28aa65d0628aeb78a8c5af21eeef22fa90a944713fae98f2827b21dc1750dc11400947b83ea4e9
7
+ data.tar.gz: 116b36b2b66855546e79d7033fcf1473926c8d3085e049c14ff8b803a8e7e737768decb49b29ffff9ebc6144e4ed5510da27afc542f309524deec2e9a185600c
data/.gitignore CHANGED
@@ -8,4 +8,5 @@ resources/*.storyboardc
8
8
  .bundle
9
9
  Gemfile.lock
10
10
  pkg/*
11
- .rvmrc
11
+ .rvmrc
12
+ vendor
data/.travis.yml CHANGED
@@ -1,6 +1,3 @@
1
1
  language: objective-c
2
- before_install:
3
- - rvm install ruby-1.9.3-p429
4
- - rvm use 1.9.3
5
2
  install: bundle install
6
3
  script: bundle exec rake spec:units
data/Gemfile CHANGED
@@ -3,5 +3,8 @@ source 'https://rubygems.org'
3
3
  gem 'guard-motion'
4
4
  gem 'rb-fsevent'
5
5
 
6
+ gem "motion-cocoapods"
7
+ gem "cocoapods"
8
+
6
9
  # Specify your gem's dependencies in motion-settings.gemspec
7
- gemspec
10
+ gemspec
data/LIST_OF_ROW_TYPES.md CHANGED
@@ -19,6 +19,7 @@
19
19
  [Subform](#subform)<br/>
20
20
  [Template](#template)<br/>
21
21
  [MapView](#mapview)<br/>
22
+ [WebLink](#weblink)<br/>
22
23
  [WebView](#webview)<br/>
23
24
  [PagedImage](#pagedimage)<br/>
24
25
  [Tags](#tags)<br/>
@@ -38,6 +39,8 @@ All row types accept following properties:
38
39
  value: 'Some Value', # The initial value passed to the row
39
40
  title: 'Title', # Title of the row
40
41
  subtitle: 'Subtitle', # Subtitle of the row
42
+ image: nil, # Image for the cell's imageView. Accepts a string, UIImage, URL string, or NSURL
43
+ image_placeholder: nil # Used only when you are loading remote images. Accpets a string or UIImage
41
44
  type: :string, # The type of row (string, phone, switch, etc)
42
45
  row_height: 100 # Height of the row
43
46
  }
@@ -70,11 +73,12 @@ All character based row types accept following properties:
70
73
  type: :string,
71
74
  placeholder: 'James Bond',
72
75
  auto_correction: :no,
73
- auto_capitalization: :none
76
+ auto_capitalization: :none,
77
+ input_accessory: :done
74
78
  }
75
79
  ```
76
80
 
77
- The `StringRow` is a simple text input row and opens a `UIKeyboardTypeDefault` keyboard when editing.
81
+ The `StringRow` is a simple text input row and opens a `UIKeyboardTypeDefault` keyboard when editing. `input_accessory` can be nil or `:done`, and shows a toolbar with a done button above the keyboard.
78
82
 
79
83
 
80
84
  ### <a name="text"></a> Text row
@@ -355,7 +359,8 @@ The `SliderRow` takes a ruby range as `range` property that defines the min and
355
359
  key: :pick,
356
360
  type: :picker,
357
361
  items: ["Ruby", "Motion", "Rocks"],
358
- value: "Motion"
362
+ value: "Motion",
363
+ input_accessory: :done
359
364
  }
360
365
  ```
361
366
 
@@ -432,13 +437,60 @@ Use a `:display_key` to show the value of the subform in the row:
432
437
  ```ruby
433
438
  {
434
439
  title: "Map",
435
- type: :map_view,
436
- value: coordinates, # of type CLLocationCoordinate2D
440
+ type: :map,
441
+ value: coordinates, # of type CLLocationCoordinate2D, CLCircularRegion, or a Hash of options
437
442
  row_height: 200 # for better viewing
438
443
  }
439
444
  ```
440
445
 
441
- Shows a map with a pin at the coordinates from value.
446
+ Shows a map with a pin at the coordinates from value. If you pass a `CLLocationCoordinate2D` or `CLCircularRegion`, a pin will be placed at the coordinates. You can pass a hash of options like this:
447
+
448
+ ```ruby
449
+ {
450
+ title: "Map",
451
+ type: :map,
452
+ value: {
453
+ coord: coordinates,
454
+ enabled: true, # Whether the user can interact with the map.
455
+ type: MKMapTypeStandard, # The type of map to show. See MKMapType documentation.
456
+ animated: true, # Whether setting the region should animate. This property also applies to annotation titles.
457
+ pin: {
458
+ coord: coordinates, # Must be a CLLocationCoordinate2D
459
+ title: nil, # Title of the annotation
460
+ subtitle: nil # Subtitle of the annotation
461
+ }
462
+ }
463
+ row_height: 200 # for better viewing
464
+ }
465
+ ```
466
+
467
+ If you pass `pin: nil` the map will not display an annotation. Annotations with titles will automatically pop open the annotation. _Note: If you set a title on an annotation it will automatically invalidate `enabled:false` and the map will be interactable._
468
+
469
+ ### <a name="weblink"></a> WebLink row
470
+ ```ruby
471
+ {
472
+ title: "My Awesome Site",
473
+ type: :web_link,
474
+ value: "http://www.myawesomesite.com" # URL to be opened. Can also be an NSURL
475
+ }
476
+ ```
477
+
478
+ You can also allow the user to confirm leaving your app:
479
+ ```ruby
480
+ {
481
+ title: "My Awesome Site",
482
+ type: :web_link,
483
+ warn: true,
484
+ # or pass a hash to :warn.
485
+ # Here are the default values (Bubblewrap alert options):
486
+ # warn: {
487
+ # title: "Leaving #{App.name}",
488
+ # message: "This action will leave #{App.name} and open Safari.",
489
+ # buttons: ["Cancel", "OK"]
490
+ # }
491
+ value: "http://www.myawesomesite.com", # URL to be opened
492
+ }
493
+ ```
442
494
 
443
495
 
444
496
  ### <a name="webview"></a> WebView row
data/Rakefile CHANGED
@@ -1,8 +1,8 @@
1
1
  $:.unshift("/Library/RubyMotion/lib")
2
- require 'motion/project'
2
+ require 'motion/project/template/ios'
3
3
  require "bundler/gem_tasks"
4
4
  require "bundler/setup"
5
-
5
+ Bundler.require
6
6
  $:.unshift("./lib/")
7
7
  require './lib/formotion'
8
8
  require 'guard/motion'
@@ -10,6 +10,10 @@ require 'guard/motion'
10
10
  Motion::Project::App.setup do |app|
11
11
  # Use `rake config' to see complete project settings.
12
12
  app.name = 'Formotion'
13
+
14
+ app.pods do
15
+ pod 'JMImageCache'
16
+ end
13
17
  end
14
18
 
15
19
  namespace :spec do
data/app/app_delegate.rb CHANGED
@@ -11,6 +11,7 @@ class AppDelegate
11
11
  title: "Photo",
12
12
  key: :photo,
13
13
  type: :image,
14
+ image: "camera",
14
15
  deletable: true
15
16
  },{
16
17
  title: "Picker",
@@ -31,6 +32,11 @@ class AppDelegate
31
32
  placeholder: "required",
32
33
  type: :string,
33
34
  secure: true
35
+ }, {
36
+ title: "Remote Loaded Image",
37
+ type: :static,
38
+ image: "http://placekitten.com/80/80?t=#{Time.now.to_i}",
39
+ image_placeholder: "camera"
34
40
  }, {
35
41
  title: "Password",
36
42
  subtitle: "Confirmation",
@@ -1,3 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'formotion', path: '../..'
3
+ gem 'formotion', path: '../..'
4
+ gem 'motion-cocoapods'
@@ -1,12 +1,17 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  $:.unshift("/Library/RubyMotion/lib")
3
- require 'motion/project'
3
+ require 'motion/project/template/ios'
4
4
 
5
- require 'rubygems'
6
- require 'bundler'
7
- Bundler.require :default
5
+ begin
6
+ require 'bundler'
7
+ Bundler.require
8
+ rescue LoadError
9
+ end
8
10
 
9
11
  Motion::Project::App.setup do |app|
10
12
  # Use `rake config' to see complete project settings.
11
13
  app.name = 'KitchenSink'
14
+ app.pods do
15
+ pod 'SDWebImage'
16
+ end
12
17
  end
@@ -14,15 +14,28 @@ class AppDelegate
14
14
  title: "Email",
15
15
  key: :email,
16
16
  placeholder: "me@mail.com",
17
+ image: "email",
17
18
  type: :email,
18
19
  auto_correction: :no,
19
- auto_capitalization: :none
20
+ auto_capitalization: :none,
21
+ input_accessory: :done
22
+ }, {
23
+ title: "Image Accessory",
24
+ subtitle: "You can add an image to any row type",
25
+ image: "arrow-up",
26
+ type: :static
27
+ }, {
28
+ title: "Image from URL",
29
+ subtitle: "Or from a URL!",
30
+ image: "http://placekitten.com/80/80?t=#{Time.now.to_i}",
31
+ type: :static
20
32
  }, {
21
33
  title: "Gender",
22
34
  key: :gender,
23
35
  type: :picker,
24
- items: [['Female', 'f'], ['Male', 'm']],
25
- value: 'm'
36
+ items: [['Female', 'f'],['fds', 'df'],['fddfsfds', 'f3'],['fdfafds', 'f33'], ['Male', 'm']],
37
+ value: 'm',
38
+ input_accessory: :done
26
39
  }, {
27
40
  title: "Password",
28
41
  key: :password,
@@ -35,14 +48,16 @@ class AppDelegate
35
48
  placeholder: "555-555-5555",
36
49
  type: :phone,
37
50
  auto_correction: :no,
38
- auto_capitalization: :none
51
+ auto_capitalization: :none,
52
+ input_accessory: :done
39
53
  }, {
40
54
  title: "Number",
41
55
  key: :number,
42
56
  placeholder: "12345",
43
57
  type: :number,
44
58
  auto_correction: :no,
45
- auto_capitalization: :none
59
+ auto_capitalization: :none,
60
+ input_accessory: :done
46
61
  }, {
47
62
  title: "Subtitle",
48
63
  subtitle: "Confirmation",
@@ -6,6 +6,8 @@ class AppDelegate
6
6
 
7
7
  @view_controller.navigationItem.leftBarButtonItem = UIBarButtonItem.alloc.initWithTitle("Render", style: UIBarButtonItemStyleBordered, target:self, action:'reset_form')
8
8
 
9
+ @view_controller.navigationItem.rightBarButtonItem = UIBarButtonItem.alloc.initWithTitle("Save", style: UIBarButtonItemStyleBordered, target:self, action:'submit')
10
+
9
11
  @navigation_controller = UINavigationController.alloc.initWithRootViewController(@view_controller)
10
12
 
11
13
  @window.rootViewController = @navigation_controller
@@ -4,6 +4,41 @@ class AccountSettingsController < Formotion::FormController
4
4
  API_SERVER = "hello_world"
5
5
  API_KEY = "123123secret"
6
6
 
7
+ SPECIAL_OPTIONS_HASH = {
8
+ title: "Special options",
9
+ sections: [{
10
+ rows: [{
11
+ title: "Phone Number",
12
+ value: "555-555-5555",
13
+ type: "phone",
14
+ key: "phone"
15
+ }, {
16
+ title: "Address",
17
+ value: "90210",
18
+ type: "string",
19
+ key: "address"
20
+ }]
21
+ }]
22
+ }
23
+
24
+ DISPLAY_KEY_HASH = {
25
+ title: "Alert Sounds",
26
+ sections: [{
27
+ key: :sound,
28
+ select_one: true,
29
+ rows: [{
30
+ title: "Beeps",
31
+ key: :Beeps,
32
+ value: true,
33
+ type: :check
34
+ },{
35
+ title: "Boops",
36
+ key: :Boops,
37
+ type: :check
38
+ }]
39
+ }]
40
+ }
41
+
7
42
  SETTINGS_HASH = {
8
43
  title: "Application",
9
44
  persist_as: PERSIST_AS,
@@ -24,6 +59,37 @@ class AccountSettingsController < Formotion::FormController
24
59
  auto_correction: :no,
25
60
  auto_capitalization: :none
26
61
  }]
62
+ }, {
63
+ rows: [{
64
+ title: "Name",
65
+ type: :string,
66
+ key: :name,
67
+ value: "Clay",
68
+ auto_correction: :no,
69
+ auto_capitalization: :none
70
+ }, {
71
+ title: "Password",
72
+ value: "Secret",
73
+ type: :string,
74
+ key: :password,
75
+ secure: false,
76
+ auto_correction: :no,
77
+ auto_capitalization: :none
78
+ }]
79
+ }, {
80
+ title: "w/ Subforms",
81
+ rows: [{
82
+ title: "Special Options",
83
+ type: :subform,
84
+ key: :special_options,
85
+ subform: SPECIAL_OPTIONS_HASH
86
+ }, {
87
+ title: "w/ Display Key",
88
+ type: :subform,
89
+ key: :alert_sound,
90
+ display_key: :sound,
91
+ subform: DISPLAY_KEY_HASH
92
+ }]
27
93
  }]
28
94
  }
29
95
 
@@ -49,7 +49,7 @@ module Formotion
49
49
  # Setting @form.controller assigns
50
50
  # @form as the datasource and delegate
51
51
  # and reloads the data.
52
- @form.controller = self
52
+ @form.controller = WeakRef.new(self)
53
53
  end
54
54
 
55
55
  def viewWillAppear(animated)
@@ -267,19 +267,26 @@ module Formotion
267
267
  end
268
268
 
269
269
  def open
270
- @form_observer ||= lambda { |form, saved_render|
270
+ @form_observer ||= ->(form, saved_render, uses_display_key = false) {
271
+ no_saved_render = saved_render.nil?
272
+ saved_render ||= {}
273
+
271
274
  form.sections.each_with_index do |section, s_index|
272
275
  section.rows.each_with_index do |row, index|
273
276
  next if row.templated?
274
277
  saved_row_value = saved_render[row.key]
275
278
 
279
+ if uses_display_key && section.select_one && saved_render.include?(section.key.to_s)
280
+ saved_row_value = row.key.to_s == saved_render[section.key.to_s].to_s
281
+ end
282
+
276
283
  if row.subform?
277
- @form_observer.call(row.subform.to_form, saved_row_value)
284
+ @form_observer.call(row.subform.to_form, saved_row_value, !!row.display_key)
278
285
  elsif row.type == :template
279
286
  row.value = saved_row_value
280
287
  row.object.update_template_rows
281
288
  else
282
- row.value = saved_row_value
289
+ row.value = saved_row_value if !no_saved_render
283
290
  end
284
291
  end
285
292
  end
@@ -294,8 +301,10 @@ module Formotion
294
301
 
295
302
  # places hash of values into application persistance
296
303
  def save
297
- App::Persistence[persist_key] = render
298
- App::Persistence[original_persist_key] ||= render
304
+ rendered = render
305
+ recursive_delete_nil(rendered)
306
+ App::Persistence[persist_key] = rendered
307
+ App::Persistence[original_persist_key] ||= rendered
299
308
  end
300
309
 
301
310
  def reset
@@ -54,7 +54,7 @@ module Formotion
54
54
  end
55
55
 
56
56
  # Creates a Formotion::Form out of the model
57
- def to_form
57
+ def to_form_hash
58
58
  rows = self.class.form_properties.collect { |options|
59
59
  {
60
60
  title: options[:property].capitalize,
@@ -63,14 +63,16 @@ module Formotion
63
63
  value: self.send(options[:property])
64
64
  }.merge(options)
65
65
  }
66
- form_hash = {
66
+ return {
67
67
  title: self.class.form_title || self.class.to_s.capitalize,
68
68
  sections: [{
69
- rows: rows
70
- }]
69
+ rows: rows
70
+ }]
71
71
  }
72
+ end
72
73
 
73
- form = Formotion::Form.new(form_hash)
74
+ def to_form
75
+ form = Formotion::Form.new(to_form_hash)
74
76
  form.on_submit do
75
77
  self.on_submit
76
78
  end
@@ -96,4 +98,4 @@ module Formotion
96
98
  p "need to implement on_submit in your Formable model #{self.class.to_s}"
97
99
  end
98
100
  end
99
- end
101
+ end