Git Product home page Git Product logo

promotion's Introduction

ProMotion

Gem Version

ProMotion was created by me, Jamon Holmgren. While you're welcome to use ProMotion, please note that it's no longer maintained!

(And yes -- I created it long before Apple launched their own ProMotion.)

iPhone Apps, Ruby-style

ProMotion is a RubyMotion gem that makes iOS development more like Ruby and less like Objective-C. It introduces a clean, Ruby-style syntax for building screens that is easy to learn and remember and abstracts a ton of boilerplate UIViewController, UINavigationController, and other iOS code into a simple, Ruby-like DSL.

# app/app_delegate.rb
class AppDelegate < PM::Delegate
  status_bar true, animation: :fade

  def on_load(app, options)
    open RootScreen
  end
end

# app/screens/root_screen.rb
class RootScreen < PM::Screen
  title "Root Screen"
  nav_bar true

  def on_load
    set_nav_bar_button :right, title: "Help", action: :open_help_screen
  end

  def open_help_screen
    open HelpScreen
  end
end

# app/screens/help_screen.rb
class HelpScreen < PM::TableScreen
  title "Table Screen"

  def table_data
    [{
      title: "Help",
      cells: [
        { title: "About this app", action: :tapped_about },
        { title: "Log out", action: :log_out }
      ]
    }]
  end

  def tapped_about(args={})
    open AboutScreen
  end

  def log_out
    # Log out!
  end
end

Features

Screens Navigation Bars Tab Bars
ProMotion Screen ProMotion Nav Bar ProMotion Tabs
Table Screens Grouped Tables Searchable Refreshable
ProMotion TableScreen Grouped Table Screen Searchable Refreshable
SplitScreens Map Screens Web Screens
ProMotion SplitScreens MapScreen ProMotion WebScreen

...and much more.

Getting Started

  1. Check out the Getting Started Guide
  2. Watch the excellent MotionInMotion screencast about ProMotion (very reasonably priced subscription required)
  3. Follow a tutorial: Building an ESPN app using RubyMotion, ProMotion, and TDD
  4. Read the Documentation

Changelog

See Releases page

Apps built on ProMotion

Apps built on ProMotion

Your app

Open a pull request! We love adding new ProMotion-built apps.

API Reference

We have comprehensive documentation with code examples, usage examples, and API reference.

Screencasts

Help

We're no longer supporting ProMotion and it's mostly retired. If you need help, feel free to file an issue, but I may not see it.

Contributing

See CONTRIBUTING.md.

Core Team (inactive)

Other Contributors

promotion's People

Contributors

adam-pl avatar andrewhavens avatar atastor avatar austinseraphin avatar bitgangsta avatar bmichotte avatar carlinisaacson avatar cavalryjim avatar chrise86 avatar dchersey avatar dmarkow avatar gertig avatar hellopatrick avatar jamonholmgren avatar jbender avatar jeffcarbs avatar jonmorehouse avatar jsierles avatar kevinvangelder avatar lax avatar macfanatic avatar markrickert avatar ohammersmith avatar robertjwhitney avatar ryanlntn avatar satoyos avatar sxross avatar thecodeduchess avatar toshiwo avatar willrax avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

promotion's Issues

Crash with searchable tableview in 0.7-head

I've got a table that works fine in 0.6 and when I tap the search box to begin searching, the app crashes in version-0.7.

The initial table loads correctly and it only crashes if you tap the search field.

(main)> 2013-05-30 12:11:49.693 BA Styles[92849:c07] _table.rb:104:in `tableView:cellForRowAtIndexPath:': undefined method `table_view_cell' for true:TrueClass (NoMethodError)
2013-05-30 12:11:49.694 BA Styles[92849:c07] *** Terminating app due to uncaught exception 'NoMethodError', reason: '_table.rb:104:in `tableView:cellForRowAtIndexPath:': undefined method `table_view_cell' for true:TrueClass (NoMethodError)
'
*** First throw call stack:
(0x1cd8012 0x7bae7e 0x339a44 0x3f52 0x3591)
libc++abi.dylib: terminate called throwing an exception
((null))> rake aborted!
Command failed with status (1): [DYLD_FRAMEWORK_PATH="/Applications/Xcode.a...]
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/file_utils.rb:53:in `block in create_shell_runner'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/file_utils.rb:45:in `call'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/file_utils.rb:45:in `sh'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/file_utils_ext.rb:37:in `sh'
/Library/RubyMotion/lib/motion/project/template/ios.rb:93:in `block in <top (required)>'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/task.rb:246:in `call'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/task.rb:246:in `block in execute'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/task.rb:241:in `each'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/task.rb:241:in `execute'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/task.rb:184:in `block in invoke_with_call_chain'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/task.rb:177:in `invoke_with_call_chain'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/task.rb:205:in `block in invoke_prerequisites'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/task.rb:203:in `each'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/task.rb:203:in `invoke_prerequisites'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/task.rb:183:in `block in invoke_with_call_chain'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/task.rb:177:in `invoke_with_call_chain'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/task.rb:170:in `invoke'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/application.rb:143:in `invoke_task'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/application.rb:101:in `block (2 levels) in top_level'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/application.rb:101:in `each'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/application.rb:101:in `block in top_level'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/application.rb:110:in `run_with_threads'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/application.rb:95:in `top_level'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/application.rb:73:in `block in run'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/application.rb:160:in `standard_exception_handling'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon@global/gems/rake-10.0.4/lib/rake/application.rb:70:in `run'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon/bin/ruby_noexec_wrapper:14:in `eval'
/Users/mrickert/.rvm/gems/ruby-1.9.3-p327-falcon/bin/ruby_noexec_wrapper:14:in `<main>'
Tasks: TOP => default => simulator
(See full trace by running task with --trace)

Add functional tests

Right now we have decent unit tests, but I'd like to add a full functional suite. I'll be working on this before version 1.0.

Crash when using custom accessoryStyle

(main)> 2013-02-21 13:10:54.536 OUCalc[19236:c07] sectioned_table.rb:143:in `tableView:cellForRowAtIndexPath:': undefined local variable or method `tableCell' for #<SearchModulesScreen:0xaa219a0> (NameError)
2013-02-21 13:10:54.538 OUCalc[19236:c07] *** Terminating app due to uncaught exception 'NameError', reason: 'sectioned_table.rb:143:in `tableView:cellForRowAtIndexPath:': undefined local variable or method `tableCell' for #<SearchModulesScreen:0xaa219a0> (NameError)
'
*** First throw call stack:
(0xc69012 0x651e7e 0x2d1364 0x1965c9 0x16ef8fb 0x16ef9cf 0x16d81bb 0x16e8b4b 0x16852dd 0x6656b0 0x261ffc0 0x261433c 0x2614150 0x25920bc 0x2593227 0x25938e2 0xc31afe 0xc31a3d 0xc0f7c2 0xc0ef44 0xc0ee1b 0x2d7a7e3 0x2d7a668 0x1634ffc 0x35c7 0x2b65)
libc++abi.dylib: terminate called throwing an exception
((null))> rake aborted!
Command failed with status (1): [DYLD_FRAMEWORK_PATH="/Applications/Xcode.a...]
/Library/RubyMotion/lib/motion/project.rb:101:in `block in <top (required)>'
/Users/jh/.rvm/gems/ruby-1.9.3-p327@oucalc/bin/ruby_noexec_wrapper:14:in `eval'
/Users/jh/.rvm/gems/ruby-1.9.3-p327@oucalc/bin/ruby_noexec_wrapper:14:in `<main>'
Tasks: TOP => default => simulator
(See full trace by running task with --trace)

Title not being set.

When including ProMotion functionality, the class method title doesn't appear to work.

The following code does not set the title.

class SomeScreen < UIViewController
  include PM::ScreenModule
  title "Some Screen's Title"
end

Whereas, this does:

class OtherScreen < PM::Screen
  title "Other Screen Title"
end

And this too:

class SomeScreen < UIViewController
  include PM::ScreenModule

  def on_load
    self.title = "Some Screen's Title"
  end
end

TableScreen BackgroundColor stays white

The code below produces an all white tableview.

class MenuScreen < ProMotion::TableScreen
  title "Menu"

  def on_load
    # tried both of these
    self.view.backgroundColor = UIColor.darkGrayColor
    self.tableView.backgroundColor = UIColor.darkGrayColor
  end

  def table_data
    [{
      title: "Account",
      cells: [
        { title: "Edit Profile", action: :edit_profile, arguments: { id: 3 }, background_color: UIColor.darkGrayColor },
        { title: "Log Out", action: :log_out },
        { title: "Notification Settings", action: :notification_settings }
      ]
    }]
  end

Objective-C stub for message `setShowsSelectionIndicator:' type `v@:c' not precompiled.

When trying to create a new UIPickerView as below this error is raised.

pickerView =  add_element UIPickerView.alloc.initWithFrame(CGRectMake(0, 45, 220, 40)), {     
  dataSource: self,
  delegate: self,
  showsSelectionIndicator: true
}

If instead of adding this to the args hash I explicitly set it as follows, no problems.

pickerView.showsSelectionIndicator=true

CamelCase options in sectioned_table.rb

    def tableView(table_view, cellForRowAtIndexPath:indexPath)
      # Aah, magic happens here...

      data_cell = cell_at_section_and_index(indexPath.section, indexPath.row)
      return UITableViewCell.alloc.init unless data_cell
      data_cell[:cellStyle] ||= UITableViewCellStyleDefault
      data_cell[:cellIdentifier] ||= "Cell"
      cellIdentifier = data_cell[:cellIdentifier]
      data_cell[:cellClass] ||= ProMotion::TableViewCell

      table_cell = table_view.dequeueReusableCellWithIdentifier(cellIdentifier)
      unless table_cell
        table_cell = data_cell[:cellClass].alloc.initWithStyle(data_cell[:cellStyle], reuseIdentifier:cellIdentifier)

        # Add optimizations here
        table_cell.layer.masksToBounds = true if data_cell[:masksToBounds]
        table_cell.backgroundColor = data_cell[:backgroundColor] if data_cell[:backgroundColor]
        table_cell.selectionStyle = data_cell[:selectionStyle] if data_cell[:selectionStyle]
        table_cell.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin
      end

      if data_cell[:cellClassAttributes]
        set_cell_attributes table_cell, data_cell[:cellClassAttributes]
      end

      if data_cell[:accessoryView]
        table_cell.accessoryView = data_cell[:accessoryView]
        table_cell.accessoryView.autoresizingMask = UIViewAutoresizingFlexibleWidth
      end

      if data_cell[:accessoryType]
        tableCell.accessoryType = data_cell[:accessoryType]
      end

      if data_cell[:accessory] && data_cell[:accessory] == :switch
        switchView = UISwitch.alloc.initWithFrame(CGRectZero)
        switchView.addTarget(self, action: "accessory_toggled_switch:", forControlEvents:UIControlEventValueChanged);
        switchView.on = true if data_cell[:accessoryDefault]
        table_cell.accessoryView = switchView
      end

      if data_cell[:subtitle]
        table_cell.detailTextLabel.text = data_cell[:subtitle]
        table_cell.detailTextLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth
      end

      table_cell.selectionStyle = UITableViewCellSelectionStyleNone if data_cell[:no_select]

      if data_cell[:remoteImage]
        if table_cell.imageView.respond_to?("setImageWithURL:placeholderImage:")
          url = data_cell[:remoteImage][:url]
          url = NSURL.URLWithString(url) unless url.is_a?(NSURL)
          placeholder = data_cell[:remoteImage][:placeholder]
          placeholder = UIImage.imageNamed(placeholder) if placeholder.is_a?(String)

          table_cell.image_size = data_cell[:remoteImage][:size] if data_cell[:remoteImage][:size] && table_cell.respond_to?("image_size=")
          table_cell.imageView.setImageWithURL(url, placeholderImage: placeholder)
          table_cell.imageView.layer.masksToBounds = true
          table_cell.imageView.layer.cornerRadius = data_cell[:remoteImage][:radius]
        else
          ProMotion::Console.log("ProMotion Warning: to use remoteImage with TableScreen you need to include the CocoaPod 'SDWebImage'.", with_color: ProMotion::Console::RED_COLOR)
        end
      elsif data_cell[:image]
        table_cell.imageView.layer.masksToBounds = true
        table_cell.imageView.image = data_cell[:image][:image]
        table_cell.imageView.layer.cornerRadius = data_cell[:image][:radius] if data_cell[:image][:radius]
      end

      if data_cell[:subViews]
        tag_number = 0
        data_cell[:subViews].each do |view|
          # Remove an existing view at that tag number
          tag_number += 1
          existing_view = table_cell.viewWithTag(tag_number)
          existing_view.removeFromSuperview if existing_view

          # Add the subview if it exists
          if view
            view.tag = tag_number
            table_cell.addSubview view
          end
        end
      end

      if data_cell[:details]
        table_cell.addSubview data_cell[:details][:image]
      end

      if data_cell[:styles] && data_cell[:styles][:textLabel] && data_cell[:styles][:textLabel][:frame]
        ui_label = false
        table_cell.contentView.subviews.each do |view|
          if view.is_a? UILabel
            ui_label = true
            view.text = data_cell[:styles][:textLabel][:text]
          end
        end

        unless ui_label == true
          label ||= UILabel.alloc.initWithFrame(CGRectZero)
          set_cell_attributes label, data_cell[:styles][:textLabel]
          table_cell.contentView.addSubview label
        end
        # hackery
        table_cell.textLabel.textColor = UIColor.clearColor
      else
        cell_title = data_cell[:title]
        cell_title ||= ""
        table_cell.textLabel.text = cell_title
      end

      return table_cell
    end

TableScreen cleanup

This has been an eyesore for a while. I'm assigning it to @silasj to clean up for version 1.0. :) Also need lots of tests!

Having problem with rotation

My app supports all 4 layout rotations but I have a single screen that I want to appear ONLY in portrait.

I understand that the only way to do this is to present the view controller modally (since all UIViewControllers take the rotation property of their UINavigationController). Not a problem.

I'm using the latest version-0.7 head

So i'm invoking the new PM::Screen subclass like this:

  def open_srm_analyzer_screen(args={})
      open SRMAnalyzerScreen.new, {modal:true, nav_bar:true}
  end

And in my class, I'm defining this:

# ...
  def should_rotate(orientation)
    puts "Trying to determine rotation"
    UIDeviceOrientationPortrait == orientation
  end

  def should_autorotate
    puts "should autorotate?"
    false
  end

  def supported_orientations
    puts "checking supported orientations"
    orientations = 0
    orientations |= UIInterfaceOrientationMaskPortrait
    orientations
  end
# ...

...but none of those methods ever get called. There's no output on the REPL when switching orientations in the simulator.

Any help would be appreciated. Am I doing something wrong? Let me know if you'd like any additional information.

Dynamic data in GroupedTableScreen

I'm new to Rubymotion, so this question might be naïve.

I'm using GroupedTableScreen, and I have the table items to be pulled from remote server.

 def on_load
   BW::HTTP.get("http://remoteserver.com/api.json") do |response|
      @games_list = massage_data(response)
   end
 end

 def on_load
    @hometable ||= [{
      title: "List of games",
      cells: @games_list
    },
    {
      title: "Settings",
      cells:
        [{
        title: "Account", action: :account_settings
        },
        {
          title: "Notification", action: :notification_settings  
      }]
    }
  ]
 end

Unfortunately, this doesn't work because BW:HTTP is async. How do I update the cell data in GroupedTable?

Element styling

I think the element styling needs more work and potentially a new paradigm.

  • ProMotion works well with Pixate but not everyone will have Pixate or want to use it.
  • The add method (previously add_element) works pretty well but still litters your controllers with view code
  • Subclassing views is a fine way to style them, but you end up with a lot of files and not everyone wants to do that
  • Teacup is one way to accomplish this but not everyone likes the way it works

I'd like some ideas. Potential discussion points:

  1. Subclass UIKit elements to add additional functionality to them, much as we've done to the UIController set?
  2. Provide a "stylesheets" folder and do something with that?
  3. Pull in an external styling system I'm not aware of, or integrate better with Teacup?

Of course, we should avoid forcing this styling paradigm on people and still work well with Teacup, Pixate, and other styling DSLs. But I think a built-in or included styling system would be a good idea.

Comments needed!

add_element: Create easy positioning attributes

I'm considering adding some additional functionality to the add_element method for easier positioning. Also, I'd like to change the name to just "add".

Example:

# NOTE that `.new` class methods alias to .alloc.init. I believe this works fine.

# Creates a horizontally-centered text field that stays centered on rotate
add UITextField.new, {
  top: 200,
  left: :auto,
  right: :auto,
  width: 200,
  height: 40
}

# Creates a right-aligned text field, 20 points from the right side
add UITextField.new, {
  top: 200,
  left: :auto,
  right: 20,
  width: 200,
  height: 40
}

# Creates a text field 20 points below the one just added.
# (definitely need input on this one)
add UITextField.new, {
  move_down: 60,
  left: :auto,
  right: 20,
  width: 200,
  height: 40
}

# Creates a text field vertically centered, dynamic width, 20 points left/right padding.
add UITextField.new, {
  top: :auto,
  bottom: :auto,
  left: 20,
  right: 20,
  width: :auto,
  height: 40
}

Need input on this.

ProMotion template

Now that RubyMotion 2.0 has template support, I'd like to build a ProMotion template.

Project Templates

RubyMotion now exposes functionality to let users chose a template when creating a new project, by passing a value to the —template argument of the motion create command.

RubyMotion comes with 3 builtin templates: ios (the default one), osx and gem, which will respectively create a RubyMotion iOS, OSX or RubyGem project.

For example, to create a new OSX project named Hello:

$ motion create --template=osx Hello
Create Hello
Create Hello/app/app_delegate.rb
Create Hello/app/menu.rb
Create Hello/Rakefile
Create Hello/resources/Credits.rtf
Create Hello/spec/main_spec.rb
3rd-party templates can also be installed into the ~/Library/RubyMotion/template directory.

We expect certain RubyMotion gems to make use of the system to provide richer project templates that include specific integration code. As an example, the Joybox team is looking into making a template that includes a game skeletton.

How to open a modal and nav_bar screen?

I want to open a new modal screen with:

open TestScreen.new, {modal: true, nav_bar: true}

But I get always the error message:

2013-03-08 14:01:41.255 Inventory[75875:c07] screen_navigation.rb:29:in `open_screen:': NSInvalidArgumentException: Application tried to present modally an active controller <DbViewScreen: 0x1d356c70>. (RuntimeError)
    from db_view_screen.rb:27:in `add_item'

What I doing wrong?

Screens - subscribe to events

Let's add an abstraction to NSNotification (perhaps as a separate gem that integrates with ProMotion).

Example:

class SomeScreen < ProMotion::Screen
  def will_appear
    subscribe_to :an_event, action: :handle_an_event
  end
  def handle_an_event
    # handle it
  end
end

# some other class
  broadcast :an_event

open doesn't animate when nav_bar: false

Hi, I don't want that nav_bar on my app, but I do want the sliding animation when you open a new screen. Since animated: true only works on modal screens, how to do this?

Something like: [self.navigationController pushViewController:vc animated:YES];

ProMotion installation generator

I'd like to make the installation instructions simpler and it would be great to be able to do something like a Rails generator:

$ motion generate promotion:install

...or...

$ rake promotion:install

This could modify the app_delegate.rb, create the app/screens and app/styles folders, etc.

Any ideas on how we could accomplish this? A Rake task seems like the easiest route to take.

Screens - inherit from UIViewController and add the ProMotion sugar via module

This will allow devs to inherit from any UIViewController and mix in ProMotion capabilities.

class HomeScreen < AnyCustomViewController
  include ProMotion::ScreenModule

  title "Home Screen"

  def will_appear
    @label = add_view UILabel.alloc.initWithFrame(CGRectMake(5, 5, 20, 20)), {
      text: "This is awesome!",
      font: UIFont.UIFont.systemFontOfSize(18)
    }
  end
end

Styling our app

In the readme of the 0.5, you tell us that the BigDay! Reminder App is built with ProMotion.
It could be interresting to tell us the gem or the basic workflow to style our app.

Like customise the nav bar color, embed custom font,...

With that, I would totally LOVE your gem !

Dismissing SplitView

I need to dismiss the master view in portrait mode when a cell in the master view's table is clicked. I can't see how to do this in the existing code, so I hacked out some code. Before submitting a pull, I wanted to run it by you for comment. In split_screen.rb:

    def dismiss_popover_controller
      @popover_controller.dismissPopoverAnimated(@popover_controller) if @popover_controller
    end

    # UISplitViewControllerDelegate methods

    def splitViewController(svc, willHideViewController: vc, withBarButtonItem: button, forPopoverController: pc)
      button.title = vc.title
      svc.detail_screen.navigationItem.leftBarButtonItem = button;
      @popover_controller = pc
    end

    def splitViewController(svc, willShowViewController: vc, invalidatingBarButtonItem: barButtonItem)
      svc.detail_screen.navigationItem.leftBarButtonItem = nil
      @popover_controller = nil
    end

Add the method dismiss_popover_controller and memoized the popover.

In client code, the split view is created in AppDelegate, so I do this:

      App.delegate.dismiss_popover_controller

For TableScreens, on_init is called after table_setup

Note - I've edited the original issue to be more clear.

I've gotten around this by defining my table_data method like this:

attr_accessor :my_attr_accessor

def on_init
  @my_attr_accessor = []
end

def table_data
  on_init if @my_attr_accessor.nil?
  # build table data here
end

It looks like we could just switch these two lines in _screen_module.rb to fix the issue so that there's a chance to initialize things before the table is built:

self.table_setup if self.respond_to?(:table_setup)
self.on_init if self.respond_to?(:on_init)

Change name of PM::AppDelegateParent to PM::Delegate

I've never been fond of ProMotion::AppDelegateParent. What say we change it to just ProMotion::Delegate?

class AppDelegate < ProMotion::Delegate
  def on_load(app, options)
    open HomeScreen
  end
end

I'll keep the AppDelegateParent active so older apps can use it.

Support for UITableView deleteRowsAtIndexPaths

I keep getting:
The number of rows contained in an existing section after the update (77) must be equal to the number of rows contained in that section before the update (77), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted)

Get the controller of the screen

There's numbers of pods and gems who need the controller of the current view to work.

It could be great to have a function that return the view controller for a screen and the table view controller when it's the case.

table screen w/ searchable - search fails with:

(main)> 2013-05-30 16:05:05.421 mobileAdmin2[6650:c07] _searcha:in searchDisplayController:shouldReloadTableForSearchString:': undefined methodsearch' for true:TrueClass (NoMethodError)
2013-05-30 16:05:05.448 mobileAdmin2[6650:c07] *** Terminating app due to uncaught exception 'NoMethodError', reason: '_searcha:in searchDisplayController:shouldReloadTableForSearchString:': undefined methodsearch' for true:TrueClass (NoMethodError)

Specs fail with RubyMotion 2.0

I've submitted a support request.

With RM 1.35, specs pass fine in ProMotion 0.6 branch:

https://github.com/clearsightstudio/ProMotion/tree/version-0.6

Running rake spec debug=1 -- no problem. "Program exited normally."

With RM 2.0, partway through it crashes with this:

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x30b3b0e2
0x004f709b in objc_msgSend ()

If you clone the repo and run rake spec debug=1 with both RM 1.35 and RM 2.0 you'll see this happen. I was able to replicate every time.

I'll update here with any response. For now, downgrading to RubyMotion 1.35 (via sudo motion update --force-version=1.35) works.

Auto-populate table screens based on array of objects

Example:

class FriendsScreen < ProMotion::TableScreen
  title "Friends"
  cell_label_method :full_name
  cell_action :tapped_friend

  def friends
    @friends ||= [ Friend.new("Joe"), Friend.new("John"), Friend.new("Silas") ]
  end

  def table_data
    self.friends
  end

  def tapped_friend(friend)
    # Do something with the friend object here
  end
end

This would use the cell_label_method to call each object in the table_data array and construct the table:

if self.cell_label_method
  data.each do |obj|
    @table_cell[:label] = obj.send(self.cell_label_method)
  end
end

...something like that.

Thoughts?

Pull to refresh in Table Screen

It could be great to have a simple config to make a pull refresh enabled for a table view.
Imagine if the data came from a json call or whatever, you can call the update_table_data.

We can use the UIRefreshControl for iOS 6 and use CKRefreshControl for older version : we can use the same code for iOS 5 and 6 with that.

It could be somethings like :

class SettingsScreen < ProMotion::TableScreen
  title "Settings"
  pullToRefresh true

  def on_load
    add_right_nav_button(label: "Save", action: :save)
    set_tab_bar_item(title: "Settings", icon: "settings.png")
  end

  def table_data
    ...
  end
end

What do you think about that ?

textFieldShouldReturn not being called in ProMotion::Screen

textFieldShouldReturn doesn't appear to be getting called in a ProMotion::Screen. I've got the following code.

Can anyone reproduce this?

class LoginScreen < ProMotion::Screen

  def will_appear
    set_attributes self.view, {
      backgroundColor: 'white'.to_color
    }

    @screen_height = view.bounds.size.height
    @screen_width = view.bounds.size.width

    add_fields
  end

  def add_fields    
    # Login button
    @login = UIButton.buttonWithType(UIButtonTypeRoundedRect)
    @login.setTitle("Login", forState:UIControlStateNormal)
    @login.sizeToFit
    @login.frame = CGRectMake( 20, 100, @screen_width - 40, 55 ) # left, top, width, height
    add @login

    @login.when(UIControlEventTouchUpInside) do
      p @email.text
    end

    # Email
    @email = UITextField.alloc.initWithFrame [[20, 20], [@screen_width - 40, 26]]
    @email.placeholder = "Email Address"
    @email.textAlignment = UITextAlignmentLeft
    @email.keyboardType = UIKeyboardTypeEmailAddress
    @email.borderStyle = UITextBorderStyleRoundedRect
    @email.returnKeyType = UIReturnKeyNext
    add @email

    # Password
    @password = UITextField.alloc.initWithFrame [[20, 60], [@screen_width - 40, 26]]
    @password.placeholder = "Password"
    @password.textAlignment = UITextAlignmentLeft
    @password.keyboardType = UIKeyboardTypeEmailAddress
    @password.borderStyle = UITextBorderStyleRoundedRect
    @email.returnKeyType = UIReturnKeyDone
    add @password
  end

  def textFieldShouldReturn textField
    textField.resignFirstResponder
    true
  end
end

add_element: Allow for parameterized attribute setters?

How could we accomplish the situation like below with setTitle:forControlState:?

@button = add_element UIButton.buttonWithType(UIButtonTypeRoundedRect), {
  setTitle: "test", # it needs two parameters here, the title-string and the UIControlState (e.g. UIControlStateNormal)
  frame: CGRectMake(10, 150, 200, 40),
  backgroundColor: UIColor.blueColor
}

One suggestion would be to use a hash:

@button = add_element UIButton.buttonWithType(UIButtonTypeRoundedRect), {
  {setTitle: "test", forControlState: UIControlStateNormal},
  frame: CGRectMake(10, 150, 200, 40),
  backgroundColor: UIColor.blueColor
}

Not sure how to implement though.

Getting Started: Clarification

It's worth mentioning that when a new user drops the on_load code into AppDelegate, they have to remove the boilerplate didFinishLoadingWithOptions method or they'll never get the goodness of ProMotion.

Great work, BTW!

Fire on_return in the view_did_disappear method?

There's a problem when dismissing a modal screen and trying to open another one in that on_return is fired as soon as the modal starts animating but before it has a chance to completely disappear. This prevents you from opening another screen (modally or otherwise).

It would be possible to wait for the view_did_disappear to fire before sending the on_return method call. Anybody see any negative side effects?

Add Test Coverage

I think before you get too many more versions under your belt, that we should look at adding some test coverage to the suite. Would have definitely helped with the refactoring that went on from 0.3 => 0.4 => 0.5

I'd love to help out, so if you want to get started over Twitter & share some contact info, let's make this happen. I added test coverage to my (much smaller) gem for RM that I released yesterday, can_i, and it was actually a pleasure to do and not terribly difficult to get started.

There's articles on using cucumber with some other library, and even a gem for mocking with RM.

RUBYMOTION_ENV uninitialized constant

Since I'm using 0.7 I had a deprecation but the logging of this information created this
error message:

logger.rb:36:in `log:': uninitialized constant ProMotion::Logger::RUBYMOTION_ENV (NameError)
    from logger.rb:46:in `deprecated:'
    from delegate.rb:33:in `inherited:'

Don't work with ::RUBYMOTION_ENV. But "p RUBYMOTION_ENV" in my on_load in app_delegate.rb works. Are there some Gem limitations?

Adding a UIButton

This looks like an awesome library. I seem to be having some trouble adding a UIButton.

My last attempt was this:
@button = add UIButton.buttonWithType.UIButtonTypeRoundedRect, {
setTitle: "Schedule",
}

Not sure what I am missing. Any ideas?

Simple method to reload data for table screen

When the return of table_data is updated (I see it by getting the result in the console), Ii doesn't affect the table screen. If you have it in your gem, I'm sorry but I can't find it.

Why not have somethings like if we can code it :

class ContactsScreen < ProMotion::GroupedTableScreen
  def on_load
    self.loadJson
  end

  def table_data
    # get the data from the model and generate the cells
    return theCellsData
  end

  def loadJson
    # Loading stuff and generate the new contacts in the models
    self.reload_table_data
  end
end

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.