motion-prime 0.5.2 → 0.5.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.
Files changed (40) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG.md +6 -0
  3. data/Gemfile.lock +3 -1
  4. data/README.md +10 -1
  5. data/ROADMAP.md +10 -6
  6. data/files/Gemfile +2 -2
  7. data/files/Gemfile.lock +15 -13
  8. data/files/Rakefile +1 -0
  9. data/files/app/app_delegate.rb +1 -1
  10. data/lib/motion-prime.rb +2 -2
  11. data/motion-prime.gemspec +1 -0
  12. data/motion-prime/api_client.rb +71 -29
  13. data/motion-prime/app_delegate.rb +1 -1
  14. data/motion-prime/config/base.rb +8 -1
  15. data/motion-prime/core_ext/kernel.rb +4 -3
  16. data/motion-prime/elements/_content_text_mixin.rb +5 -3
  17. data/motion-prime/elements/_text_mixin.rb +1 -1
  18. data/motion-prime/elements/base_element.rb +5 -4
  19. data/motion-prime/elements/draw/image.rb +3 -4
  20. data/motion-prime/elements/draw/label.rb +3 -3
  21. data/motion-prime/env.rb +3 -1
  22. data/motion-prime/models/errors.rb +1 -0
  23. data/motion-prime/models/store.rb +1 -1
  24. data/motion-prime/screens/screen.rb +11 -6
  25. data/motion-prime/sections/_draw_section_mixin.rb +4 -0
  26. data/motion-prime/sections/base_section.rb +3 -3
  27. data/motion-prime/sections/form/base_field_section.rb +21 -2
  28. data/motion-prime/sections/form/date_field_section.rb +9 -2
  29. data/motion-prime/sections/form/submit_field_section.rb +3 -1
  30. data/motion-prime/sections/table.rb +7 -2
  31. data/motion-prime/styles/base.rb +2 -2
  32. data/motion-prime/styles/form.rb +8 -2
  33. data/motion-prime/support/mp_cell_content_view.rb +12 -0
  34. data/motion-prime/support/mp_cell_with_section.rb +16 -14
  35. data/motion-prime/support/tab_bar_controller.rb +28 -7
  36. data/motion-prime/version.rb +1 -1
  37. data/motion-prime/views/layout.rb +2 -1
  38. data/motion-prime/views/view_builder.rb +5 -2
  39. data/motion-prime/views/view_styler.rb +33 -17
  40. metadata +17 -2
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YzJhZGY0OTNiNDY5YmZmOWQ0NDZhNGEzOWY4MjM3ZDU3YjUzODVkOQ==
4
+ NWM1NzdlODhjMWNjZjU2ZDMwYjNhYzExNDBiNjA2OTE1MDAyYThmNg==
5
5
  data.tar.gz: !binary |-
6
- ZDcyYmRiYWM3MWQyYmI5OTA0M2U2YzcyYTlmZGFkNjBjZWIzMWJlMw==
6
+ NzE4MTM4ZGI1YmIxZjExNjkxZWYwMzM5NWRlMmNjZDViZDBhMjBjOA==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- NzAwYWU2NDlmYjUyZGVhZjkxMzcyZGE0ZTBiNmYyN2EwZmEyNGMzYjJmNTcz
10
- N2IyZmRkNWVjZjU0ZDVmNGQxYmYxZGJkOTE0YTdkZTBjMDc3MmMwZDU2NjJk
11
- NWUyYWRjN2E4NDg4YWEwY2U0N2MyMDhlMzI2OTY0MDJmNjRiZGE=
9
+ NWQ0NjVjYzAyYzQ2NThiOGJkNGU2OTNiYzZmMDA1N2JhOTQ4MTBjNjc1N2Jl
10
+ NjI4ZWRkM2IzNWRjOTZhOTdmYzNjMDkyMzFjMjcwZTczNmYxMzAyZjRmZmIw
11
+ NDQzZGY3Y2EwYjIxZmY4OGEyODVhMWViNTM0MWUxYjhhMWRkMTU=
12
12
  data.tar.gz: !binary |-
13
- MmYyY2I4MTQ5ZTA4OGIxZjYzOWFhOTc1NDk5NWI5YWMwZjJmN2Q0NGU1Y2Jm
14
- MTQwZGU3ZDlmNTgwMThkZGQ2OTBmMjU5NTY3OTY3OGQ5NzA3NjQxODYwZThj
15
- MThjMjgxMmQ0YzU0MTYyZDljZGY1NTI0NzllZGExYzRkZjMxYmU=
13
+ ZGIxZTA4OWY1NzRhMTRjMDY0NDE3YmIwMDM5M2ZjZTBjNGFlYWI0Yzk2YzI0
14
+ NDBmOTQ0MWVhNDdhZGEzNGU0ZTY0MzdlYmU3MzY5YjE1MTBmZWIyY2RhYjE5
15
+ YTQ5NjI5ZGVkNjM1OTQzM2ZhOTU3NzBkYzBlZmM5OWU5OTQyOTY=
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ === 0.5.3
2
+ * bug fixes.
3
+ * improve form fields.
4
+ * memory fixes.
5
+ * add selected image support for tab bar items.
6
+
1
7
  === 0.5.2
2
8
  * fix bugs.
3
9
 
data/Gemfile.lock CHANGED
@@ -1,13 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- motion-prime (0.5.2)
4
+ motion-prime (0.5.3)
5
5
  bubble-wrap
6
6
  cocoapods
7
7
  methadone
8
8
  motion-cocoapods
9
9
  motion-require
10
10
  motion-support
11
+ rm-digest
11
12
  sugarcube
12
13
 
13
14
  GEM
@@ -53,6 +54,7 @@ GEM
53
54
  nap (0.6.0)
54
55
  open4 (1.3.0)
55
56
  rake (10.1.0)
57
+ rm-digest (0.0.2)
56
58
  sugarcube (1.3.7)
57
59
  xcodeproj (0.14.1)
58
60
  activesupport (~> 3.0)
data/README.md CHANGED
@@ -4,6 +4,11 @@
4
4
 
5
5
  MotionPrime is yet another framework written on RubyMotion for creating really fast iOS applications.
6
6
 
7
+ ## Why MotionPrime?
8
+
9
+ * Performance. MotionPrime designed to improve creating and scrolling performance of table views.
10
+ * Simplicity. Creating first MotionPrime application is as simple as creating new RubyOnRails application.
11
+
7
12
  ## Getting Started
8
13
 
9
14
  ### 1. Install MotionPrime:
@@ -65,6 +70,10 @@ MotionPrime is yet another framework written on RubyMotion for creating really f
65
70
  * [ECSlidingViewController 2 integration](https://github.com/droidlabs/prime_sliding_menu) (Sidebar)
66
71
  * [RESideMenu integration](https://github.com/droidlabs/prime_reside_menu) (Sidebar)
67
72
 
73
+ ## Samples
74
+
75
+ * [Simple to-do app](https://github.com/droidlabs/prime_sample_todo)
76
+
68
77
  ## Contributing
69
78
 
70
79
  1. Fork it
@@ -73,7 +82,7 @@ MotionPrime is yet another framework written on RubyMotion for creating really f
73
82
  4. Push to the branch (`git push origin my-new-feature`)
74
83
  5. Create new Pull Request
75
84
 
76
- ## Documentation
85
+ ## Help with Documentation
77
86
 
78
87
  We are using [Docco](http://jashkenas.github.io/docco/) to generate documentation.
79
88
 
data/ROADMAP.md CHANGED
@@ -1,16 +1,20 @@
1
1
  === 0.6.0
2
+ * deprecate root level :title option for submit field
3
+ * rename submit element in submit field to button element
4
+ * rename date_picker element in date_picker field to input element
5
+ * add more and better default options for fields
6
+
7
+ === 0.7.0
2
8
  * add cleanup for section events
3
- * add computed_options.get(), this will allow to make sure that options is computed.
4
9
  * add dsl for push notifications
5
10
  * add some extensions/middleware system, at least for networking.
6
11
  * create "display_network_error" extension.
7
12
  * add different templates. some templates should be more like final app.
8
13
 
9
- === 0.7.0
14
+ === 0.8.0
15
+ * add computed_options.get(), this will allow to make sure that options is computed.
10
16
  * add testing framework
11
- * add auth backends to ApiClient: password auth and facebook auth
12
17
 
13
- === 0.8.0
18
+ === 0.9.0
14
19
  * add sections/screens/models generator
15
- * add DSL for ViewStyles#setValue conditions
16
- * add auto-symbol-value for Prime::Config.color items
20
+ * add DSL for ViewStyles#setValue conditions
data/files/Gemfile CHANGED
@@ -3,9 +3,9 @@ source 'http://rubygems.org'
3
3
  gem 'motion-cocoapods', '~> 1.4.0'
4
4
  gem 'motion-support', '~> 0.2.4'
5
5
  gem 'sugarcube', '~> 1.3.7', require: 'sugarcube-classic'
6
- gem 'bubble-wrap', '~> 1.3.0'
6
+ gem 'bubble-wrap', '~> 1.4.0'
7
7
 
8
- gem 'motion-prime', '~> 0.5.1'
8
+ gem 'motion-prime', '~> 0.5.2'
9
9
 
10
10
  # add reside menu for sidebar support
11
11
  gem 'prime_reside_menu', '~> 0.1.3'
data/files/Gemfile.lock CHANGED
@@ -4,35 +4,37 @@ GEM
4
4
  activesupport (3.2.16)
5
5
  i18n (~> 0.6, >= 0.6.4)
6
6
  multi_json (~> 1.0)
7
- bubble-wrap (1.3.0)
7
+ bubble-wrap (1.4.0)
8
8
  claide (0.4.0)
9
- cocoapods (0.28.0)
9
+ cocoapods (0.29.0)
10
10
  activesupport (>= 3.2.15, < 4)
11
11
  claide (~> 0.4.0)
12
- cocoapods-core (= 0.28.0)
13
- cocoapods-downloader (~> 0.2.0)
12
+ cocoapods-core (= 0.29.0)
13
+ cocoapods-downloader (~> 0.3.0)
14
+ cocoapods-try-release-fix (~> 0.1.1)
14
15
  colored (~> 1.2)
15
16
  escape (~> 0.0.4)
16
17
  json_pure (~> 1.8)
18
+ nap (~> 0.5)
17
19
  open4 (~> 1.3)
18
20
  xcodeproj (~> 0.14.1)
19
- cocoapods-core (0.28.0)
21
+ cocoapods-core (0.29.0)
20
22
  activesupport (>= 3.2.15, < 4)
21
23
  fuzzy_match (~> 2.0.4)
22
- json (~> 1.8)
24
+ json_pure (~> 1.8)
23
25
  nap (~> 0.5)
24
- cocoapods-downloader (0.2.0)
26
+ cocoapods-downloader (0.3.0)
27
+ cocoapods-try-release-fix (0.1.1)
25
28
  colored (1.2)
26
29
  escape (0.0.4)
27
30
  fuzzy_match (2.0.4)
28
31
  i18n (0.6.9)
29
- json (1.8.1)
30
32
  json_pure (1.8.1)
31
33
  methadone (1.3.1)
32
34
  bundler
33
35
  motion-cocoapods (1.4.0)
34
36
  cocoapods (>= 0.26.2)
35
- motion-prime (0.5.1)
37
+ motion-prime (0.5.2)
36
38
  bubble-wrap
37
39
  cocoapods
38
40
  methadone
@@ -41,9 +43,9 @@ GEM
41
43
  motion-support
42
44
  sugarcube
43
45
  motion-require (0.0.7)
44
- motion-support (0.2.5)
46
+ motion-support (0.2.6)
45
47
  motion-require (>= 0.0.6)
46
- multi_json (1.8.2)
48
+ multi_json (1.8.4)
47
49
  nap (0.6.0)
48
50
  open4 (1.3.0)
49
51
  prime_reside_menu (0.1.3)
@@ -61,9 +63,9 @@ PLATFORMS
61
63
  ruby
62
64
 
63
65
  DEPENDENCIES
64
- bubble-wrap (~> 1.3.0)
66
+ bubble-wrap (~> 1.4.0)
65
67
  motion-cocoapods (~> 1.4.0)
66
- motion-prime (~> 0.5.1)
68
+ motion-prime (~> 0.5.2)
67
69
  motion-support (~> 0.2.4)
68
70
  prime_reside_menu (~> 0.1.3)
69
71
  sugarcube (~> 1.3.7)
data/files/Rakefile CHANGED
@@ -7,6 +7,7 @@ require 'bundler'
7
7
  Bundler.require
8
8
  require 'motion-prime'
9
9
 
10
+ require File.expand_path 'app/environment.rb'
10
11
  Motion::Project::App.setup do |app|
11
12
  # Use `rake config' to see complete project settings.
12
13
  app.name = 'Prime Project'
@@ -1,7 +1,7 @@
1
1
  class AppDelegate < Prime::BaseAppDelegate
2
2
  def on_load(app, options)
3
3
  setup_navigation_styles
4
- open_screen HomeScreen.new, sidebar: SidebarScreen.new(navigation: false)
4
+ open_screen :home, sidebar: true
5
5
  end
6
6
 
7
7
  def setup_navigation_styles
data/lib/motion-prime.rb CHANGED
@@ -3,6 +3,7 @@ require 'motion-support'
3
3
  require 'sugarcube-common'
4
4
  require 'bubble-wrap'
5
5
  require 'bubble-wrap/reactor'
6
+ require 'rm-digest'
6
7
  require File.expand_path('../../motion-prime/env.rb', __FILE__)
7
8
  require File.expand_path('../../motion-prime/prime.rb', __FILE__)
8
9
 
@@ -16,7 +17,6 @@ Motion::Project::App.setup do |app|
16
17
  pod 'SDWebImage'
17
18
  pod 'SVPullToRefresh'
18
19
  pod 'MBAlertView'
19
- pod 'SDSegmentedControl'
20
- pod 'MBProgressHUD'
20
+ pod 'MBProgressHUD', '~> 0.8'
21
21
  end
22
22
  end
data/motion-prime.gemspec CHANGED
@@ -27,4 +27,5 @@ Gem::Specification.new do |spec|
27
27
  spec.add_dependency 'bubble-wrap'
28
28
  spec.add_dependency 'sugarcube'
29
29
  spec.add_dependency("methadone")
30
+ spec.add_dependency("rm-digest")
30
31
  end
@@ -5,35 +5,39 @@ class ApiClient
5
5
  self.access_token = options[:access_token]
6
6
  end
7
7
 
8
- def parse_json(text)
9
- Prime::JSON.parse(text)
10
- rescue
11
- NSLog("Can't parse json: #{text}")
12
- false
13
- end
14
-
15
8
  def request_params(data)
9
+ data = data.clone
16
10
  files = data.delete(:files)
17
- params = {payload: data, no_redirect: true, format: :form_data}
11
+ params = {
12
+ payload: data,
13
+ no_redirect: !config.allow_redirect,
14
+ format: config.request_format
15
+ }
18
16
  if files.present?
19
17
  params.merge!(files: files)
20
18
  end
21
- if MotionPrime::Config.api.http_auth.present?
22
- params.merge!(credentials: MotionPrime::Config.api.http_auth.to_hash)
19
+ if config.http_auth?
20
+ params.merge!(credentials: config.http_auth.to_hash)
21
+ end
22
+ if config.sign_request?
23
+ signature = RmDigest::MD5.hexdigest(
24
+ config.signature_secret + data.keys.map(&:to_s).sort.join
25
+ )
26
+ params[:payload].merge!(sign: signature)
23
27
  end
24
28
  params
25
29
  end
26
30
 
27
- def authenticate(username, password, &block)
28
- data = {
31
+ def authenticate(username = nil, password = nil, data = nil, &block)
32
+ data ||= {
29
33
  grant_type: "password",
30
34
  username: username,
31
35
  password: password,
32
- client_id: MotionPrime::Config.api.client_id,
33
- client_secret: MotionPrime::Config.api.client_secret
36
+ client_id: config.client_id,
37
+ client_secret: config.client_secret
34
38
  }
35
39
  use_callback = block_given?
36
- BW::HTTP.post("#{MotionPrime::Config.api.base}/oauth/token", request_params(data)) do |response|
40
+ BW::HTTP.post("#{config.base}#{config.auth_path}", request_params(data)) do |response|
37
41
  access_token = if response.ok?
38
42
  json = parse_json(response.body)
39
43
  json[:access_token]
@@ -48,40 +52,78 @@ class ApiClient
48
52
 
49
53
  def api_url(path)
50
54
  return path if path =~ /^http(s)?:\/\//
51
- "#{MotionPrime::Config.api.base}/api/v1#{path}"
55
+ "#{config.base}#{config.api_namespace}#{path}"
52
56
  end
53
57
 
54
58
  def page_url(path)
55
- "#{MotionPrime::Config.api.base}/#{path}"
59
+ "#{config.base}#{path}"
56
60
  end
57
61
 
58
62
  def resource_url(path)
59
63
  # return if path.blank?
60
- base = Prime::Config.api.resource_base.present? ? Prime::Config.api.resource_base : Prime::Config.api.base
64
+ base = config.resource_base? ? config.resource_base : config.base
61
65
  "#{base}#{path}"
62
66
  end
63
67
 
64
- def request(method, path, params = {}, &block)
68
+ def request(method, path, params = {}, options = {}, &block)
65
69
  params.merge!(access_token: access_token)
70
+ use_callback = block_given?
66
71
  BW::HTTP.send method, api_url(path), request_params(params) do |response|
67
- json = parse_json(response.body.to_s)
68
- block.call(json, response.status_code)
72
+ if !response.ok? && options[:allow_queue] && config.allow_queue?
73
+ add_to_queue(method: method, path: path, params: params)
74
+ else
75
+ json = parse_json(response.body.to_s)
76
+ block.call(json, response.status_code) if use_callback
77
+ process_queue
78
+ end
79
+ end
80
+ end
81
+
82
+ def process_queue
83
+ queue = user_defaults['api_client_queue']
84
+ user_defaults['api_client_queue'] = []
85
+ Array.wrap(queue).each do |item|
86
+ request(item[:method], item[:path], item[:params].clone.symbolize_keys)
69
87
  end
70
88
  end
71
89
 
72
- def get(path, params = {}, &block)
73
- request(:get, path, params, &block)
90
+ def add_to_queue(item)
91
+ queue = user_defaults['api_client_queue'].clone || []
92
+ queue.push(item)
93
+ user_defaults['api_client_queue'] = queue
94
+ end
95
+
96
+ def get(path, params = {}, options = {}, &block)
97
+ request(:get, path, params, options, &block)
74
98
  end
75
99
 
76
- def put(path, params = {}, &block)
77
- request(:put, path, params, &block)
100
+ def put(path, params = {}, options = {}, &block)
101
+ request(:put, path, params, options, &block)
78
102
  end
79
103
 
80
- def post(path, params = {}, &block)
81
- request(:post, path, params, &block)
104
+ def post(path, params = {}, options = {}, &block)
105
+ options[:allow_queue] = true unless options.has_key?(:allow_queue)
106
+ request(:post, path, params, options, &block)
82
107
  end
83
108
 
84
- def delete(path, params = {}, &block)
85
- request(:delete, path, params, &block)
109
+ def delete(path, params = {}, options = {}, &block)
110
+ options[:allow_queue] = true unless options.has_key?(:allow_queue)
111
+ request(:delete, path, params, options, &block)
86
112
  end
113
+
114
+ private
115
+ def user_defaults
116
+ @user_defaults ||= NSUserDefaults.standardUserDefaults
117
+ end
118
+
119
+ def parse_json(text)
120
+ Prime::JSON.parse(text)
121
+ rescue
122
+ NSLog("Can't parse json: #{text}")
123
+ false
124
+ end
125
+
126
+ def config
127
+ MotionPrime::Config.api_client
128
+ end
87
129
  end
@@ -77,7 +77,7 @@ module MotionPrime
77
77
  self.window.makeKeyAndVisible
78
78
  screen
79
79
  end
80
-
80
+
81
81
  def open_content_screen(screen, options = {})
82
82
  open_root_screen(screen)
83
83
  end
@@ -10,9 +10,16 @@ MotionPrime::Config.configure do |config|
10
10
  colors.base = 0x424242
11
11
  colors.error = 0xef471f
12
12
  end
13
- config.api do |api|
13
+ config.api_client do |api|
14
14
  api.base = "http://example.com"
15
15
  api.client_id = ""
16
16
  api.client_secret = ""
17
+ api.signature_secret = ""
18
+ api.sign_request = false
19
+ api.auth_path = '/oauth/token'
20
+ api.api_namespace = '/api'
21
+ api.request_format = :form_data
22
+ api.allow_redirect = false
23
+ api.allow_queue = false
17
24
  end
18
25
  end
@@ -16,10 +16,11 @@ class Kernel
16
16
  end
17
17
 
18
18
  def clear_instance_variables(options = {})
19
- ivars = self.instance_variables.clone
20
- ivars.each do |ivar|
19
+ ivars = self.instance_variables
20
+ clear_block = proc { |ivar|
21
21
  next if Array.wrap(options[:except]).include?(ivar[1..-1])
22
22
  self.instance_variable_set(ivar, nil)
23
- end
23
+ }.weak!
24
+ ivars.each(&clear_block)
24
25
  end
25
26
  end
@@ -54,9 +54,11 @@ module MotionPrime
54
54
  def get_content_rect(width)
55
55
  raise "Please set element width for content size calculation" unless width
56
56
 
57
- content_attributed_text.boundingRectWithSize(
58
- [width, Float::MAX], options: NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading | NSStringDrawingTruncatesLastVisibleLine, context:nil
59
- )
57
+ options = NSStringDrawingUsesLineFragmentOrigin
58
+ if is_a?(TextViewElement)
59
+ options |= NSStringDrawingUsesFontLeading | NSStringDrawingTruncatesLastVisibleLine
60
+ end
61
+ content_attributed_text.boundingRectWithSize([width, Float::MAX], options: options, context:nil)
60
62
  end
61
63
 
62
64
  def button_content_text
@@ -13,7 +13,7 @@ module MotionPrime
13
13
  def html_string(options)
14
14
  styles = []
15
15
  styles << "color: #{options[:text_color].hex};" if options[:text_color]
16
- styles << "line-height: #{options.fetch(:line_height, options[:line_spacing].to_f + options[:font].pointSize)}px;"
16
+ styles << "line-height: #{options[:line_height] || (options[:line_spacing].to_f + options[:font].pointSize)}px;"
17
17
  styles << "font-family: '#{options[:font].familyName}';"
18
18
  styles << "font-size: #{options[:font].pointSize}px;"
19
19
  styles << "text-align: #{options[:text_alignment_name]};" if options[:text_alignment_name]
@@ -28,10 +28,10 @@ module MotionPrime
28
28
  @view_name = self.class_name_without_kvo.demodulize.underscore.gsub(/(_draw)?_element/, '')
29
29
  end
30
30
 
31
- def dealloc
32
- # pp 'deallocating elemenet', self.name, self.to_s, view_class, view.try(:to_s)
33
- super
34
- end
31
+ # def dealloc
32
+ # pp 'deallocating elemenet', self.name, self.to_s, view_class#, view.try(:to_s)
33
+ # super
34
+ # end
35
35
 
36
36
  def add_target(target = nil, action = 'on_click:', event = :touch)
37
37
  return false unless self.view
@@ -164,6 +164,7 @@ module MotionPrime
164
164
  end.flatten
165
165
  @styles += custom_styles
166
166
  # puts @view_class.to_s + @styles.inspect, ''
167
+ @styles
167
168
  end
168
169
 
169
170
  class << self
@@ -68,14 +68,13 @@ module MotionPrime
68
68
  return if image_data || !computed_options[:url]
69
69
  BW::Reactor.schedule do
70
70
  manager = SDWebImageManager.sharedManager
71
- @screen_ref = screen.strong_ref
72
- @section_ref = section.strong_ref
71
+ @strong_refs = section.strong_references
73
72
  manager.downloadWithURL(computed_options[:url],
74
73
  options: 0,
75
74
  progress: lambda{ |r_size, e_size| },
76
75
  completed: lambda{ |image, error, type, finished|
77
76
  if !image || screen.retainCount == 1 || section.retainCount == 1
78
- @screen_ref = @section_ref = nil
77
+ @strong_refs = nil
79
78
  return
80
79
  end
81
80
 
@@ -87,7 +86,7 @@ module MotionPrime
87
86
  else
88
87
  self.view.performSelectorOnMainThread :setNeedsDisplay, withObject: nil, waitUntilDone: false
89
88
  end
90
- @screen_ref = @section_ref = nil
89
+ @strong_refs = nil
91
90
  }
92
91
  )
93
92
  end
@@ -7,13 +7,13 @@ module MotionPrime
7
7
 
8
8
  def draw_options
9
9
  options = computed_options
10
- text = (options[:html] || options[:text]).to_s.gsub(/^[\n\r]+/, '')
10
+ text = (options[:html] || options[:text]).to_s.gsub(/\A[\n\r]+/, '')
11
11
  text_color = (options[:text_color] || :black).uicolor
12
12
  font = (options[:font] || :system).uifont
13
13
 
14
- text_alignment_name = options.has_key?(:text_alignment) ? options[:text_alignment] : :left
14
+ text_alignment_name = options.fetch(:text_alignment, :left)
15
15
  text_alignment = text_alignment_name.uitextalignment
16
- line_break_mode_name = options.has_key?(:line_break_mode) ? options[:line_break_mode] : :tail_truncation
16
+ line_break_mode_name = options.fetch(:line_break_mode, :tail_truncation)
17
17
  line_break_mode = line_break_mode_name.uilinebreakmode
18
18
 
19
19
  top_left_corner = CGPointMake(computed_inner_left, computed_inner_top)
data/motion-prime/env.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  module MotionPrime
2
2
  class Env
3
3
  def env
4
- ENV['PRIME_ENV'] || ENV['RUBYMOTION_ENV'] ||
4
+ (defined?(NSBundle) && NSBundle.mainBundle.objectForInfoDictionaryKey('PRIME_ENV')) ||
5
+ ENV['PRIME_ENV'] ||
6
+ ENV['RUBYMOTION_ENV'] ||
5
7
  (defined?(RUBYMOTION_ENV) && RUBYMOTION_ENV) ||
6
8
  'development'
7
9
  end
@@ -34,6 +34,7 @@ module MotionPrime
34
34
  end
35
35
 
36
36
  def add(key, error)
37
+ initialize_for_key(key)
37
38
  send(unique_key(key)) << error
38
39
  end
39
40
 
@@ -11,7 +11,7 @@ module MotionPrime
11
11
  when :persistent, :file
12
12
  path ||= begin
13
13
  documents_path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true)[0]
14
- documents_path + "/nano.db"
14
+ documents_path + "/nano_#{Prime.env.to_s}.db"
15
15
  end
16
16
  store = NSFNanoStore.createAndOpenStoreWithType(NSFPersistentStoreType, path: path, error: error_ptr)
17
17
  else
@@ -30,24 +30,29 @@ module MotionPrime
30
30
  end
31
31
 
32
32
  def will_appear
33
- unless @on_appear_happened
33
+ @visible = true
34
+ @on_appear_happened ||= {}
35
+ unless @on_appear_happened[view.object_id]
34
36
  setup view, styles: default_styles do
35
37
  run_callbacks :render { render }
36
38
  end
37
39
  end
38
- @on_appear_happened = true
40
+ @on_appear_happened[view.object_id] = true
41
+ end
42
+
43
+ def will_disappear
44
+ @visible = false
39
45
  end
40
46
 
41
47
  def dealloc
42
- pp self.object_id, 'Deallocating Screen', self.retainCount
48
+ pp 'Deallocating Screen', self.object_id, self.to_s
43
49
  # FIXME: calling instance_eval in title method (_base_screen_mixin) instance variables need to be cleared manually
44
- # clear_instance_variables cause BAD_ACCESS errors too
45
- @main_section = nil
50
+ clear_instance_variables
46
51
  super
47
52
  end
48
53
 
49
54
  def visible?
50
- self.isViewLoaded && view.window
55
+ @visible
51
56
  end
52
57
  end
53
58
  end
@@ -77,6 +77,10 @@ module MotionPrime
77
77
  @cached_draw_image ||= MotionSupport::HashWithIndifferentAccess.new
78
78
  end
79
79
 
80
+ def strong_references
81
+ [self, screen].map(&:strong_ref)
82
+ end
83
+
80
84
  private
81
85
  def set_container_gesture_recognizer
82
86
  single_tap = UITapGestureRecognizer.alloc.initWithTarget(self, action: 'on_container_tap_gesture:')
@@ -37,7 +37,7 @@ module MotionPrime
37
37
  end
38
38
 
39
39
  def dealloc
40
- pp 'deallocating section', self.name, self.elements.try(:count), self.to_s, self.object_id
40
+ # pp 'deallocating section', self.name, self.elements.try(:count), self.to_s, self.object_id
41
41
  NSNotificationCenter.defaultCenter.removeObserver self # unbinding events created in bind_keyboard_events
42
42
  super
43
43
  end
@@ -110,7 +110,7 @@ module MotionPrime
110
110
  end
111
111
  end
112
112
 
113
- def add_element(key, options)
113
+ def add_element(key, options = {})
114
114
  return unless render_element?(key)
115
115
  opts = options.clone
116
116
  index = opts.delete(:at)
@@ -254,7 +254,7 @@ module MotionPrime
254
254
  # we should clone options to prevent overriding options
255
255
  # in next element with same name in another class
256
256
  options = opts.clone
257
- options[:type] ||= (options[:text] || options[:attributed_text_options]) ? :label : :view
257
+ options[:type] ||= (options[:text] || options[:html] || options[:attributed_text_options]) ? :label : :view
258
258
  options.merge(screen: screen, section: self.weak_ref)
259
259
  end
260
260
 
@@ -11,9 +11,15 @@ module MotionPrime
11
11
 
12
12
  def prepare_table_data
13
13
  @form = @options[:table]
14
- @errors_observer_options = normalize_options(options.delete(:observe_errors).clone, self) if options[:observe_errors]
14
+ if options[:observe_errors]
15
+ @errors_observer_options = normalize_options(options.delete(:observe_errors), self)
16
+ end
15
17
  end
16
18
 
19
+ # Returns true if we should render element in current state
20
+ #
21
+ # @param element_name [Symbol] name of element in field
22
+ # @return [Boolean]
17
23
  def render_element?(element_name)
18
24
  case element_name.to_sym
19
25
  when :error_message
@@ -24,6 +30,19 @@ module MotionPrime
24
30
  end
25
31
  end
26
32
 
33
+ # Changes height of the field (the cell in table) with animation.
34
+ #
35
+ # @param height [Integet] new height of field
36
+ # @return [MotionPrime::BaseFieldSection]
37
+ def update_height(height)
38
+ container_options[:height] = height
39
+ field_index = form.field_indexes[name]
40
+ index = field_index.split('_').map(&:to_i)
41
+ path = NSIndexPath.indexPathForRow(index.last, inSection: index.first)
42
+ form.table_view.reloadRowsAtIndexPaths([path], withRowAnimation: UITableViewRowAnimationNone)
43
+ self
44
+ end
45
+
27
46
  def on_section_render
28
47
  @status_for_updated = :rendered
29
48
  form.register_elements_from_section(self)
@@ -57,7 +76,7 @@ module MotionPrime
57
76
 
58
77
  def focus(begin_editing = true)
59
78
  # scroll to cell
60
- path = form.table_view.indexPathForCell cell
79
+ path = form.table_view.indexPathForCell(cell)
61
80
  form.table_view.scrollToRowAtIndexPath path,
62
81
  atScrollPosition: UITableViewScrollPositionTop, animated: true
63
82
  # focus on text field
@@ -4,14 +4,21 @@ module MotionPrime
4
4
  element :label, type: :label do
5
5
  options[:label] || {}
6
6
  end
7
- element :date_picker, type: :date_picker
7
+ element :date_picker, type: :date_picker do
8
+ options[:input] || {}
9
+ end
8
10
 
9
11
  after_render :bind_date_picker
10
12
 
11
13
  def bind_date_picker
12
14
  picker = view(:date_picker)
13
15
  picker.setDelegate form
14
- picker.setDate NSDate.date, animated: true
16
+ unless picker.date
17
+ picker.setDate NSDate.date, animated: true
18
+ end
19
+ picker.on :change do
20
+ form.send(options[:action]) if options[:action]
21
+ end
15
22
  end
16
23
  end
17
24
  end
@@ -1,8 +1,10 @@
1
1
  module MotionPrime
2
2
  class SubmitFieldSection < BaseFieldSection
3
3
  element :submit, type: :button do
4
- {title: options[:title]}
4
+ {title: options[:title]}.merge(options[:button] || {})
5
5
  end
6
+ element :error_message, type: :error_message, text: proc { all_errors.join("\n") if observing_errors? }
7
+
6
8
  after_render :bind_submit
7
9
 
8
10
  def bind_submit
@@ -51,11 +51,17 @@ module MotionPrime
51
51
  @preloader_queue[-1] = :cancelled if @preloader_queue.present?
52
52
  end
53
53
 
54
+ def reload_cell(section)
55
+ section.elements.values.each(&:compute_options!)
56
+ section.cached_draw_image = nil
57
+ # TODO: reset date stamps, reload row
58
+ end
59
+
54
60
  def table_styles
55
61
  type = self.is_a?(FormSection) ? :base_form : :base_table
56
62
 
57
63
  base_styles = [type]
58
- base_styles << :"#{type}_with_sections" #unless flat_data?
64
+ base_styles << :"#{type}_with_sections" unless flat_data?
59
65
  item_styles = [name.to_sym]
60
66
  item_styles << @styles if @styles.present?
61
67
  {common: base_styles, specific: item_styles}
@@ -371,7 +377,6 @@ module MotionPrime
371
377
  BW::Reactor.schedule(@preloader_queue.count) do |queue_id|
372
378
  @preloader_queue[queue_id] = :in_progress
373
379
  @strong_refs[queue_id] = screen.strong_ref
374
-
375
380
  result = load_count.times do |offset|
376
381
  if @preloader_queue[queue_id] == :cancelled
377
382
  @strong_refs[queue_id] = nil
@@ -19,8 +19,8 @@ MotionPrime::Styles.define :base do
19
19
  # basic form styles
20
20
  # ----------
21
21
  style :form,
22
- width: 260,
23
- left: 30,
22
+ width: 280,
23
+ left: 20,
24
24
  top: 0,
25
25
  right: 30,
26
26
  bottom: 0,
@@ -37,7 +37,8 @@ MotionPrime::Styles.define :base_form do
37
37
  style :field_error_message,
38
38
  top: nil,
39
39
  bottom: 0,
40
- width: 300,
40
+ width: 280,
41
+ left: 0,
41
42
  line_break_mode: :word_wrap,
42
43
  number_of_lines: 0,
43
44
  size_to_fit: true,
@@ -79,6 +80,7 @@ MotionPrime::Styles.define :base_form do
79
80
  title_label: {
80
81
  font: proc { MotionPrime::Config.font.name.uifont(16) }
81
82
  }
83
+
82
84
  style :select_field_image,
83
85
  image: "images/forms/select_arrow.png",
84
86
  top: 40,
@@ -89,7 +91,11 @@ MotionPrime::Styles.define :base_form do
89
91
  style :with_sections_field_switch,
90
92
  right: 20
91
93
 
92
- style :with_sections_field_text_field, :with_sections_field_text_view, :with_sections_field_password_field, :with_sections_field_label, :with_sections_field_button,
94
+ style :with_sections_field_text_field,
95
+ :with_sections_field_text_view,
96
+ :with_sections_field_password_field,
97
+ :with_sections_field_label,
98
+ :with_sections_field_button,
93
99
  left: 20,
94
100
  right: 20
95
101
 
@@ -0,0 +1,12 @@
1
+ class MPTableViewCellContentView < UITableViewCellContentView
2
+ attr_accessor :section
3
+
4
+ def setSection(section)
5
+ @section = section.try(:weak_ref)
6
+ end
7
+
8
+ def drawRect(rect)
9
+ section.try(:draw_in, rect)
10
+ super
11
+ end
12
+ end
@@ -1,23 +1,25 @@
1
1
  class MPCellWithSection < UITableViewCell
2
2
  attr_reader :section
3
+ attr_accessor :scroll_view, :content_view
3
4
 
4
- def setSection(section)
5
- @section = section.try(:weak_ref)
6
- @section_name = section.try(:name) # TODO: remove after debug
7
- end
8
-
9
- def drawRect(rect)
5
+ def setNeedsDisplay
6
+ content_view.try(:setNeedsDisplay)
10
7
  super
11
- draw_in(rect)
12
8
  end
13
9
 
14
- def draw_in(rect)
15
- # pp '++ drawing', @section_name, self.object_id
16
- section.draw_in(rect) if section && section.respond_to?(:draw_in)
10
+ def setSection(section)
11
+ @section = section.try(:weak_ref)
12
+ self.content_view.setSection(@section)
17
13
  end
18
14
 
19
- # def dealloc
20
- # pp '--- deallog cell with section', @section_name, self.object_id
21
- # super
22
- # end
15
+ def initialize_content
16
+ self.scroll_view = self.subviews.first
17
+ self.scroll_view.subviews.first.removeFromSuperview
18
+ self.content_view = MPTableViewCellContentView.alloc.initWithFrame(self.bounds)
19
+ self.content_view.setBackgroundColor(:clear.uicolor)
20
+ self.content_view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
21
+ self.content_view.top = 0
22
+ self.content_view.left = 0
23
+ self.scroll_view.addSubview(content_view)
24
+ end
23
25
  end
@@ -5,14 +5,11 @@ module MotionPrime
5
5
 
6
6
  view_controllers = []
7
7
 
8
- screens.each_with_index do |screen, index|
9
- if screen.is_a?(Hash)
10
- screen, image, title = screen[:screen], screen[:image], screen[:title]
11
- screen = Screen.create_with_options(screen).try(:weak_ref)
12
- title ||= screen.title
13
- image = image.uiimage if image
14
- screen.tabBarItem = UITabBarItem.alloc.initWithTitle title, image: image, tag: index
8
+ screens.each_with_index do |options, index|
9
+ if options.is_a?(Hash)
10
+ screen = init_screen_with_options(options, tag: index)
15
11
  else
12
+ screen = options
16
13
  screen.tabBarItem.tag = index
17
14
  end
18
15
 
@@ -33,5 +30,29 @@ module MotionPrime
33
30
  end
34
31
  controller
35
32
  end
33
+
34
+ protected
35
+ def self.init_screen_with_options(options, tag: tag)
36
+ screen, image, title = options[:screen], options[:image], options[:title]
37
+ screen = Screen.create_with_options(screen).try(:weak_ref)
38
+ title ||= screen.title
39
+
40
+ image = extract_image_from_options(options, with_key: :image)
41
+ screen.tabBarItem = UITabBarItem.alloc.initWithTitle title, image: image, tag: tag
42
+
43
+ selected_image = extract_image_from_options(options, with_key: :selected_image)
44
+ screen.tabBarItem.setSelectedImage(selected_image) if selected_image
45
+ screen
46
+ end
47
+
48
+ def self.extract_image_from_options(options, with_key: key)
49
+ image = options[key]
50
+ return unless image
51
+ image = image.uiimage
52
+ if options[:translucent] === false
53
+ image = image.imageWithRenderingMode UIImageRenderingModeAlwaysOriginal
54
+ end
55
+ image
56
+ end
36
57
  end
37
58
  end
@@ -1,3 +1,3 @@
1
1
  module MotionPrime
2
- VERSION = "0.5.2"
2
+ VERSION = "0.5.3"
3
3
  end
@@ -2,7 +2,8 @@
2
2
  motion_require '../support/mp_cell_with_section'
3
3
  module MotionPrime
4
4
  module Layout
5
- def add_view(klass, options = {}, &block)
5
+ def add_view(klass, options = {}, &block)
6
+ options = options.clone
6
7
  bounds = if view_stack.empty?
7
8
  options.delete(:parent_view).try(:bounds) || CGRectZero
8
9
  else
@@ -35,6 +35,7 @@ module MotionPrime
35
35
  if options.slice(:line_spacing, :line_height, :underline, :fragment_color).any?
36
36
  options[:attributed_text_options] = {
37
37
  text: options.delete(:text),
38
+ html: options.delete(:html),
38
39
  line_spacing: options.delete(:line_spacing),
39
40
  line_height: options.delete(:line_height),
40
41
  fragment_color: options.delete(:fragment_color),
@@ -74,7 +75,7 @@ module MotionPrime
74
75
  is_custom_button = options[:background_image] || options[:title_color]
75
76
  default_button_type = is_custom_button ? :custom : :rounded
76
77
  button_type = (options.delete(:button_type) || default_button_type).uibuttontype
77
- button = klass.buttonWithType button_type
78
+ klass.buttonWithType button_type
78
79
  },
79
80
  'UIImageView' => Proc.new{|klass, options|
80
81
  image = options.delete(:image)
@@ -109,7 +110,9 @@ module MotionPrime
109
110
  options.delete(:gradient)
110
111
  end
111
112
 
112
- klass.alloc.initWithStyle style, reuseIdentifier: options.delete(:reuse_identifier)
113
+ obj = klass.alloc.initWithStyle style, reuseIdentifier: options.delete(:reuse_identifier)
114
+ obj.initialize_content
115
+ obj
113
116
  },
114
117
  'MPViewWithSection' => Proc.new{|klass, options|
115
118
  if options[:has_drawn_content]
@@ -106,25 +106,41 @@ module MotionPrime
106
106
  view.mask = mask_layer
107
107
  elsif key == 'attributed_text_options'
108
108
  attributes = {}
109
- if line_spacing = value[:line_spacing] || line_height = value[:line_height]
110
- paragrahStyle = NSMutableParagraphStyle.alloc.init
111
- line_height ? paragrahStyle.setMinimumLineHeight(line_height) : paragrahStyle.setLineSpacing(line_spacing)
112
- attributes[NSParagraphStyleAttributeName] = paragrahStyle
113
- end
109
+ if value[:html] # TODO: use _text_mixin
110
+ styles = []
111
+ styles << "color: #{options[:text_color].hex};" if options[:text_color]
112
+ styles << "line-height: #{options[:line_height] || (options[:line_spacing].to_f + options[:font].pointSize)}px;"
113
+ styles << "font-family: '#{options[:font].familyName}';"
114
+ styles << "font-size: #{options[:font].pointSize}px;"
114
115
 
115
- attributedString = NSAttributedString.alloc.initWithString(value[:text], attributes: attributes)
116
- if underline_range = value[:underline]
117
- attributedString = NSMutableAttributedString.alloc.initWithAttributedString(attributedString)
118
- attributedString.addAttributes({NSUnderlineStyleAttributeName => NSUnderlineStyleSingle}, range: underline_range)
119
- end
120
- if fragment_color = value[:fragment_color]
121
- attributedString = NSMutableAttributedString.alloc.initWithAttributedString(attributedString)
122
- attributedString.addAttributes({NSForegroundColorAttributeName => fragment_color[:color].uicolor}, range: fragment_color[:range])
123
- end
124
- if view.is_a?(UIButton)
125
- view.setAttributedTitle attributedString, forState: UIControlStateNormal
116
+ html_options = {
117
+ NSDocumentTypeDocumentAttribute => NSHTMLTextDocumentType,
118
+ NSCharacterEncodingDocumentAttribute => NSNumber.numberWithInt(NSUTF8StringEncoding)
119
+ }
120
+ text = "#{value[:html]}<style>* { #{styles.join} }</style>"
121
+ view.attributedText = NSAttributedString.alloc.initWithData(text.dataUsingEncoding(NSUTF8StringEncoding), options: html_options, documentAttributes: nil, error: nil)
126
122
  else
127
- view.attributedText = attributedString
123
+ if line_spacing = value[:line_spacing] || line_height = value[:line_height]
124
+ paragrahStyle = NSMutableParagraphStyle.alloc.init
125
+ line_height ? paragrahStyle.setMinimumLineHeight(line_height) : paragrahStyle.setLineSpacing(line_spacing)
126
+ attributes[NSParagraphStyleAttributeName] = paragrahStyle
127
+ end
128
+
129
+ attributedString = NSAttributedString.alloc.initWithString(value[:text].to_s, attributes: attributes)
130
+ if underline_range = value[:underline]
131
+ underline_range = [0, value[:text].length] if underline_range === true
132
+ attributedString = NSMutableAttributedString.alloc.initWithAttributedString(attributedString)
133
+ attributedString.addAttributes({NSUnderlineStyleAttributeName => NSUnderlineStyleSingle}, range: underline_range)
134
+ end
135
+ if fragment_color = value[:fragment_color]
136
+ attributedString = NSMutableAttributedString.alloc.initWithAttributedString(attributedString)
137
+ attributedString.addAttributes({NSForegroundColorAttributeName => fragment_color[:color].uicolor}, range: fragment_color[:range])
138
+ end
139
+ if view.is_a?(UIButton)
140
+ view.setAttributedTitle attributedString, forState: UIControlStateNormal
141
+ else
142
+ view.attributedText = attributedString
143
+ end
128
144
  end
129
145
  elsif key == 'gradient'
130
146
  gradient = prepare_gradient(value)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: motion-prime
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Iskander Haziev
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-01-12 00:00:00.000000000 Z
12
+ date: 2014-01-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -151,6 +151,20 @@ dependencies:
151
151
  - - ! '>='
152
152
  - !ruby/object:Gem::Version
153
153
  version: '0'
154
+ - !ruby/object:Gem::Dependency
155
+ name: rm-digest
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ! '>='
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ type: :runtime
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ! '>='
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
154
168
  description: RubyMotion apps development framework
155
169
  email:
156
170
  - gvalmon@gmail.com
@@ -294,6 +308,7 @@ files:
294
308
  - motion-prime/support/_key_value_store.rb
295
309
  - motion-prime/support/_padding_attribute.rb
296
310
  - motion-prime/support/mp_button.rb
311
+ - motion-prime/support/mp_cell_content_view.rb
297
312
  - motion-prime/support/mp_cell_with_section.rb
298
313
  - motion-prime/support/mp_label.rb
299
314
  - motion-prime/support/mp_search_bar_custom.rb