(Rubymotion) How can I do this custom view in Formotion? - ios

I am struggling at the moment to make a custom Form with Formotion(Also I'm very new in Rubymotion). Maybe I have to try another framework or maybe not doing any framework at all....
I try to make this:
At this moment I created this in Formotion:
The problem is the Border between password and email. It has to start under the text field and not under the icon. It is a small change but I don't know how to do this with Formotion. Are those kind of things easy possible? Thanks in advanced!
Here is my code:
class LoginScreen < PM::FormotionScreen
title ""
def table_data
{
sections: [
{
title: "Login",
rows: [
{
title: "Email",
key: :email,
type: :email,
placeholder: "me#mail.com",
auto_correction: :no,
auto_capitalization: :none,
text_alignment: UITextAlignmentLeft
}, {
title: "Password",
key: :password,
type: :password,
placeholder: "required",
secure: true,
text_alignment: UITextAlignmentLeft
}
]
}
]
}
end
end
I overwritten the EmailRow to insert the icon
motion_require 'string_row'
module Formotion
module RowType
class EmailRow < StringRow
def build_cell(cell)
cell.selectionStyle = self.row.selection_style || UITableViewCellSelectionStyleBlue
field = UITextField.alloc.initWithFrame(CGRectZero)
field.tag = TEXT_FIELD_TAG
observe(self.row, "value") do |old_value, new_value|
break_with_semaphore do
update_text_field(new_value)
end
end
field.clearButtonMode = UITextFieldViewModeWhileEditing
field.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter
field.textAlignment = row.text_alignment || UITextAlignmentRight
field.keyboardType = keyboardType
field.secureTextEntry = true if row.secure?
field.returnKeyType = row.return_key || UIReturnKeyNext
field.autocapitalizationType = row.auto_capitalization if row.auto_capitalization
field.autocorrectionType = row.auto_correction if row.auto_correction
field.clearButtonMode = row.clear_button || UITextFieldViewModeWhileEditing
field.enabled = row.editable?
field.inputAccessoryView = input_accessory_view(row.input_accessory) if row.input_accessory
add_callbacks(field)
cell.swizzle(:layoutSubviews) do
def layoutSubviews
old_layoutSubviews
# viewWithTag is terrible, but I think it's ok to use here...
formotion_field = self.viewWithTag(TEXT_FIELD_TAG)
formotion_field.sizeToFit
field_frame = formotion_field.frame
field_frame.origin.x = self.textLabel.frame.origin.x + Formotion::RowType::Base.field_buffer * 2
field_frame.origin.y = ((self.frame.size.height - field_frame.size.height) / 2.0).round
field_frame.size.width = self.frame.size.width - field_frame.origin.x - Formotion::RowType::Base.field_buffer
formotion_field.frame = field_frame
end
end
if UIDevice.currentDevice.systemVersion >= "6.0"
field.swizzle(:setText) do
def setText(text)
r = old_setText(text)
self.sendActionsForControlEvents(UIControlEventEditingChanged)
r
end
end
end
field.font = BW::Font.new(row.font) if row.font
field.placeholder = row.placeholder
field.text = row_value
icon = UIImage.imageNamed("icons/mail.png")
icon_view = UIImageView.alloc.initWithImage(icon)
icon_view.setFrame(CGRectMake(20, 18, icon_view.frame.size.width, icon_view.frame.size.height))
cell.addSubview(icon_view)
cell.addSubview(field)
cell.textLabel.hidden = true
field
end
end
end
end

This was extremely easy in the end. Just add an image in cell.imageView in EmailRow.
added this line:
cell.imageView.image = UIImage.imageNamed("icons/mail.png")
cell.imageView.setFrame(CGRectMake(20, 18, cell.imageView.frame.size.width, cell.imageView.frame.size.height))
and you access the cell with the code below, for example:
cell = #form.table.visibleCell.first

I'd recommend disabling the built-in border entirely and adding a pseudo-border using a thin UIView. That way you can set the frame to position it in the right position and give it a backgroundColor of #E3E3E5k like in your mockup.

Related

Kivy: FileChooser redrawing

I want to use FileChooser for basic operation. I select folder using FileChooser, I will remove it using own function. Folder is removed and I want to show new contents of disc but contents is incorrect How do I show current right contents of disc?
My question based from problem with next code. When I removed folder in root directory, contens of FileChooserListView was incorrect. Source of problem was in discname. Last symbol in disc name wasn't '**'. After added this ( function delete_dir() isn't problem.
Builder.load_string('''
<ConfirmPopup>:
cols:1
Label:
text: root.text
GridLayout:
cols: 2
size_hint_y: None
height: '44sp'
Button:
text: 'Yes'
on_release: root.dispatch('on_answer','yes')
Button:
text: 'No'
on_release: root.dispatch('on_answer', 'no')
''')
class ConfirmPopup(GridLayout):
text = StringProperty('')
def __init__(self,**kwargs):
self.register_event_type('on_answer')
super(ConfirmPopup,self).__init__(**kwargs)
def on_answer(self, *args):
pass
class PopupYesNo(GridLayout):
def __init__(self, save_as, task):
self.save_as = save_as
self.task = task
def show_widget(self, question):
self.content = ConfirmPopup(text= question)
self.content.bind(on_answer = self._on_answer)
self.popup = Popup(title="Answer Question",
content=self.content,
size_hint=(None, None),
size=(480,400),
auto_dismiss= False)
self.popup.open()
def _on_answer(self, instance, answer):
if answer == 'yes':
self.save_as.act_task()
self.popup.dismiss()
return
class SaveAs(BoxLayout):
def __init__(self, **kwargs):
super(SaveAs,self).__init__(**kwargs)
self.orientation = 'vertical'
self.fichoo = FileChooserListView(size_hint_y = 0.8)
self.add_widget(self.fichoo)
control = GridLayout(cols = 5, row_force_default=True, row_default_height=35, size_hint_y = 0.14)
self.tein_dir = TextInput(size_hint_x = None, width = 350)
self.tein_dir.multiline = False
bt_del_dir = Button(text = 'Remove',size_hint_x = None, width = 80)
bt_del_dir.bind(on_release = self.on_delete_dir)
control.add_widget(self.tein_dir)
control.add_widget(bt_del_dir)
self.fichoo.bind(path = self.on_path_select)
self.add_widget(control)
return
def on_path_select(self, inst, val):
self.tein_dir.text = str(self.fichoo.path)
return
def on_delete_dir(self, obj):
question = 'Do You want to remove: '+ self.tein_dir.text+ '?'
self.act_task = self.delete_dir
popup = PopupYesNo(self, SaveAs.delete_dir)
popup.show_widget(question)
return
def delete_dir(self):
pos = self.fichoo.path.rfind('\\', 0, len(self.fichoo.path))
new_path = str(self.fichoo.path)[0:pos]
if new_path[-1] == ':':
new_path += '\\' # last symbol in discname is '\'
self.tein_dir.text = new_path
os.chdir(new_path)
shutil.rmtree(str(self.fichoo.path))
self.fichoo.path = new_path
return
class ExplorerApp(App):
def build(self):
self.save_as = SaveAs()
return self.save_as
if __name__ == '__main__':
ExplorerApp().run()

Batch processing and error handling in CSV upload in Rails

I am using active admin and uploading the records into the database from CSV file. However, there are two issues occurs here; Code breaks if any filed is missing and secondly performance is very week, can't we do it in the batch process. It is an important and I believe many developers thinking a good solution for such problem.
require 'CSV'
class CsvDb
class << self
def convert_save(model_name, csv_data, field_name=nil)
target_model = model_name.classify.constantize
csv_file = csv_data.read
row_headers={}
counter=0;
#Thread.new do
CSV.parse(csv_file) do |row|
if counter==0
temp=row
row_headers = Hash[temp.map.with_index.to_a]
counter +=1
next
end
unless row[row_headers["name"]].nil?
temp={}
business_type = row[row_headers["business_type_id"]]
business_type_id = business_type=='Online' ? 1: business_type=='Local' ? 2: 3
temp[:business_type_id] = business_type_id
temp[:user_id] = row[row_headers["user_id"]]
temp[:name] = row[row_headers["name"]]
temp[:country_id] = row[row_headers["country_id"]]
temp[:homepage] = row[row_headers["homepage"]] ||=""
temp[:telephone] = row[row_headers["telephone"]] ||=""
temp[:email] = row[row_headers["email"]] ||=""
temp[:address] = row[row_headers["address"]] ||=""
temp[:latitude] = row[row_headers["latitude"]]
temp[:longitude] = row[row_headers["longitude"]]
temp[:facebook] = row[row_headers["facebook"]] ||=""
temp[:twitter] = row[row_headers["twitter"]] ||=""
temp[:google] = row[row_headers["google"]] ||=""
temp[:instagram] = row[row_headers["instagram"]] ||=""
temp[:pinterest] = row[row_headers["pinterest"]] ||=""
temp[:free_shipping] = row[row_headers["free_shipping"]]
temp[:ship_details] = row[row_headers["ship_details"]] ||=""
temp[:category_ids] = [row[row_headers["category_ids"]]]
temp[:style_ids] = [row[row_headers["style_ids"]]]
temp[:shipping_country_ids] = [row[row_headers["shipping_country_ids"]]]
temp[:filter_ids] = [row[row_headers["filter_ids"]]]
business = target_model.new(temp)
business.save
end
end
ActiveRecord::Base.connection.close
end
#end
end
end
I'll just focus on the translation of the CSV rows into an object. There's just to much repetition in the unless body. All those rows should be mentioned once, then handled in a loop instead of hard coding them like this. E.g.
unless row[row_headers["name"]].nil?
temp={}
business_type = row[row_headers["business_type_id"]]
business_type_id = business_type == "Online" ? 1: business_type == "Local" ? 2 : 3
temp[:business_type_id] = business_type_id
for name in [:user_id, :name, :country_id, :latitude, :longitude, :free_shipping, :category_ids, :style_ids, :shipping_country_ids]
temp[name] = row[row_headers[name.to_s]]
end
for name in [:homepage, :telephone, :email, :address, :facebook, :twitter, :google, :instagram, :pinterest, :ship_details]
temp[name] = row[row_headers[name.to_s]] ||= ""
end
business = target_model.new(temp)
business.save
end
Alternate solution received from code review site:
CSV.parse(csv_file, {headers: true, header_converters: :symbol}) do |row|
business_type_id = case row[:business_type_id]
when 'Online' then 1
when 'Local' then 2
else 3
end
target_model.new( {business_type_id: business_type_id} + extract_required_fields(row) + extract_optionals_fiels(row) )
.save()
end
def extract_required_fields(row)
[:user_id, :name, :country_id, :free_shipping, :category_ids, :style_ids, :shipping_country_ids]
.reduce({}) do |carry, item|
carry[item] = row[item]
end
end
def extract_optionals_fiels(row)
[:homepage, :telephone, :email, :address, :facebook, :twitter, :google, :instagram, :pinterest, :ship_details]
.reduce({}) do |carry, item|
carry[item] = row[item] ||= ''
end
end

Avoiding eval when building radio buttons in rails

Here, I am building database driven radio buttons. I wanted to know if there is a way I can avoid eval and see checked is true or not !Thanks,
Index Controller
columns = Model.column_names
View in haml
- columns.each do |cols|
- check = "c[0].#{cols}==1? true : false" // checking value here
- negcheck = "c[0].#{cols}==0? true : false"// checking value here
- pluckid = "c[0].id"
- id = eval(pluckid)
%tbody
%td #{cols}
%td
= label_tag 'On'
= radio_button_tag("ABC",1,checked = eval(check), options = {})
= label_tag 'Off'
= radio_button_tag("xyz",0,checked = eval(negcheck), options = {})
You can use the [] method to access the value.
- columns.each do |cols|
- check = c[0][cols] == 1
- negcheck = c[0][cols] == 0
- id = c[0].id
%tbody
%td #{cols}
%td
= label_tag 'On'
= radio_button_tag("ABC", 1, checked = check, options = {})
= label_tag 'Off'
= radio_button_tag("xyz", 0, checked = negcheck, options = {})
eval("c[0].#{cols}==1? true : false")
can be written as
c[0].send(cols) == 1

How to change an entire tables text color with prawn

I have a RoR app that generates a pdf page using the prawn gem:
class ReportPdf < Prawn::Document
def initialize(employees)
super(top_margin: 70)
#employees = employees
list_employees
end
def list_employees
move_down 20
table list_employee_rows do
row(0).font_style = :bold
columns(1..4).align = :right
self.row_colors = ["E8EDFF", "FFFFFF"]
self.row(0).background_color = '005C89'
self.row(0).text_color = "FFFFFF"
self.header = true
end
end
def list_employee_rows
[["Name", "Badge number"]] +
#employees.map do |employee|
[employee.name, employee.badge_number]
end
end
end
I can change a specific row's text color (above I've changed the header's color to white) but how would I set the entire tables text color (and not the already set header's color)?
It's simple one line change in your list_employees.
Your list_employees method should look like this:
def list_employees
move_down 20
table list_employee_rows do
row(0).font_style = :bold
columns(1..4).align = :right
self.cell_style = { :text_color => "ffffff"}
self.row(0).background_color = '005C89'
self.row(0).text_color = "FFFFFF"
self.row_colors = ["E8EDFF", "FFFFFF"]
self.header = true
end
end
Inside the tables do block you should be able to define the properties of all the cells using a call to cells.style. There you will be able to define all the properties you like.

undefined method `initWithNibName'

I have just started learning iOS development with RubyMotion and I'm doing this tutorial. It seems pretty easy to understand, but right now I'm stuck with this error I get when I run the rake command:
ColorController.rb:7:in `initWithColor:': undefined method `initWithNibName' for #<ColorController:0x9b4f470> (NoMethodError)
from SearchController.rb:46:in `open_color:'
from Color.rb:35:in `block in find:'
from query.rb:358:in `call_delegator_with_response'
from query.rb:128:in `connectionDidFinishLoading:'
I got to the part where WHEW WELL THAT IS A TON OF CODE NOW ISN'T IT. is found on the tutorial page and I'm stuck there. Currently my code looks like:
# app_delegate.rb
class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
#window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
#search_controller = SearchController.alloc.initWithNibName(nil, bundle: nil)
#navigation_controller = UINavigationController.alloc.initWithRootViewController(#search_controller)
#window.rootViewController = #navigation_controller
#window.makeKeyAndVisible
true
end
end
# ColorController.rb
class ColorController < UIViewController
attr_accessor :color
def initWithColor(color)
initWithNibName(nil, bunlde: nil)
self.color = color
self
end
def viewDidLoad
super
self.title = self.color.hex
#info_container = UIView.alloc.initWithFrame [[0, 0], [self.view.frame.size.width, 110]]
#info_container.backgroundColor = UIColor.lightGrayColor
self.view.addSubview #info_container
#color_view = UIView.alloc.initWithFrame [[10, 10], [90, 90]]
#color_view.backgroundColor = String.new(self.color.hex).to_color
self.view.addSubview #color_view
#color_label = UILabel.alloc.initWithFrame [[110, 30], [0, 0]]
#color_label.text = self.color.hex
#color_label.sizeToFit
self.view.addSubview #color_label
#text_field = UITextField.alloc.initWithFrame [[110, 60], [100, 26]]
#text_field.placeholder = "tag"
#text_field.textAlignment = UITextAlignmentLeft
#text_field.autocapitalizationType = UITextAutocapitalizationTypeNone
#text_field.borderStyle = UITextBorderStyleRoundedRect
self.view.addSubview #text_field
#add_button = UIButton.buttonWithType(UIButtonTypeRoundedRect)
#add_button.setTitle("Add", forState: UIControlStateNormal)
#add_button.setTitle("Adding", forState: UIControlStateDisabled)
#add_button.setTitleColor(UIColor.lightGrayColor, forState: UIControlStateDisabled)
#add_button.sizeToFit
#add_button.frame = [[#text_field.frame.origin.x + #text_field.frame.size.width + 10, #text_field.frame.origin.y], #add_button.frame.size]
self.view.addSubview(#add_button)
table_frame = [[0, #info_container.frame.size.height], [self.view.bounds.size.width, self.view.bounds.size.height - #info_container.frame.size.height - self.navigationController.navigationBar.frame.size.height]]
#table_view = UITableView.alloc.initWithFrame(table_frame, style: UITableViewStylePlain)
self.view.addSubview(#table_view)
end
end
# SearchController.rb
class SearchController < UIViewController
def viewDidLoad
super
self.title = "Search"
self.view.backgroundColor = UIColor.whiteColor
#text_field = UITextField.alloc.initWithFrame [[10, 10], [self.view.frame.size.width - 20, 30]]
#text_field.placeholder = "#abcabc"
#text_field.textAlignment = UITextAlignmentLeft
#text_field.autocapitalizationType = UITextAutocapitalizationTypeNone
#text_field.borderStyle = UITextBorderStyleRoundedRect
#text_field.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2 - 100)
self.view.addSubview #text_field
#search_button = UIButton.buttonWithType(UIButtonTypeRoundedRect)
#search_button.setTitle("Search", forState: UIControlStateNormal)
#search_button.setTitle("Loading", forState: UIControlStateDisabled)
#search_button.sizeToFit
#search_button.center = CGPointMake(self.view.frame.size.width / 2, #text_field.center.y + 40)
self.view.addSubview #search_button
#search_button.when(UIControlEventTouchUpInside) do
#search_button.enabled = false
#text_field.enabled = false
hex = #text_field.text
hex = hex[1..-1] if hex[0] == "#"
Color.find(hex) do |color|
if color.nil?
#search_button.setTitle("None :(", forState: UIControlStateNormal)
else
#search_button.setTitle("Search", forState: UIControlStateNormal)
self.open_color(color)
end
#search_button.enabled = true
#text_field.enabled = true
end
end
end
def open_color(color)
self.navigationController.pushViewController(ColorController.alloc.initWithColor(color), animated: true)
end
end
I also have another two models which I'm sure they are not relevant unless you're going to run the code.
Can anyone tell me what am I supposed to do ? I realise that I'm trying to call the initWithNibName method which is not defined on my class, but that is what the tutorial does so I assumed it's correct. Do I need to define it on the ColorController class ? Or can I call it in some other way ?
You just spelled bundle incorrectly.
change:
initWithNibName(nil, bunlde: nil)
to:
initWithNibName(nil, bundle: nil)

Resources