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.
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