motion-prime 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +13 -0
  3. data/Gemfile.lock +83 -0
  4. data/README.md +67 -0
  5. data/Rakefile +23 -0
  6. data/app/app_delegate.rb +5 -0
  7. data/doc/SECTION.md +7 -0
  8. data/doc/STYLE.md +39 -0
  9. data/files/Gemfile +3 -0
  10. data/files/Rakefile +16 -0
  11. data/files/app/app_delegate.rb +4 -0
  12. data/files/app/screens/application_screen.rb +3 -0
  13. data/lib/motion-prime.rb +14 -0
  14. data/lib/view_styler.rb +141 -0
  15. data/motion-prime.gemspec +27 -0
  16. data/motion-prime/app_delegate.rb +56 -0
  17. data/motion-prime/elements/base.rb +94 -0
  18. data/motion-prime/elements/button.rb +7 -0
  19. data/motion-prime/elements/draw.rb +56 -0
  20. data/motion-prime/elements/draw/image.rb +43 -0
  21. data/motion-prime/elements/draw/label.rb +13 -0
  22. data/motion-prime/elements/image.rb +14 -0
  23. data/motion-prime/elements/label.rb +20 -0
  24. data/motion-prime/elements/text_field.rb +7 -0
  25. data/motion-prime/elements/text_view.rb +7 -0
  26. data/motion-prime/helpers/has_authorization.rb +10 -0
  27. data/motion-prime/helpers/has_search_bar.rb +25 -0
  28. data/motion-prime/models/base.rb +220 -0
  29. data/motion-prime/screens/_aliases_mixin.rb +32 -0
  30. data/motion-prime/screens/_base_mixin.rb +119 -0
  31. data/motion-prime/screens/_navigation_bar_mixin.rb +57 -0
  32. data/motion-prime/screens/_navigation_mixin.rb +118 -0
  33. data/motion-prime/screens/_orientations_mixin.rb +39 -0
  34. data/motion-prime/screens/base_screen.rb +22 -0
  35. data/motion-prime/screens/sidebar_container_screen.rb +58 -0
  36. data/motion-prime/sections/base.rb +101 -0
  37. data/motion-prime/sections/draw.rb +62 -0
  38. data/motion-prime/sections/form.rb +103 -0
  39. data/motion-prime/sections/form/base_field_section.rb +26 -0
  40. data/motion-prime/sections/form/password_field_section.rb +33 -0
  41. data/motion-prime/sections/form/select_field_section.rb +40 -0
  42. data/motion-prime/sections/form/string_field_section.rb +32 -0
  43. data/motion-prime/sections/form/submit_field_section.rb +20 -0
  44. data/motion-prime/sections/form/text_field_section.rb +33 -0
  45. data/motion-prime/sections/table.rb +97 -0
  46. data/motion-prime/sections/table/refresh_mixin.rb +13 -0
  47. data/motion-prime/styles/forms.rb +93 -0
  48. data/motion-prime/support/_key_value_store.rb +10 -0
  49. data/motion-prime/support/dm_button.rb +22 -0
  50. data/motion-prime/support/dm_cell_with_section.rb +12 -0
  51. data/motion-prime/support/dm_text_field.rb +30 -0
  52. data/motion-prime/support/dm_text_view.rb +93 -0
  53. data/motion-prime/support/dm_view_controller.rb +50 -0
  54. data/motion-prime/support/dm_view_with_section.rb +11 -0
  55. data/motion-prime/support/navigation_controller.rb +4 -0
  56. data/motion-prime/support/ui_search_bar_custom.rb +10 -0
  57. data/motion-prime/support/ui_view.rb +59 -0
  58. data/motion-prime/version.rb +3 -0
  59. data/motion-prime/views/layout.rb +45 -0
  60. data/motion-prime/views/styles.rb +44 -0
  61. data/motion-prime/views/view_builder.rb +80 -0
  62. data/motion-prime/views/view_styler.rb +141 -0
  63. data/resources/Default-568h@2x.png +0 -0
  64. data/spec/main_spec.rb +9 -0
  65. metadata +245 -0
@@ -0,0 +1,97 @@
1
+ motion_require './table/refresh_mixin'
2
+ module MotionPrime
3
+ class TableSection < BaseSection
4
+ include TableSectionRefreshMixin
5
+ include HasSearchBar
6
+
7
+ attr_accessor :table_view
8
+ before_render :render_table
9
+
10
+ def table_data
11
+ []
12
+ end
13
+
14
+ def data
15
+ @data ||= begin
16
+ table_data
17
+ end
18
+ end
19
+
20
+ def reload_data
21
+ @data = nil
22
+ @data_stamp = Time.now.to_i
23
+ table_view.reloadData
24
+ end
25
+
26
+ def render_table
27
+ @data_stamp = Time.now.to_i
28
+ self.table_view = screen.table_view(styles: [:base_table, name.to_sym], delegate: self, data_source: self).view
29
+ end
30
+
31
+ def render_cell(index, table)
32
+ cell = cached_cell(index)
33
+ return cell if cell
34
+ item = data[index.row]
35
+
36
+ # define default styles for cell
37
+ styles = [:"#{name}_cell"]
38
+ if item.respond_to?(:container_styles) && item.container_styles.present?
39
+ styles += Array.wrap(item.container_styles)
40
+ end
41
+ if item.respond_to?(:name) && item.name.present?
42
+ styles += [item.name.to_sym]
43
+ end
44
+
45
+ # DrawSection allows as to draw inside the cell view, so we can setup
46
+ # to use cell view as container
47
+ if item.is_a?(MotionPrime::DrawSection)
48
+ item.render(to: screen, as: :cell,
49
+ styles: [:base_table_cell] + styles,
50
+ reuse_identifier: cell_name(table, index)
51
+ )
52
+ else
53
+ screen.table_view_cell styles: [:base_table_cell] + styles, reuse_identifier: cell_name(table, index) do
54
+ item.render(to: screen)
55
+ end
56
+ end
57
+ end
58
+
59
+ def on_click(table, index)
60
+ end
61
+
62
+ def cell_name(table, index)
63
+ record = data[index.row]
64
+ if record && record.model &&
65
+ record.model.respond_to?(:id) && record.model.id.present?
66
+ "cell_#{record.model.id}_#{@data_stamp}"
67
+ else
68
+ "cell_#{index.section}_#{index.row}_#{@data_stamp}"
69
+ end
70
+ end
71
+
72
+ def cached_cell(index, table = nil)
73
+ table ||= self.table_view
74
+ table.dequeueReusableCellWithIdentifier(cell_name(table, index))
75
+ end
76
+
77
+ # ALIASES
78
+ # ---------------------
79
+
80
+ def tableView(table, cellForRowAtIndexPath:index)
81
+ cell = cached_cell(index, table) || render_cell(index, table)
82
+ cell.is_a?(UIView) ? cell : cell.view
83
+ end
84
+
85
+ def tableView(table, numberOfRowsInSection:section)
86
+ data.length
87
+ end
88
+
89
+ def tableView(table, didSelectRowAtIndexPath:index)
90
+ on_click(table, index)
91
+ end
92
+
93
+ def tableView(table, heightForRowAtIndexPath:index)
94
+ data[index.row].container_height
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,13 @@
1
+ module MotionPrime
2
+ module TableSectionRefreshMixin
3
+ def add_pull_to_refresh(&block)
4
+ table_view.addPullToRefreshWithActionHandler(block)
5
+ screen.setup table_view.pullToRefreshView, styles: [:base_pull_to_refresh]
6
+ end
7
+
8
+ def fisnish_pull_to_refresh
9
+ reload_data
10
+ table_view.pullToRefreshView.stopAnimating
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,93 @@
1
+ motion_require '../views/styles.rb'
2
+ MotionPrime::Styles.define :base do
3
+ # basic table styles
4
+ # ----------
5
+ style :table,
6
+ top: 0,
7
+ left: 0,
8
+ width: 320,
9
+ bottom: 0
10
+
11
+ # basic form styles
12
+ # ----------
13
+ style :form,
14
+ width: 260,
15
+ left: 30,
16
+ top: 0,
17
+ right: 30,
18
+ bottom: 0,
19
+ background_color: :clear,
20
+ separator_color: :clear,
21
+ scroll_enabled: true
22
+
23
+ style :form_field,
24
+ selection_style: UITableViewCellSelectionStyleNone
25
+
26
+ # available options for string label:
27
+ # @background_color: COLOR
28
+ # @text_color: COLOR
29
+ style :field_label,
30
+ background_color: :clear,
31
+ text_color: :gray,
32
+ top: 6,
33
+ height: 20,
34
+ left: 0,
35
+ right: 0,
36
+ font: proc { APP_CONFIG[:css_font_base].uifont(12) },
37
+ size_to_fit: true
38
+
39
+ # available options for input:
40
+ # @layer: @border_width: FLOAT
41
+ # @layer: @border_color: COLOR
42
+ # @background_color: COLOR
43
+ # @background_image: PATH_TO_FILE
44
+ style :field_input,
45
+ layer: {
46
+ border_width: 1,
47
+ border_color: :gray
48
+ },
49
+ font: proc { APP_CONFIG[:css_font_base].uifont(16) },
50
+ placeholder_font: proc { APP_CONFIG[:css_font_base].uifont(16) },
51
+ background_color: :white,
52
+ left: 0,
53
+ right: 0,
54
+ top: 30,
55
+ bottom: 0,
56
+ padding_top: 4
57
+
58
+ # available options for submit button:
59
+ # @button_type: :rounded, :custom
60
+ # @background_color: COLOR
61
+ # @background_image: PATH_TO_FILE
62
+ style :submit_button,
63
+ background_color: :gray,
64
+ left: 0,
65
+ right: 0,
66
+ top: 10,
67
+ height: 44,
68
+ title_color: :white
69
+
70
+ style :select_field_button,
71
+ background_color: :white,
72
+ left: 0,
73
+ right: 0,
74
+ top: 30,
75
+ height: 36,
76
+ title_color: 0x16759a,
77
+ title_shadow_color: :white,
78
+ contentHorizontalAlignment: UIControlContentHorizontalAlignmentLeft,
79
+ layer: {
80
+ border_color: :gray,
81
+ border_width: 1
82
+ },
83
+ title_color: :gray,
84
+ title_label: {
85
+ font: proc { APP_CONFIG[:css_font_base].uifont(16) }
86
+ }
87
+ style :select_field_arrow,
88
+ image: "images/forms/select_arrow.png",
89
+ top: 42,
90
+ right: 5,
91
+ width: 9,
92
+ height: 14
93
+ end
@@ -0,0 +1,10 @@
1
+ module MotionPrime
2
+ module KeyValueStore
3
+ extend ::MotionSupport::Concern
4
+
5
+ # Key-Value accessors
6
+ def setValue(value, forUndefinedKey: key)
7
+ self.send(:"#{key}=", key)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,22 @@
1
+ class DMButton < UIButton
2
+ include MotionPrime::KeyValueStore
3
+ attr_accessor :paddingLeft, :paddingTop, :padding
4
+
5
+ def setTitle(value)
6
+ setTitle value, forState: UIControlStateNormal
7
+ end
8
+
9
+ def drawPadding(rect)
10
+ padding_left = self.paddingLeft || self.padding || 5
11
+ padding_top = self.paddingTop || self.padding || 0
12
+ self.setTitleEdgeInsets UIEdgeInsetsMake(
13
+ padding_top, padding_left,
14
+ padding_top, padding_left
15
+ )
16
+ end
17
+
18
+ def drawRect(rect)
19
+ drawPadding(rect)
20
+ super
21
+ end
22
+ end
@@ -0,0 +1,12 @@
1
+ class DMCellWithSection < UITableViewCell
2
+ attr_accessor :section
3
+
4
+ def setSection(section)
5
+ @section = WeakRef.new(section)
6
+ end
7
+
8
+ def drawRect(rect)
9
+ super
10
+ section.draw_in(rect)
11
+ end
12
+ end
@@ -0,0 +1,30 @@
1
+ # This class have some modifications for UITextField:
2
+ # * support padding, padding_left, padding_right options
3
+ # * support placeholder_color, placeholder_font options
4
+ class DMTextField < UITextField
5
+ include MotionPrime::KeyValueStore
6
+
7
+ attr_accessor :paddingLeft, :paddingTop, :padding,
8
+ :placeholderColor, :placeholderFont
9
+
10
+ # placeholder position
11
+ def textRectForBounds(bounds)
12
+ padding_left = self.paddingLeft || self.padding || 5
13
+ padding_top = self.paddingTop || self.padding || 3
14
+ CGRectInset(bounds, padding_left, padding_top)
15
+ end
16
+
17
+ # text position
18
+ def editingRectForBounds(bounds)
19
+ padding_left = self.paddingLeft || self.padding || 5
20
+ padding_top = self.paddingTop || self.padding || 3
21
+ CGRectInset(bounds, padding_left, padding_top)
22
+ end
23
+
24
+ def drawPlaceholderInRect(rect)
25
+ color = self.placeholderColor || :gray.uicolor
26
+ color.setFill
27
+ font = self.placeholderFont || self.font || :system.uifont(16)
28
+ self.placeholder.drawInRect(rect, withFont: font)
29
+ end
30
+ end
@@ -0,0 +1,93 @@
1
+ # This class have some modifications for UITextView:
2
+ # * support padding, padding_left, padding_right options
3
+ # * support placeholder, placeholder_color, placeholder_font options
4
+ class DMTextView < UITextView
5
+ include MotionPrime::KeyValueStore
6
+ DEFAULT_PADDING_LEFT = 7
7
+
8
+ attr_accessor :paddingLeft, :paddingTop, :padding,
9
+ :placeholderColor, :placeholderFont, :placeholder
10
+
11
+ def drawPadding(rect)
12
+ # add padding to UITextView
13
+ padding_left = 0 - DEFAULT_PADDING_LEFT + (self.paddingLeft || self.padding || 5)
14
+ padding_top = 0 - DEFAULT_PADDING_LEFT + (self.paddingTop || self.padding || 5)
15
+ padding = UIEdgeInsetsMake(
16
+ padding_top, padding_left,
17
+ padding_top, padding_left
18
+ )
19
+ self.contentInset = padding
20
+
21
+ # must change frame before bounds because the text wrap is reformatted based on frame,
22
+ # don't include the top and bottom insets
23
+ insetFrame = UIEdgeInsetsInsetRect(frame, UIEdgeInsetsMake(0, padding.left, 0, padding.right))
24
+ # offset frame back to original x
25
+ offsetX = frame.origin.x - (insetFrame.origin.x - ( padding.left + padding.right ) / 2)
26
+ insetFrame = CGRectApplyAffineTransform(insetFrame, CGAffineTransformMakeTranslation(offsetX, 0))
27
+ self.frame = insetFrame
28
+ self.bounds = UIEdgeInsetsInsetRect(self.bounds, UIEdgeInsetsMake(0, -padding.left, 0, -padding.right))
29
+ end
30
+
31
+ def drawPlaceholder(rect)
32
+ padding_left = self.paddingLeft || self.padding || 5
33
+ padding_top = self.paddingTop || self.padding || 5
34
+ padding = UIEdgeInsetsMake(
35
+ padding_top, padding_left,
36
+ padding_top, padding_left
37
+ )
38
+ if self.placeholder && self.text.blank?
39
+ color = self.placeholderColor || :gray.uicolor
40
+ color.setFill
41
+ font = self.placeholderFont || self.font || :system.uifont(16)
42
+
43
+ color.setFill
44
+ rect = CGRectMake(
45
+ rect.origin.x + padding_left,
46
+ rect.origin.y + padding_top,
47
+ self.frame.size.width - padding_left,
48
+ self.frame.size.height - padding_top
49
+ )
50
+ placeholder.drawInRect(rect, withFont: font)
51
+ end
52
+ end
53
+
54
+ def drawRect(rect)
55
+ drawPadding(rect)
56
+ drawPlaceholder(rect)
57
+ super
58
+ end
59
+
60
+ def initPlaceholder
61
+ NSNotificationCenter.defaultCenter.addObserver(self,
62
+ selector: :textChanged, name: UITextViewTextDidChangeNotification, object: self
63
+ )
64
+ @shouldDrawPlaceholder = placeholder && self.text.blank?
65
+ end
66
+
67
+ def textChanged
68
+ updatePlaceholderDraw
69
+ end
70
+
71
+ def updatePlaceholderDraw
72
+ prev = @shouldDrawPlaceholder
73
+ @shouldDrawPlaceholder = placeholder && self.text.blank?
74
+ if prev != @shouldDrawPlaceholder
75
+ self.setNeedsDisplay
76
+ end
77
+ end
78
+
79
+ # custom initializer
80
+ def initWithCoder(aDecoder)
81
+ if super
82
+ initPlaceholder
83
+ end
84
+ self
85
+ end
86
+
87
+ def initWithFrame(frame)
88
+ if super
89
+ initPlaceholder
90
+ end
91
+ self
92
+ end
93
+ end
@@ -0,0 +1,50 @@
1
+ class DMViewController < UIViewController
2
+ def self.new(args = {})
3
+ s = self.alloc.initWithNibName(nil, bundle:nil)
4
+ s.on_create(args) if s.respond_to?(:on_create)
5
+ s
6
+ end
7
+
8
+ def viewDidLoad
9
+ super
10
+ self.view_did_load if self.respond_to?(:view_did_load)
11
+ end
12
+
13
+ def viewWillAppear(animated)
14
+ super
15
+ self.view_will_appear(animated) if self.respond_to?("view_will_appear:")
16
+ end
17
+
18
+ def viewDidAppear(animated)
19
+ super
20
+ self.view_did_appear(animated) if self.respond_to?("view_did_appear:")
21
+ end
22
+
23
+ def viewWillDisappear(animated)
24
+ self.view_will_disappear(animated) if self.respond_to?("view_will_disappear:")
25
+ super
26
+ end
27
+
28
+ def viewDidDisappear(animated)
29
+ if self.respond_to?("view_did_disappear:")
30
+ self.view_did_disappear(animated)
31
+ end
32
+ super
33
+ end
34
+
35
+ def shouldAutorotateToInterfaceOrientation(orientation)
36
+ self.should_rotate(orientation)
37
+ end
38
+
39
+ def shouldAutorotate
40
+ self.should_autorotate
41
+ end
42
+
43
+ def willRotateToInterfaceOrientation(orientation, duration:duration)
44
+ self.will_rotate(orientation, duration)
45
+ end
46
+
47
+ def didRotateFromInterfaceOrientation(orientation)
48
+ self.on_rotate
49
+ end
50
+ end
@@ -0,0 +1,11 @@
1
+ class DMViewWithSection < UIView
2
+ attr_accessor :section
3
+
4
+ def setSection(section)
5
+ @section = WeakRef.new(section)
6
+ end
7
+
8
+ def drawRect(rect)
9
+ section.draw_in(rect)
10
+ end
11
+ end