motion-prime 0.1.0
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.
- data/.gitignore +17 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +83 -0
- data/README.md +67 -0
- data/Rakefile +23 -0
- data/app/app_delegate.rb +5 -0
- data/doc/SECTION.md +7 -0
- data/doc/STYLE.md +39 -0
- data/files/Gemfile +3 -0
- data/files/Rakefile +16 -0
- data/files/app/app_delegate.rb +4 -0
- data/files/app/screens/application_screen.rb +3 -0
- data/lib/motion-prime.rb +14 -0
- data/lib/view_styler.rb +141 -0
- data/motion-prime.gemspec +27 -0
- data/motion-prime/app_delegate.rb +56 -0
- data/motion-prime/elements/base.rb +94 -0
- data/motion-prime/elements/button.rb +7 -0
- data/motion-prime/elements/draw.rb +56 -0
- data/motion-prime/elements/draw/image.rb +43 -0
- data/motion-prime/elements/draw/label.rb +13 -0
- data/motion-prime/elements/image.rb +14 -0
- data/motion-prime/elements/label.rb +20 -0
- data/motion-prime/elements/text_field.rb +7 -0
- data/motion-prime/elements/text_view.rb +7 -0
- data/motion-prime/helpers/has_authorization.rb +10 -0
- data/motion-prime/helpers/has_search_bar.rb +25 -0
- data/motion-prime/models/base.rb +220 -0
- data/motion-prime/screens/_aliases_mixin.rb +32 -0
- data/motion-prime/screens/_base_mixin.rb +119 -0
- data/motion-prime/screens/_navigation_bar_mixin.rb +57 -0
- data/motion-prime/screens/_navigation_mixin.rb +118 -0
- data/motion-prime/screens/_orientations_mixin.rb +39 -0
- data/motion-prime/screens/base_screen.rb +22 -0
- data/motion-prime/screens/sidebar_container_screen.rb +58 -0
- data/motion-prime/sections/base.rb +101 -0
- data/motion-prime/sections/draw.rb +62 -0
- data/motion-prime/sections/form.rb +103 -0
- data/motion-prime/sections/form/base_field_section.rb +26 -0
- data/motion-prime/sections/form/password_field_section.rb +33 -0
- data/motion-prime/sections/form/select_field_section.rb +40 -0
- data/motion-prime/sections/form/string_field_section.rb +32 -0
- data/motion-prime/sections/form/submit_field_section.rb +20 -0
- data/motion-prime/sections/form/text_field_section.rb +33 -0
- data/motion-prime/sections/table.rb +97 -0
- data/motion-prime/sections/table/refresh_mixin.rb +13 -0
- data/motion-prime/styles/forms.rb +93 -0
- data/motion-prime/support/_key_value_store.rb +10 -0
- data/motion-prime/support/dm_button.rb +22 -0
- data/motion-prime/support/dm_cell_with_section.rb +12 -0
- data/motion-prime/support/dm_text_field.rb +30 -0
- data/motion-prime/support/dm_text_view.rb +93 -0
- data/motion-prime/support/dm_view_controller.rb +50 -0
- data/motion-prime/support/dm_view_with_section.rb +11 -0
- data/motion-prime/support/navigation_controller.rb +4 -0
- data/motion-prime/support/ui_search_bar_custom.rb +10 -0
- data/motion-prime/support/ui_view.rb +59 -0
- data/motion-prime/version.rb +3 -0
- data/motion-prime/views/layout.rb +45 -0
- data/motion-prime/views/styles.rb +44 -0
- data/motion-prime/views/view_builder.rb +80 -0
- data/motion-prime/views/view_styler.rb +141 -0
- data/resources/Default-568h@2x.png +0 -0
- data/spec/main_spec.rb +9 -0
- metadata +245 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source 'http://rubygems.org'
|
2
|
+
|
3
|
+
gem 'cocoapods', '0.19.1'
|
4
|
+
gem 'motion-cocoapods', '1.3.2'
|
5
|
+
|
6
|
+
# ruby sugar
|
7
|
+
gem 'sugarcube', '0.20.23'
|
8
|
+
gem 'motion-support', '0.2.4'
|
9
|
+
gem 'bubble-wrap', '1.3.0'
|
10
|
+
|
11
|
+
# modelds
|
12
|
+
gem 'nano-store', '0.6.3'
|
13
|
+
gemspec
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
motion-prime (0.1.0)
|
5
|
+
bubble-wrap
|
6
|
+
cocoapods
|
7
|
+
motion-cocoapods
|
8
|
+
motion-require
|
9
|
+
motion-support
|
10
|
+
nano-store
|
11
|
+
sugarcube
|
12
|
+
|
13
|
+
GEM
|
14
|
+
remote: http://rubygems.org/
|
15
|
+
specs:
|
16
|
+
activesupport (3.2.13)
|
17
|
+
i18n (= 0.6.1)
|
18
|
+
multi_json (~> 1.0)
|
19
|
+
addressable (2.3.5)
|
20
|
+
bubble-wrap (1.3.0)
|
21
|
+
claide (0.2.0)
|
22
|
+
cocoapods (0.19.1)
|
23
|
+
activesupport (~> 3.2.13)
|
24
|
+
claide (~> 0.2.0)
|
25
|
+
cocoapods-core (= 0.19.1)
|
26
|
+
cocoapods-downloader (~> 0.1.0)
|
27
|
+
colored (~> 1.2)
|
28
|
+
escape (~> 0.0.4)
|
29
|
+
faraday (~> 0.8.1)
|
30
|
+
json (~> 1.7.3)
|
31
|
+
octokit (~> 1.7)
|
32
|
+
open4 (~> 1.3.0)
|
33
|
+
rake (~> 10.0.0)
|
34
|
+
xcodeproj (~> 0.5.5)
|
35
|
+
cocoapods-core (0.19.1)
|
36
|
+
activesupport (~> 3.2.13)
|
37
|
+
rake (~> 10.0.0)
|
38
|
+
cocoapods-downloader (0.1.1)
|
39
|
+
colored (1.2)
|
40
|
+
escape (0.0.4)
|
41
|
+
faraday (0.8.7)
|
42
|
+
multipart-post (~> 1.1)
|
43
|
+
faraday_middleware (0.9.0)
|
44
|
+
faraday (>= 0.7.4, < 0.9)
|
45
|
+
hashie (2.0.5)
|
46
|
+
i18n (0.6.1)
|
47
|
+
json (1.7.7)
|
48
|
+
motion-cocoapods (1.3.2)
|
49
|
+
cocoapods (>= 0.17.0)
|
50
|
+
motion-require (0.0.7)
|
51
|
+
motion-support (0.2.4)
|
52
|
+
motion-require (>= 0.0.6)
|
53
|
+
multi_json (1.7.7)
|
54
|
+
multipart-post (1.2.0)
|
55
|
+
nano-store (0.6.3)
|
56
|
+
motion-cocoapods (>= 1.2.1)
|
57
|
+
netrc (0.7.7)
|
58
|
+
octokit (1.25.0)
|
59
|
+
addressable (~> 2.2)
|
60
|
+
faraday (~> 0.8)
|
61
|
+
faraday_middleware (~> 0.9)
|
62
|
+
hashie (~> 2.0)
|
63
|
+
multi_json (~> 1.3)
|
64
|
+
netrc (~> 0.7.7)
|
65
|
+
open4 (1.3.0)
|
66
|
+
rake (10.0.4)
|
67
|
+
sugarcube (0.20.23)
|
68
|
+
xcodeproj (0.5.5)
|
69
|
+
activesupport (~> 3.2.13)
|
70
|
+
colored (~> 1.2)
|
71
|
+
|
72
|
+
PLATFORMS
|
73
|
+
ruby
|
74
|
+
|
75
|
+
DEPENDENCIES
|
76
|
+
bubble-wrap (= 1.3.0)
|
77
|
+
cocoapods (= 0.19.1)
|
78
|
+
motion-cocoapods (= 1.3.2)
|
79
|
+
motion-prime!
|
80
|
+
motion-support (= 0.2.4)
|
81
|
+
nano-store (= 0.6.3)
|
82
|
+
rake
|
83
|
+
sugarcube (= 0.20.23)
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# MotionPrime
|
2
|
+
|
3
|
+

|
4
|
+
|
5
|
+
MotionPrime is yet another framework written on RubyMotion.
|
6
|
+
|
7
|
+
The main feature of MotionPrime is one more level on UI elements: Section.
|
8
|
+
"Section" is something like "Partial" in Ruby On Rails, but it's smarter and will help you build application UI.
|
9
|
+
|
10
|
+
## Getting Started
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'motion-prime'
|
15
|
+
|
16
|
+
Or create MotionPrime project:
|
17
|
+
|
18
|
+
$ motion create --template=git@github.com:droidlabs/motion-prime.git myapp
|
19
|
+
|
20
|
+
## Hello World (Sample)
|
21
|
+
|
22
|
+
# app/app_delegate.rb
|
23
|
+
class AppDelegate < MotionPrime::BaseAppDelegate
|
24
|
+
def on_load(app, options)
|
25
|
+
open_root_screen MainScreen.new
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# app/screens/main_screen.rb
|
30
|
+
class MainScreen < ApplicationScreen
|
31
|
+
title 'Main screen'
|
32
|
+
|
33
|
+
def render
|
34
|
+
@main_section = MyProfileSection.new(model: User.first)
|
35
|
+
@main_section.render(to: self)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# app/sections/my_profile.rb
|
40
|
+
class MyProfileSection < MotionPrime::BaseSection
|
41
|
+
element :title, text: proc { Hello World }
|
42
|
+
element :avatar, image: "images/avatar.png", type: :image
|
43
|
+
end
|
44
|
+
|
45
|
+
# app/styles/my_profile.rb
|
46
|
+
MotionPrime::Styles.define :my_profile do
|
47
|
+
style :title,
|
48
|
+
width: 300, height: 20, color: :black,
|
49
|
+
top: 10, left: 5, background_color: :white
|
50
|
+
|
51
|
+
style :avatar,
|
52
|
+
width: 90, height: 90, top: 40, left: 5
|
53
|
+
end
|
54
|
+
|
55
|
+
## Contributing
|
56
|
+
|
57
|
+
1. Fork it
|
58
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
59
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
60
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
61
|
+
5. Create new Pull Request
|
62
|
+
|
63
|
+
## Thanks for using MotionPrime!
|
64
|
+
|
65
|
+
Hope, you'll enjoy MotionPrime!
|
66
|
+
|
67
|
+
Cheers, [Droid Labs](http://droidlabs.pro).
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
$:.unshift("/Library/RubyMotion/lib")
|
3
|
+
require 'motion/project/template/ios'
|
4
|
+
require "rubygems"
|
5
|
+
require "bundler"
|
6
|
+
require "bundler/gem_tasks"
|
7
|
+
require 'motion-cocoapods'
|
8
|
+
Bundler.setup
|
9
|
+
Bundler.require
|
10
|
+
require 'motion-support'
|
11
|
+
require 'nano-store'
|
12
|
+
require 'motion-prime'
|
13
|
+
|
14
|
+
Motion::Project::App.setup do |app|
|
15
|
+
app.name = 'MotionPrime'
|
16
|
+
app.pods do
|
17
|
+
pod 'PKRevealController'
|
18
|
+
pod 'NanoStore', '~> 2.6.0'
|
19
|
+
pod 'SDWebImage'
|
20
|
+
pod 'SVPullToRefresh'
|
21
|
+
pod 'MBAlertView'
|
22
|
+
end
|
23
|
+
end
|
data/app/app_delegate.rb
ADDED
data/doc/SECTION.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
== GENERAL
|
2
|
+
|
3
|
+
Section is the most important part of MotionPrime. Section is container for elements (views), grouped for some aim.
|
4
|
+
|
5
|
+
== Section attributes
|
6
|
+
|
7
|
+
* @name - this option is used by part of default styles of any contained element. Check out STYLES doc for more information. default value: section class name without "section word". E.g. LoginFormSection have default name: "login_form"
|
data/doc/STYLE.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
== Default styling names for elements.
|
2
|
+
|
3
|
+
=== Screen
|
4
|
+
* "base_screen"
|
5
|
+
* "%screen class name%", e.g. "login_screen"
|
6
|
+
|
7
|
+
=== Table
|
8
|
+
* "base_table"
|
9
|
+
* "%section_name%", e.g. "tasks_table"
|
10
|
+
|
11
|
+
=== Table cell
|
12
|
+
* "base_table_cell"
|
13
|
+
* "%section_name%_cell", e.g. "tasks_table_cell"
|
14
|
+
* "%cell_section_name%", e.g. "tasks_item"
|
15
|
+
|
16
|
+
=== Form (basically it's table)
|
17
|
+
* "base_form"
|
18
|
+
* "%section_name%", e.g. "login_form"
|
19
|
+
|
20
|
+
=== Form field (basically it's table cell)
|
21
|
+
* "base_form_field"
|
22
|
+
* "%section_name%_field", e.g. "login_form_field"
|
23
|
+
|
24
|
+
=== Form field: label
|
25
|
+
* "base_field_label"
|
26
|
+
* "base_%field_type%_field_label", e.g. "base_string_field_label"
|
27
|
+
* "%section_name%_field_label", e.g. "login_form_field_label"
|
28
|
+
* "%section_name%_%field_name%_field_label", e.g. "login_form_email_field_label"
|
29
|
+
|
30
|
+
=== Form field: input
|
31
|
+
* "base_field_input"
|
32
|
+
* "base_%field_name%_field_label", e.g. "base_string_field_input"
|
33
|
+
* "%section_name%_field_input", e.g. "login_form_field_input"
|
34
|
+
* "%section_name%_%field_name%_field_input", e.g. "login_form_email_field_input"
|
35
|
+
|
36
|
+
=== Form field: button
|
37
|
+
* "base_submit_button"
|
38
|
+
* "%section_name%_submit_button", e.g. "login_form_submit_button"
|
39
|
+
* "%section_name%_%field_name%_button", e.g. "login_form_signup_button"
|
data/files/Gemfile
ADDED
data/files/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
$:.unshift("/Library/RubyMotion/lib")
|
3
|
+
require 'motion/project/template/ios'
|
4
|
+
require "rubygems"
|
5
|
+
require 'bundler'
|
6
|
+
Bundler.require
|
7
|
+
require 'motion-prime'
|
8
|
+
|
9
|
+
Motion::Project::App.setup do |app|
|
10
|
+
# Use `rake config' to see complete project settings.
|
11
|
+
app.name = 'MotionPrimeProject'
|
12
|
+
|
13
|
+
app.pods do
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
data/lib/motion-prime.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'motion-require'
|
2
|
+
|
3
|
+
Motion::Require.all(Dir.glob(File.expand_path('../../motion-prime/**/*.rb', __FILE__)))
|
4
|
+
|
5
|
+
Motion::Project::App.setup do |app|
|
6
|
+
app.pods do
|
7
|
+
pod 'PKRevealController'
|
8
|
+
pod 'NanoStore', '~> 2.6.0'
|
9
|
+
pod 'SDWebImage'
|
10
|
+
pod 'SVPullToRefresh'
|
11
|
+
pod 'MBAlertView'
|
12
|
+
end
|
13
|
+
app.detect_dependencies = false
|
14
|
+
end
|
data/lib/view_styler.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
module MotionPrime
|
2
|
+
class ViewStyler
|
3
|
+
attr_reader :view, :options
|
4
|
+
|
5
|
+
def initialize(view, bounds = CGRectZero, options = {})
|
6
|
+
@options = Styles.extend_and_normalize_options options
|
7
|
+
@view = view
|
8
|
+
calculate_frame_for(bounds) if @options.delete(:calculate_frame)
|
9
|
+
end
|
10
|
+
|
11
|
+
def apply
|
12
|
+
convert_primitives_to_objects(options)
|
13
|
+
setValuesForKeysWithDictionary(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def convert_primitives_to_objects(options)
|
17
|
+
options.each do |k,v|
|
18
|
+
options[k] = STRUCTS_MAP[v.class].call(v) if STRUCTS_MAP.has_key?(v.class)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def calculate_frame_for(bounds)
|
23
|
+
width = options.delete(:width)
|
24
|
+
height = options.delete(:height)
|
25
|
+
top = options.delete(:top)
|
26
|
+
right = options.delete(:right)
|
27
|
+
bottom = options.delete(:bottom)
|
28
|
+
left = options.delete(:left)
|
29
|
+
|
30
|
+
if width.nil? && height.nil? && right.nil? && bottom.nil?
|
31
|
+
options[:frame] = CGRectZero
|
32
|
+
else
|
33
|
+
frame = CGRectZero
|
34
|
+
max_width = bounds.size.width
|
35
|
+
max_height = bounds.size.height
|
36
|
+
width = 0.0 if width.nil?
|
37
|
+
height = 0.0 if height.nil?
|
38
|
+
|
39
|
+
# calculate left and right if width is relative, e.g 0.7
|
40
|
+
if width > 0 && width <= 1
|
41
|
+
if right.nil?
|
42
|
+
left ||= 0
|
43
|
+
right = max_width - max_width * width
|
44
|
+
else
|
45
|
+
left = max_width - max_width * width
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# calculate top and bottom if height is relative, e.g 0.7
|
50
|
+
if height > 0 && height <= 1
|
51
|
+
if bottom.nil?
|
52
|
+
top ||= 0
|
53
|
+
bottom = max_height - max_height * height
|
54
|
+
else
|
55
|
+
top = max_height - max_height * height
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
mask = UIViewAutoresizingNone
|
60
|
+
mask |= UIViewAutoresizingFlexibleTopMargin if top.nil?
|
61
|
+
mask |= UIViewAutoresizingFlexibleLeftMargin if left.nil?
|
62
|
+
mask |= UIViewAutoresizingFlexibleBottomMargin if bottom.nil?
|
63
|
+
mask |= UIViewAutoresizingFlexibleRightMargin if right.nil?
|
64
|
+
mask |= UIViewAutoresizingFlexibleWidth if !left.nil? && !right.nil?
|
65
|
+
mask |= UIViewAutoresizingFlexibleHeight if !top.nil? && !bottom.nil?
|
66
|
+
|
67
|
+
if !left.nil? && !right.nil?
|
68
|
+
frame.origin.x = left
|
69
|
+
frame.size.width = max_width - left - right
|
70
|
+
elsif !right.nil?
|
71
|
+
frame.origin.x = max_width - width - right
|
72
|
+
frame.size.width = width
|
73
|
+
elsif !left.nil?
|
74
|
+
frame.origin.x = left
|
75
|
+
frame.size.width = width
|
76
|
+
else
|
77
|
+
frame.origin.x = max_width / 2 - width / 2
|
78
|
+
frame.size.width = width
|
79
|
+
end
|
80
|
+
|
81
|
+
if !top.nil? && !bottom.nil?
|
82
|
+
frame.origin.y = top
|
83
|
+
frame.size.height = max_height - top - bottom
|
84
|
+
elsif !bottom.nil?
|
85
|
+
frame.origin.y = max_height - height - bottom
|
86
|
+
frame.size.height = height
|
87
|
+
elsif !top.nil?
|
88
|
+
frame.origin.y = top
|
89
|
+
frame.size.height = height
|
90
|
+
else
|
91
|
+
frame.origin.y = max_height / 2 - height / 2
|
92
|
+
frame.size.height = height
|
93
|
+
end
|
94
|
+
|
95
|
+
options[:frame] = frame
|
96
|
+
options[:autoresizingMask] = mask
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def setValue(value, forUndefinedKey: key)
|
101
|
+
return if value.nil?
|
102
|
+
# ignore options
|
103
|
+
return if key == 'size_to_fit' && view.is_a?(UILabel)
|
104
|
+
return if (key == 'url' || key == 'default') && view.is_a?(UIImageView)
|
105
|
+
|
106
|
+
# apply options
|
107
|
+
if key.end_with?('title_color')
|
108
|
+
view.setTitleColor value.uicolor, forState: UIControlStateNormal
|
109
|
+
elsif key.end_with?('title_shadow_color')
|
110
|
+
view.setTitleShadowColor value.uicolor, forState: UIControlStateNormal
|
111
|
+
elsif key.end_with?('color')
|
112
|
+
color = value.uicolor
|
113
|
+
color = color.cgcolor if view.is_a?(CALayer)
|
114
|
+
view.send :"#{key.camelize(:lower)}=", color
|
115
|
+
elsif key.end_with?('background_image')
|
116
|
+
if view.is_a?(UIButton)
|
117
|
+
view.setBackgroundImage value.uiimage, forState: UIControlStateNormal
|
118
|
+
elsif view.is_a?(UISearchBar) && key == 'search_field_background_image'
|
119
|
+
view.setSearchFieldBackgroundImage value.uiimage, forState: UIControlStateNormal
|
120
|
+
else
|
121
|
+
view.setBackgroundColor value.uiimage.uicolor
|
122
|
+
end
|
123
|
+
elsif key.end_with?('image')
|
124
|
+
view.setValue value.uiimage, forKey: key.camelize
|
125
|
+
elsif value.is_a?(Hash)
|
126
|
+
self.class.new(view.send(key.camelize(:lower).to_sym), nil, value).apply
|
127
|
+
else
|
128
|
+
view.setValue value, forKey: key.camelize(:lower)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
STRUCTS_MAP = {
|
133
|
+
CGAffineTransform => Proc.new {|v| NSValue.valueWithCGAffineTransform(v) },
|
134
|
+
CGPoint => Proc.new {|v| NSValue.valueWithCGPoint(v) },
|
135
|
+
CGRect => Proc.new {|v| NSValue.valueWithCGRect(v) },
|
136
|
+
CGSize => Proc.new {|v| NSValue.valueWithCGSize(v) },
|
137
|
+
UIEdgeInsets => Proc.new {|v| NSValue.valueWithUIEdgeInsets(v) },
|
138
|
+
UIOffset => Proc.new {|v| NSValue.valueWithUIOffset(v) }
|
139
|
+
}
|
140
|
+
end
|
141
|
+
end
|