ProMotion 0.0.2 → 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 CHANGED
@@ -18,4 +18,5 @@ tmp
18
18
  .repl_history
19
19
  build
20
20
  build/*
21
- *.000
21
+ *.000
22
+ .rvmrc
data/Gemfile CHANGED
@@ -1,4 +1,6 @@
1
1
  source :rubygems
2
2
 
3
3
  # Specify your gem's dependencies in ProMotion.gemspec
4
+ gem "motion-table", :path => "~/Code/motion-table"
4
5
  gemspec
6
+
data/ProMotion.gemspec CHANGED
@@ -4,10 +4,10 @@ require File.expand_path('../lib/ProMotion/version', __FILE__)
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ["Jamon Holmgren", "Silas Matson", "ClearSight Studio"]
6
6
  gem.email = ["jamon@clearsightstudio.com"]
7
- gem.description = "ProMotion is a new way to organize RubyMotion apps. Currently a proof of concept."
7
+ gem.description = "ProMotion is a new way to organize RubyMotion apps."
8
8
  gem.summary = "
9
9
  ProMotion is a new way to organize RubyMotion apps. Instead of dealing
10
- with UIViewControllers and UIViews, you work with Screens. Screens are
10
+ with UIViewControllers, you work with Screens. Screens are
11
11
  a logical way to think of your app -- similar in some ways to Storyboards.
12
12
  "
13
13
  gem.homepage = "https://github.com/clearsightstudio/ProMotion"
@@ -18,4 +18,5 @@ Gem::Specification.new do |gem|
18
18
  gem.name = "ProMotion"
19
19
  gem.require_paths = ["lib"]
20
20
  gem.version = ProMotion::VERSION
21
+ # gem.add_dependency("motion-table", "~> 0.1.6")
21
22
  end
data/README.md CHANGED
@@ -1,10 +1,7 @@
1
- # ProMotion
1
+ # ProMotion - A new way to organize RubyMotion apps.
2
2
 
3
- **Please note: this is a proof of concept and does not yet work.**
4
-
5
- ProMotion is a new way to organize RubyMotion apps. Instead of dealing
6
- with UIViewControllers and UIViews, you work with Screens. Screens are
7
- a logical way to think of your app.
3
+ ProMotion introduces a new object called "Screens". Screens have a one-to-one relationship
4
+ with your app's screens and can (usually) take the place of view controllers.
8
5
 
9
6
  Typical /app file structure:
10
7
 
@@ -17,273 +14,159 @@ Typical /app file structure:
17
14
  home_screen.rb
18
15
  settings_screen.rb
19
16
  models
17
+ view_controllers
20
18
  views
21
19
  app_delegate.rb
22
20
 
23
- The "views" folder contains custom view components, written in normal RubyMotion. "models" can be whatever ORM you're using.
24
-
25
- ### What about MVC?
26
-
27
- I'm a big believer in MVC (I'm a Rails developer, too). I found that most of the time working in RubyMotion seems to happen
28
- in the ViewControllers. This pattern may be best for simpler, smaller apps.
29
-
30
- This is a proof of concept. I'd really appreciate feedback on it at my email address (jamon@clearsightstudio.com) or Twitter (@jamonholmgren).
31
-
32
- ## Installation
33
-
34
- Add this line to your application's Gemfile:
35
-
36
- gem 'ProMotion'
37
-
38
- And then execute:
39
-
40
- $ bundle
41
-
42
- Or install it yourself as:
43
-
44
- $ gem install ProMotion
45
-
46
21
  ## Usage
47
22
 
48
- It's easy to load your first screen with a navigation bar (the screen is opened in a UINavigationController behind the scenes):
23
+ Loading your home screen:
49
24
 
50
25
  ```ruby
51
- # In /app/app_delegate.rb (note that AppDelegate extends ProMotion::AppDelegate)
52
- class AppDelegate < ProMotion::AppDelegate
53
- def application(application, didFinishLaunchingWithOptions:launchOptions)
54
- open_with_nav_bar HomeScreen
55
-
56
- true
26
+ # In /app/app_delegate.rb (note that AppDelegate extends ProMotion::AppDelegateParent)
27
+ class AppDelegate < ProMotion::AppDelegateParent
28
+ def on_load(options)
29
+ open_screen MyHomeScreen.new(nav_bar: true)
57
30
  end
58
31
  end
59
32
  ```
60
33
 
61
- Screens are pretty straightforward. You extend ProMotion::Screen and provide a title and an on_load method.
34
+ Creating a basic screen:
62
35
 
63
36
  ```ruby
64
- # In /app/screens/home_screen.rb:
65
37
  class HomeScreen < ProMotion::Screen
66
- # Set the title for use in nav bars and other containers
67
38
  title "Home"
68
39
 
69
- # Called when this screen is first "opened" and allows you to set up your view components
70
40
  def on_load
71
- @default_image = add_image(:default_image, src: "default.png", frame: [10, 50, 100, 100])
41
+ # Set up the elements in your view with add_element:
42
+ @label = add_element UILabel.alloc.initWithFrame(CGRectMake(5, 5, 20, 20)), {
43
+ text: "This is awesome!",
44
+ font: UIFont.UIFont.systemFontOfSize(18)
45
+ }
46
+ end
47
+
48
+ def on_appear
49
+ # Refresh the data if you want
72
50
  end
73
51
  end
74
52
  ```
75
53
 
76
- In on_load, you can add images, buttons, labels, custom views to your screen.
54
+ Creating a tabbed bar:
77
55
 
78
56
  ```ruby
79
- # In /app/screens/home_screen.rb:
80
- class HomeScreen < ProMotion::Screen
81
- # Set the title for use in nav bars and other containers
82
- title "Home"
83
-
84
- def on_load
85
- # Add view items as instance vars so you can access them in other methods
86
-
87
- # This adds a right nav bar button. on_tap allows you to set a method to call when it's tapped.
88
- @right_bar_button = add_right_nav_button(label: "Save", on_tap: :save)
89
-
90
- # Helper function for adding a button
91
- @settings_button = add_button(label: "Settings", frame: [10, 10, 100, 30])
92
-
93
- # Helper function for adding an image
94
- @default_image = add_image(:default_image, src: "default.png", frame: [10, 50, 100, 100])
95
-
96
- # You can also add custom UIViews through the add_view method.
97
- @custom_view = add_view(ChatView.alloc.initWithFrame(CGRectMake(10, 300, 40, 40)))
98
- end
57
+ def on_load(options)
58
+ @home = MyHomeScreen.new(nav_bar: true)
59
+ @settings = SettingsScreen.new
60
+ @contact = ContactScreen.new(nav_bar: true)
61
+ open_tab_bar @home, @settings, @contact
99
62
  end
100
63
  ```
101
64
 
102
- View components can be bound to events (like jQuery) and run methods or run a block.
65
+ Any view item (UIView, UIButton, etc) can be used with add_element.
66
+ The second argument is a hash of settings that get applied to the
67
+ element before it is dropped into the view.
103
68
 
104
69
  ```ruby
105
- # settings_pushed is executed when the button is tapped
106
- @settings_button = add_button(label: "Settings", frame: [10, 10, 100, 30])
107
- @settings_button.on(:tap, :settings_pushed)
70
+ @label = add_element UILabel.alloc.initWithFrame(CGRectMake(5, 5, 20, 20)), {
71
+ text: "This is awesome!",
72
+ font: UIFont.UIFont.systemFontOfSize(18)
73
+ }
74
+ ```
108
75
 
109
- # This demonstrates a block
110
- @settings_button.on(:tap) do
111
- # Do something
112
- end
76
+ Add a nav_bar button and a tab_bar icon:
113
77
 
114
- # This button passes in arguments to the method when it's tapped
115
- @edit_button = add_button(label: "Edit", frame: [10, 10, 100, 30])
116
- @edit_button.on(:tap, :edit_pushed, id: 4)
78
+ ```ruby
79
+ add_right_nav_button(label: "Save", action: :save)
80
+ set_tab_bar_item(title: "Contacts", system_icon: UITabBarSystemItemContacts)
117
81
  ```
118
82
 
119
- To open other screens, just call the built-in "open" method on a new instance or class:
83
+ Open a new screen:
120
84
 
121
85
  ```ruby
122
86
  def settings_button_tapped
123
87
  # ...with a class...
124
- open SettingsScreen
88
+ open_screen SettingsScreen
125
89
 
126
90
  # ...or with an instance...
127
- @settings_screen = SettingsScreen.new(some_attr: 4)
128
- open @settings_screen
129
-
130
- # ...or if you like...
131
- open SettingsScreen.new
91
+ @settings_screen = SettingsScreen.new
92
+ open_screen @settings_screen
132
93
  end
133
94
  ```
134
95
 
135
- You can pass in arguments to those screens if they have accessors:
96
+ You can pass in arguments to other screens if they have accessors:
136
97
 
137
98
  ```ruby
138
- # /app/screens/settings_screen.rb
139
- class SettingsScreen < ProMotion::Screen
140
- attr_accessor :user_type
141
-
142
- def on_load
143
- if self.user_type == "Admin"
144
- # Stuff
145
- end
146
- end
147
-
148
- # ...
149
- end
150
-
151
- # /app/screens/home_screen.rb
152
99
  class HomeScreen < ProMotion::Screen
153
100
  # ...
154
101
 
155
102
  def settings_button_tapped
156
- open SettingsScreen.new(user_type: "Admin")
103
+ open_screen ProfileScreen.new(user: some_user)
157
104
  end
158
105
  end
159
- ```
160
106
 
161
- When you're done with a screen, just close it:
107
+ class ProfileScreen < ProMotion::Screen
108
+ attr_accessor :user
162
109
 
163
- ```ruby
164
- def save_and_close
165
- if @model.save
166
- close
110
+ def on_load
111
+ self.user # => some_user instance
167
112
  end
168
113
  end
114
+
169
115
  ```
170
116
 
171
- If you want to pass arguments back to the previous screen, go for it.
117
+ Close a screen, passing back arguments to the previous screen's "on_return" method:
172
118
 
173
119
  ```ruby
174
- class SettingsScreen < ProMotion::Screen
120
+ class ItemScreen
175
121
  # ...
176
-
177
122
  def save_and_close
178
- close(saved_changes: true)
123
+ if @model.save
124
+ close_screen(model_saved: true)
125
+ end
179
126
  end
180
127
  end
181
128
 
182
129
  class MainScreen < ProMotion::Screen
183
130
  # ...
184
-
185
131
  def on_return(args = {})
186
- if args[:saved_changes]
132
+ if args[:model_saved]
187
133
  self.reload_something
188
134
  end
189
135
  end
190
136
  end
191
137
  ```
192
138
 
193
- You can create sectioned table screens easily.
139
+ Use a custom view controller:
194
140
 
195
141
  ```ruby
196
- class HomeScreen < ProMotion::Screen
197
- title "Home"
198
-
199
- # Defaults to :normal. :plain_table, :grouped_table are options.
200
- screen_type :grouped_table
201
-
202
- def on_load
203
- # No need to set anything up, really
204
- end
205
-
206
- # If you define your screen_type as some sort of table, this gets called to get the data.
207
- # You can also refresh the table data manually by calling `self.reload_table_data`
208
- def table_data
209
- # You can create a new table section here and add cells to it like so:
210
- @account_section = add_section(label: "Your Account")
211
- @account_section.add_cell(title: "Edit Profile", action: :edit_profile, arguments: { account_id: @account.id })
212
- @account_section.add_cell(title: "Log Out", action: :log_out)
213
-
214
- # Or just pass back an array with everything defined and we'll build it for you:
215
- [{
216
- title: "Your Account",
217
- cells: [
218
- { title: "Edit Profile", action: :edit_profile },
219
- { title: "Log Out", action: :log_out },
220
- { title: "Notification Settings", action: :notification_settings }
221
- ]
222
- }, {
223
- title: "App Stuff",
224
- cells: [
225
- { title: "About", action: :show_about },
226
- { title: "Feedback", action: :show_feedback }
227
- ]
228
- }]
229
- end
142
+ def on_load
143
+ set_view_controller MyCustomViewController
144
+
145
+ # Note: on_appear will not fire when using a custom
146
+ # view controller.
230
147
  end
231
148
  ```
232
149
 
233
- Here's a full demo of a screen:
150
+ The helper add_element takes a
234
151
 
235
- ```ruby
236
- # In /app/screens/home_screen.rb:
152
+ You can create sectioned table screens easily. TableScreen, SectionedTableScreen, GroupedTableScreen
237
153
 
238
- class HomeScreen < ProMotion::Screen
239
- # Accessors allow screens to set parameters when opening this screen
240
- attr_accessor :foo
241
-
242
- # Set the title for use in nav bars and other containers
243
- title "Home"
244
-
245
- # Defaults to :normal. :plain_table, :grouped_table are options.
246
- screen_type :plain_table
154
+ ```ruby
155
+ class SettingsScreen < ProMotion::GroupedTableScreen
156
+ title "Settings"
247
157
 
248
- # Called when this screen is first "opened" and allows you to set up your view components
249
158
  def on_load
250
- # Add view items as instance vars so you can access them in other methods
251
- # This adds a right nav bar button. on_tap allows you to set a method to call when it's tapped.
252
- @right_bar_button = add_right_nav_button(label: "Save", on_tap: :save)
253
-
254
- # Helper function for adding a button
255
- @settings_button = add_button(label: "Settings", frame: [10, 10, 100, 30])
256
-
257
- # View items can be bound to events (like jQuery) and run methods or run a block.
258
- @settings_button.on(:tap, :settings_pushed)
259
- @settings_button.on(:tapHold) do
260
- # Do something
261
- end
262
-
263
- # Helper function for adding an image
264
- @default_image = add_image(:default_image, src: "default.png", frame: [10, 50, 100, 100])
265
-
266
- # This button passes in arguments to the method when it's tapped
267
- @edit_button = add_button(label: "Edit", frame: [10, 10, 100, 30])
268
- @edit_button.on(:tap, :edit_pushed, id: 4)
269
-
270
- # You can also add custom UIViews through the add_view method.
271
- @custom_view = add_view(ChatView.alloc.initWithFrame(CGRectMake(10, 300, 40, 40)))
159
+ add_right_nav_button(label: "Save", action: :save)
160
+ set_tab_bar_item(title: "Settings", icon: "settings.png")
272
161
  end
273
-
274
- # If you define your screen_type as some sort of table, this gets called to get the data.
275
- # You can also refresh the table data manually by calling `self.reload_table_data`
162
+
163
+ # table_data is automatically called. Use this format in the return value.
164
+ # Grouped tables are the same as plain tables
276
165
  def table_data
277
- # You can create a new table section here and add cells to it like so:
278
- @account_section = add_section(label: "Your Account")
279
- @account_section.add_cell(title: "Edit Profile", action: :edit_profile, arguments: { account_id: @account.id })
280
- @account_section.add_cell(title: "Log Out", action: :log_out)
281
-
282
- # Or just pass back an array with everything defined and we'll build it for you:
283
166
  [{
284
167
  title: "Your Account",
285
168
  cells: [
286
- { title: "Edit Profile", action: :edit_profile },
169
+ { title: "Edit Profile", action: :edit_profile, arguments: { id: 3 } },
287
170
  { title: "Log Out", action: :log_out },
288
171
  { title: "Notification Settings", action: :notification_settings }
289
172
  ]
@@ -296,52 +179,25 @@ class HomeScreen < ProMotion::Screen
296
179
  }]
297
180
  end
298
181
 
299
- # Custom method, invoked when tapping something with this as the action
300
- def save
301
- # Assuming some sort of ORM, like ParseModel
302
- @my_model.save
303
-
304
- # When you want to close the current screen (usually in a navigation controller), just run this.
305
- close
306
-
307
- # You can also pass back arguments to the previous screen as you close.
308
- # If the previous screen has an `on_return` method, this will be passed into that method
309
- close(did_stuff: true)
182
+ # This method allows you to create a "jumplist", the index on the right side of the table
183
+ def table_data_index
184
+ return ["A", "B", "C"]
310
185
  end
311
-
312
- # This is called any time a screen "above" this screen is closed. args = {} is required.
313
- def on_return(args = {})
314
- if args[:did_stuff]
315
- # Refresh?
316
- end
317
- end
318
-
319
- # Custom method
320
- def settings_pushed
321
- # Just open a settings screen
322
- open SettingsScreen
323
-
324
- # If you prefer to pass in an instance, that works too:
325
- open SettingsScreen.new
326
- end
327
-
328
- def close_pushed
329
- close
330
- end
331
-
332
- # Custom method with passed in arguments
333
- def edit_pushed(args)
334
- # Open a screen and set some of its attributes
335
- open EditScreen.new(id: args[:id])
186
+
187
+ # Your table cells, when tapped, will execute the corresponding actions and pass in arguments:
188
+ def edit_profile(arguments)
189
+ # ...
336
190
  end
337
191
  end
338
192
  ```
339
193
 
194
+ ### What about MVC?
195
+
196
+ I'm a big believer in MVC (I'm a Rails developer, too). I found that most of the time working in RubyMotion seems to happen
197
+ in the ViewControllers and views are mainly custom elements. This pattern may be best for simpler, smaller apps.
198
+
199
+ Feedback welcome via twitter @jamonholmgren.
340
200
 
341
201
  ## Contributing
342
202
 
343
- 1. Fork it
344
- 2. Create your feature branch (`git checkout -b my-new-feature`)
345
- 3. Commit your changes (`git commit -am 'Added some feature'`)
346
- 4. Push to the branch (`git push origin my-new-feature`)
347
- 5. Create new Pull Request
203
+ I'm really looking for feedback. Tweet me with your ideas or open a ticket (I don't mind!) and let's discuss.