motion-prime 0.5.2 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
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