button widget reacts differently on Android and iOS

The button widget reacts differently when a native.showAlert appears. I created a button widget when pressed for about a half a second, a showAlert will popup asking if you want to remove the button that is being pressed and when I release the button, it switches to ended phase. This happens on simulator and on android device which is what I wanted it to do, but on iOS device it reacts differently. When the showAlert pops up and I release the button, it stays on pressed state. This behavoir freezes the app and will crash after a few seconds when I remove the button after the user chooses to delete the button.

Here’s a sample of my code.

[lua]

local function onComplete(event)
    if(event.index == 1) then
        currentButton:removeSelf();

        currentButton = nil
    end
end

function t:timer( event )
    local count = event.count;
    if releasedItem then
        timer.cancel(event.source);
        releasedItem = false;
    elseif(count == 30) then
        showdelete = true;
        native.showAlert(“Warning”, “Are you sure you want to delete this item?”, {“Yes”,“No”}, onComplete)
    end
end

local function bEvent(event)
    if event.phase == “began” then
        currentButton = event.target
        timer.performWithDelay(1, t, 0);
    elseif event.phase == “moved” then
        local dx = math.abs( event.x - event.xStart )
        local dy = math.abs( event.y - event.yStart )
        if dx > 25 or dy > 25 then
            releasedItem = true;
        end
    elseif event.phase == “ended” then
        releasedItem = true;
    end
end
 

[/lua]

Hi @larryeh,

May I ask why you’re setting an infinite timer of 1 millisecond on the “began” phase? Instead, can you just start one timer (of a slightly longer time), and if/when it executes, you manage the native popup? Or, if the user “releases” the button, just cancel the timer, so the popup won’t happen.

I just find that method firing a 1 millisecond timer 30 times in succession to be “unsetting” at the least. Timers aren’t really meant to be used that way, in general. :slight_smile:

Regards,

Brent

Whoops I posted a reply with a wrong account. I can’t delete this post so I’ll edit this.

Hello @Brent,

I did your recommendation but the app still crashed.

here is my new code

[lua]

local function onComplete(event)
    if(event.index == 1) then
        currentButton:removeSelf();
        currentButton = nil
    end
end
 
 
function t:timer( event )
    if releasedItem then
        timer.cancel(event.source);
        releasedItem = false;
    else
        showdelete = true;
        native.showAlert(“Warning”, “Are you sure you want to delete this item?”, {“Yes”,“No”}, onComplete)
    end
end
 
 
local function bEvent(event)
    if event.phase == “began” then
        currentButton = event.target
        timer.performWithDelay(500, t, 1);
    elseif event.phase == “moved” then
        local dx = math.abs( event.x - event.xStart )
        local dy = math.abs( event.y - event.yStart )
        if dx > 25 or dy > 25 then
            releasedItem = true;
        end
    elseif event.phase == “ended” then
        releasedItem = true;
    end
end

[/lua]

It really has something to do with the button staying at pressed state.

Hi @larryeh,

As I glance at the code, it appears you’re doing this (correct me if I’m wrong):

  1. When user touches the button (“began”), it starts the timer.

  2. If the user moves the touch more than 25 pixels from the start point, that’s like a “cancel action”.

  3. Same with the “ended” phase… if they don’t hold down for 500 ms, then the action is considered null and void.

If this is true, shouldn’t the timer just be cancelled in events #2 and #3 above? Directly when they occur, versus after the timer completes? I don’t know if that will solve the specific core issue that you mention, but that’s how I’d probably do it.

Now, let’s say it gets to the “alert” stage (user doesn’t move the touch point too much, and doesn’t lift up before 500 ms). I’d suggest that before you display the alert box, you dispatch a “fake ended” phase to the button listener using “dispatchEvent()” (link to the API doc below). This tells Corona that you want to treat the touch routine on the button as “ended” even if the user hasn’t actually lifted up the touch. Although not a common API, it’s useful in cases like these.

http://docs.coronalabs.com/api/type/EventListener/dispatchEvent.html

Try that, and see what happens.

Brent

P.S. - In your second implementation, does the app still crash after a few seconds?

Hello @Brent

Yes sir you got it right. Canceling the timer from event 2 and 3 is working ok. The problem only occurs after the alertShow appears. I tried using the dispatchEvent() you suggested but it doesn’t seem to be working. The button is still on pressed state. Is this correct implementation?

[lua]

local releasedItem = false
local t = {}
local currentButton
local button

local function onComplete(event)
    if(event.index == 1) then
        releasedItem = true
        currentButton:removeSelf();
        currentButton = nil
    else
        releasedItem = true
    end
end
 
function t:timer( event )
    if releasedItem then
        timer.cancel(event.source);
    else
        local myEvent = {name=“button”, phase = “ended”, target = currentButton}
        currentButton:dispatchEvent(myEvent)
        native.showAlert(“Warning”, “Are you sure you want to delete this item?”, {“Yes”,“No”}, onComplete)
    end
end
 
local function bEvent(event)
    print(event.phase)
    if event.phase == “began” then
        currentButton = event.target
        timer.performWithDelay(500, t, 1);
        releasedItem = false;
    elseif event.phase == “moved” then
        local dx = math.abs( event.x - event.xStart )
        local dy = math.abs( event.y - event.yStart )
        if dx > 25 or dy > 25 then
            releasedItem = true;
        end
    elseif event.phase == “ended” then
        releasedItem = true;
    end
end

button = widget.newButton{
    width = 100,
    height = 80,
    label = “button”,
    onEvent = bEvent
}
button.x = display.contentWidth / 2;button.y = display.contentHeight / 2;

[/lua]

Hi @larryeh,

Try setting the “name” parameter of the dispatch to “touch”… it’s supposed to equal the type of event you’re dispatching, so in this case a “touch ended” phase.

If things are still not quite working, you might also try showing the alert popup after a very short delay (like 30 ms) just to allow the event to resolve itself before showing the alert. Maybe it’s not necessary, but it’s worth trying if you’re still having issues.

Brent

@Brent

Okay I set the “name” parameter to “touch” and test it on my sample code. It worked, but when I try to implement it to my actual project code doesn’t seem to be working. I even placed the alert popup inside a timer delay just to make sure the event resolves itself but still no good. There’s probably something that blocks the dispatchEvent from performing but I don’t know what.

Here’s the sample code that I posted with the dispatchEvent() working.

[lua]

local releasedItem = false
local t = {}
local currentButton
local button

local function onComplete(event)
    if(event.index == 1) then
        releasedItem = true
        currentButton:removeSelf();
        currentButton = nil
    else
        releasedItem = true
    end
end
 
function t:timer( event )
    if releasedItem then
        timer.cancel(event.source);
    else
        local myEvent = {name=“touch”, phase = “ended”, target = currentButton}
        currentButton:dispatchEvent(myEvent)
        native.showAlert(“Warning”, “Are you sure you want to delete this item?”, {“Yes”,“No”}, onComplete)
    end
end
 
local function bEvent(event)
    print(event.phase)
    if event.phase == “began” then
        currentButton = event.target
        timer.performWithDelay(500, t, 1);
        releasedItem = false;
    elseif event.phase == “moved” then
        local dx = math.abs( event.x - event.xStart )
        local dy = math.abs( event.y - event.yStart )
        if dx > 25 or dy > 25 then
            releasedItem = true;
        end
    elseif event.phase == “ended” then
        print(“HEEY”)
        releasedItem = true;
    end
end

button = widget.newButton{
    width = 100,
    height = 80,
    label = “button”,
    onEvent = bEvent
}
button.x = display.contentWidth / 2;button.y = display.contentHeight / 2;

[/lua]

Now Here’s my actual project code:

[lua]

local storyboard = require( “storyboard” )
local scene = storyboard.newScene()
local widget = require"widget";
local database = require"database";

local _W = display.contentWidth;
local _H = display.contentHeight;

local screenGroup;
local textfield;

local bg;
local button = {}
local navBar = {}
local categories = {}
categories.list = {}
categories.idlist = 1
local category_items = {
    “Creat your own”,
    “Appliances”,
    “Baby related equipment”,
    “Electronics”,
    “Furnitures”,
    “Tools”,
    “Personal care”,
    “Apparel”
}
local t = {}

local catButtons = {}

local donotHide = true;

local releasedItem = false

local showdelete = false

local currentItem;
local currentObject;
local currentItem_id;
local currentItem_id_list;

local function hidekeyboard()
    if (textfield ~= nil and donotHide == false) then
        donotHide = true;
        textfield:removeSelf()
        textfield = nil
        native.setKeyboardFocus(nil)
    else
        donotHide = false;
    end
    if(categories.slide) then
        categories.slide = false;
        transition.to(categories.Group, {time = 100, y = categories.Group.y + 710})
    end
end

local function goback()
    storyboard.gotoScene( “create_inventory_screen_small”, “slideRight”, 200  )
end

local function onComplete(event)
    showdelete = false;
    if(event.index == 1) then
        database.deleteCategory(inventory.inventory, currentItem)
        local newy = 130
        local c_id = currentItem_id_list + 1
        categories.presenty = categories.presenty - newy;
        categories.presentlist[currentItem_id_list] = “”
        categories.list[currentItem_id_list]:removeSelf();
        categories.list[currentItem_id_list] = “”;
        for i = c_id, #categories.list do
            if(categories.list[i] ~= nil) then
                transition.to(categories.list[i], {time = 300, y = categories.list[i].y - newy})
            end
        end
        releasedItem = true
    end
end

function t:timer( event )
    if releasedItem then
        timer.cancel(event.source);
        releasedItem = false;
    else
        showdelete = true;
        local myEvent = {name=“touch”, phase=“ended”, target=currentObject}
        currentObject:dispatchEvent(myEvent)
        local function alertThis()
            native.showAlert(“Warning”, “Are you sure you want to delete this item?”, {“Yes”,“No”}, onComplete)
        end
        timer.performWithDelay(30, alertThis)
    end
end

local function catEvent(event)
    if event.phase == “began” then
        hidekeyboard()
        currentObject = event.target
        currentItem = event.target.name
        currentItem_id = event.target.id
        currentItem_id_list = event.target.id_list
        timer.performWithDelay(500, t, 1);
        releasedItem = false
    elseif event.phase == “moved” then
        local dx = math.abs( event.x - event.xStart )
        local dy = math.abs( event.y - event.yStart )
        if dx > 25 or dy > 25 then
            releasedItem = true;
            categories.Scroll:takeFocus(event);
        end
    elseif event.phase == “ended” then
        releasedItem = true;
        local function navtothis()
            if(showdelete == false) then
                local options =
                {
                    effect = “slideLeft”,
                    time = 200,
                    params =
                    {
                        inventory = categories.currentIventory,
                        category = event.target.name
                    }
                }
                storyboard:gotoScene(“room_inventory_screen_small”, options);
            end
        end
        timer.performWithDelay(100, navtothis)
    end
end

categories.textlistener = function(event)
    print(event.phase)
    if(event.phase == “began”) then
        
    elseif(event.phase == “editting”) then
        
    elseif(event.phase == “submitted”) then
        local present = false
        if(categories.presentlist ~= nil) then
            for i = 1, #categories.presentlist do
                if(categories.presentlist[i] == textfield.text) then
                    present = true;
                    break;
                end
            end
        end
    
        if(present) then
            present = false
            native.showAlert(“Warning”, “This category is already present in your current inventory”, {“Close”})
        else
            database.addCategory(textfield.text, inventory.inventory)
            categories.newCat = widget.newButton
            {
                defaultFile = “images/category_screen_small/presentCat.png”,
                overFile = “images/category_screen_small/presentCatOver.png”,
                width = 540,
                height = 120,
                fontSize = 26,
                label = textfield.text,
                labelXOffset = 40,
                onEvent = catEvent
            }
            categories.newCat.id = “custom”
            categories.newCat.id_list = categories.idlist
            categories.newCat.name = textfield.text
            categories.newCat.x = _W / 2 - 20; categories.newCat.y = categories.presenty
            categories.presentlist[#categories.presentlist+1] = textfield.text
            categories.presenty = categories.presenty + categories.newCat.contentHeight + 10;
            categories.list[#categories.list+1] = categories.newCat
            categories.Scroll:insert(categories.newCat);
            categories.idlist = categories.idlist + 1
            hidekeyboard()
        end
    end
end

local function slideCat()
    if(categories.slide) then
        categories.slide = false;
        transition.to(categories.Group, {time = 100, y = categories.Group.y + 710})
    else
        categories.slide = true;
        transition.to(categories.Group, {time = 100, y = categories.Group.y - 710})
    end
    print("Category y " … categories.Group.y)
end

local function addCat(id)
    local present = false
    if(categories.presentlist ~= nil) then
        for i = 1, #categories.presentlist do
            if(categories.presentlist[i] == category_items[id]) then
                present = true;
                break;
            end
        end
    end
    if(present) then
        present = false
        native.showAlert(“Warning”, “This category is already present in your current inventory”, {“Close”})
    else
        database.addCategory(category_items[id], inventory.inventory)
        categories.newCat = widget.newButton
        {
            defaultFile = “images/category_screen_small/presentCat.png”,
            overFile = “images/category_screen_small/presentCatOver.png”,
            width = 540,
            height = 120,
            fontSize = 26,
            label = category_items[id],
            labelXOffset = 40,
            onEvent = catEvent
        }
        categories.newCat.id = id
        categories.newCat.id_list = categories.idlist
        categories.newCat.name = category_items[id]
        categories.newCat.x = _W / 2 - 20; categories.newCat.y = categories.presenty
        categories.presentlist[#categories.presentlist+1] = category_items[id]
        categories.presenty = categories.presenty + categories.newCat.contentHeight + 10;
        categories.list[#categories.list+1] = categories.newCat
        categories.idlist = categories.idlist + 1
        categories.Scroll:insert(categories.newCat);
    end
end

local function showCat(event)
    print(event.target.id)
    if(event.target.id == 1) then
        textfield = native.newTextField(0, 0, _W, 90)
        textfield:addEventListener (“userInput”, categories.textlistener)
        
        local newFont = 24
        
        if( display.contentScaleY < 1 ) then
            newFont =  newFont /display.contentScaleY
        end
        
        textfield.size = newFont
        native.setKeyboardFocus(textfield)
        screenGroup:insert(textfield);
        slideCat()
    else
        addCat(event.target.id)
        slideCat()
    end
end

local function createCategoryOption()
    categories.y = 200;
    categories.slide = false;
    categories.Group = display.newGroup();
    categories.bg = display.newImageRect(“images/category_screen_small/categorybg.png”, 480, 700)
    categories.bg.x = _W / 2; categories.bg.y = _H / 2
    categories.Group:insert(categories.bg);
    
    for i = 1, #category_items do
        local c_item = widget.newButton
        {
            defaultFile = “images/category_screen_small/categorylistbg.png”,
            overFile = “images/category_screen_small/categorylistbgOver.png”,
            width = 400,
            height = 80,
            font = native.systemFont,
            fontSize = 30,
            label = category_items[i],
            onRelease = showCat
        }
        c_item.x = _W / 2; c_item.y = categories.y
        c_item.id = i
        c_item.name = category_items;
        categories.y = categories.y + (c_item.contentHeight / 2) + 40
        categories.Group:insert(c_item);
    end
    categories.Group.y = categories.Group.y + 830
    screenGroup:insert(categories.Group);
end

function scene:createScene( event )
    screenGroup = self.view
    inventory = event.params
    categories.currentIventory = inventory.inventory
    categories.presenty = 90
    categories.presentlist = database.getCategory(inventory.inventory)
    
    navBar.bg = display.newImageRect(“images/navBar.png”, _W, 130)
    navBar.bg.x = _W / 2; navBar.bg.y = 65;
    
    navBar.text = display.newText(inventory.inventory, 0, 0, 450, 0, native.systemFont, 45)
    navBar.text:setReferencePoint(display.CenterReferencePoint)
    navBar.text:setTextColor(0, 0, 0)
    navBar.text.x = _W / 2 - 60; navBar.text.y = navBar.text.contentHeight / 2 + 10
    
    bg = display.newImageRect(“images/bg.png”, 640, 960);
    bg.x = _W / 2; bg.y = _H / 2;
    
    categories.Scroll = widget.newScrollView
    {
        top = 120,
        left = 20,
        width = 600,
        height = 650,
        scrollWidth = 600,
        scrollHeight = 650,
        maskFile = “images/mask.png”,
        horizontalScrollDisabled = true,
        hideBackground = true
    }
    categories.Scroll:addEventListener(“tap”, hidekeyboard);
    
    if(categories.presentlist) then
        for i = 1, #categories.presentlist do
            categories.newCat = widget.newButton
            {
                defaultFile = “images/category_screen_small/presentCat.png”,
                overFile = “images/category_screen_small/presentCatOver.png”,
                width = 540,
                height = 120,
                fontSize = 26,
                label = categories.presentlist[i],
                labelXOffset = 40,
                onEvent = catEvent
            }
            categories.newCat.id = i
            categories.newCat.id_list = categories.idlist
            categories.newCat.name = categories.presentlist[i]
            categories.newCat.x = _W / 2 - 20; categories.newCat.y = categories.presenty
            categories.presenty = categories.presenty + categories.newCat.contentHeight + 10;
            categories.list[#categories.list+1] = categories.newCat
            categories.idlist = categories.idlist + 1
            categories.Scroll:insert(categories.newCat);
        end
    end
    
    button.back_button = widget.newButton
    {
        defaultFile = “images/back.png”,
        overFile = “images/backOver.png”,
        width = 170,
        height = 90,
        label = “Back”,
        font = native.systemFont,
        labelYOffset = 60,
        fontSize = 28,
        onRelease = goback
    }
    button.back_button.x = _W / 3; button.back_button.y =  _H - 100;
    
    button.add_new = widget.newButton
    {
        defaultFile = “images/room_inventory_screen_small/add.png”,
        overFile = “images/room_inventory_screen_small/addOver.png”,
        width = 170,
        height = 90,
        label = “New Category”,
        font = native.systemFont,
        labelYOffset = 60,
        fontSize = 28,
        onRelease = slideCat
    }
    button.add_new.x = (_W / 3) + (_W / 3); button.add_new.y =  _H - 100;
    
    screenGroup:insert(bg);
    screenGroup:insert(categories.Scroll);
    screenGroup:insert(button.back_button);
    screenGroup:insert(navBar.bg);
    screenGroup:insert(navBar.text);
    screenGroup:insert(button.add_new);
    
    createCategoryOption()
    
    bg:addEventListener(“touch”, hidekeyboard);
end

function scene:enterScene( event )
    local prev = storyboard.getPrevious()
    storyboard.removeScene(prev)
    
end

function scene:exitScene( event )
    hidekeyboard()
    scene:removeEventListener( “createScene”, scene )
    scene:removeEventListener( “enterScene”, scene )
    scene:removeEventListener( “exitScene”, scene )
    scene:removeEventListener( “destroyScene”, scene )
end

function scene:destroyScene( event )
    
end

scene:addEventListener( “createScene”, scene )
scene:addEventListener( “enterScene”, scene )
scene:addEventListener( “exitScene”, scene )
scene:addEventListener( “destroyScene”, scene )

return scene

[/lua]

[/lua]

Hi @larryeh,

So essentially, the entire code works perfectly in “sample” but fails in “actual”? And you’re getting no error reports in the Terminal/console? Where exactly does it fail, at the “show alert” stage or the “dispatch” part? This is probably going to be tricky to nail down… I glance at the code and don’t see anything immediately wrong, so it might require a step-by-step debugging process to figure out exactly where it’s going wrong.

Brent

@Brent

Yes it seems that way. No error or anything from the terminal at all. It fails on “dispatch” the native alert is working fine. I guess I really have to debug this thoroughly. :expressionless:

Hi @larryeh,

May I ask why you’re setting an infinite timer of 1 millisecond on the “began” phase? Instead, can you just start one timer (of a slightly longer time), and if/when it executes, you manage the native popup? Or, if the user “releases” the button, just cancel the timer, so the popup won’t happen.

I just find that method firing a 1 millisecond timer 30 times in succession to be “unsetting” at the least. Timers aren’t really meant to be used that way, in general. :slight_smile:

Regards,

Brent

Whoops I posted a reply with a wrong account. I can’t delete this post so I’ll edit this.

Hello @Brent,

I did your recommendation but the app still crashed.

here is my new code

[lua]

local function onComplete(event)
    if(event.index == 1) then
        currentButton:removeSelf();
        currentButton = nil
    end
end
 
 
function t:timer( event )
    if releasedItem then
        timer.cancel(event.source);
        releasedItem = false;
    else
        showdelete = true;
        native.showAlert(“Warning”, “Are you sure you want to delete this item?”, {“Yes”,“No”}, onComplete)
    end
end
 
 
local function bEvent(event)
    if event.phase == “began” then
        currentButton = event.target
        timer.performWithDelay(500, t, 1);
    elseif event.phase == “moved” then
        local dx = math.abs( event.x - event.xStart )
        local dy = math.abs( event.y - event.yStart )
        if dx > 25 or dy > 25 then
            releasedItem = true;
        end
    elseif event.phase == “ended” then
        releasedItem = true;
    end
end

[/lua]

It really has something to do with the button staying at pressed state.

Hi @larryeh,

As I glance at the code, it appears you’re doing this (correct me if I’m wrong):

  1. When user touches the button (“began”), it starts the timer.

  2. If the user moves the touch more than 25 pixels from the start point, that’s like a “cancel action”.

  3. Same with the “ended” phase… if they don’t hold down for 500 ms, then the action is considered null and void.

If this is true, shouldn’t the timer just be cancelled in events #2 and #3 above? Directly when they occur, versus after the timer completes? I don’t know if that will solve the specific core issue that you mention, but that’s how I’d probably do it.

Now, let’s say it gets to the “alert” stage (user doesn’t move the touch point too much, and doesn’t lift up before 500 ms). I’d suggest that before you display the alert box, you dispatch a “fake ended” phase to the button listener using “dispatchEvent()” (link to the API doc below). This tells Corona that you want to treat the touch routine on the button as “ended” even if the user hasn’t actually lifted up the touch. Although not a common API, it’s useful in cases like these.

http://docs.coronalabs.com/api/type/EventListener/dispatchEvent.html

Try that, and see what happens.

Brent

P.S. - In your second implementation, does the app still crash after a few seconds?

Hello @Brent

Yes sir you got it right. Canceling the timer from event 2 and 3 is working ok. The problem only occurs after the alertShow appears. I tried using the dispatchEvent() you suggested but it doesn’t seem to be working. The button is still on pressed state. Is this correct implementation?

[lua]

local releasedItem = false
local t = {}
local currentButton
local button

local function onComplete(event)
    if(event.index == 1) then
        releasedItem = true
        currentButton:removeSelf();
        currentButton = nil
    else
        releasedItem = true
    end
end
 
function t:timer( event )
    if releasedItem then
        timer.cancel(event.source);
    else
        local myEvent = {name=“button”, phase = “ended”, target = currentButton}
        currentButton:dispatchEvent(myEvent)
        native.showAlert(“Warning”, “Are you sure you want to delete this item?”, {“Yes”,“No”}, onComplete)
    end
end
 
local function bEvent(event)
    print(event.phase)
    if event.phase == “began” then
        currentButton = event.target
        timer.performWithDelay(500, t, 1);
        releasedItem = false;
    elseif event.phase == “moved” then
        local dx = math.abs( event.x - event.xStart )
        local dy = math.abs( event.y - event.yStart )
        if dx > 25 or dy > 25 then
            releasedItem = true;
        end
    elseif event.phase == “ended” then
        releasedItem = true;
    end
end

button = widget.newButton{
    width = 100,
    height = 80,
    label = “button”,
    onEvent = bEvent
}
button.x = display.contentWidth / 2;button.y = display.contentHeight / 2;

[/lua]

Hi @larryeh,

Try setting the “name” parameter of the dispatch to “touch”… it’s supposed to equal the type of event you’re dispatching, so in this case a “touch ended” phase.

If things are still not quite working, you might also try showing the alert popup after a very short delay (like 30 ms) just to allow the event to resolve itself before showing the alert. Maybe it’s not necessary, but it’s worth trying if you’re still having issues.

Brent

@Brent

Okay I set the “name” parameter to “touch” and test it on my sample code. It worked, but when I try to implement it to my actual project code doesn’t seem to be working. I even placed the alert popup inside a timer delay just to make sure the event resolves itself but still no good. There’s probably something that blocks the dispatchEvent from performing but I don’t know what.

Here’s the sample code that I posted with the dispatchEvent() working.

[lua]

local releasedItem = false
local t = {}
local currentButton
local button

local function onComplete(event)
    if(event.index == 1) then
        releasedItem = true
        currentButton:removeSelf();
        currentButton = nil
    else
        releasedItem = true
    end
end
 
function t:timer( event )
    if releasedItem then
        timer.cancel(event.source);
    else
        local myEvent = {name=“touch”, phase = “ended”, target = currentButton}
        currentButton:dispatchEvent(myEvent)
        native.showAlert(“Warning”, “Are you sure you want to delete this item?”, {“Yes”,“No”}, onComplete)
    end
end
 
local function bEvent(event)
    print(event.phase)
    if event.phase == “began” then
        currentButton = event.target
        timer.performWithDelay(500, t, 1);
        releasedItem = false;
    elseif event.phase == “moved” then
        local dx = math.abs( event.x - event.xStart )
        local dy = math.abs( event.y - event.yStart )
        if dx > 25 or dy > 25 then
            releasedItem = true;
        end
    elseif event.phase == “ended” then
        print(“HEEY”)
        releasedItem = true;
    end
end

button = widget.newButton{
    width = 100,
    height = 80,
    label = “button”,
    onEvent = bEvent
}
button.x = display.contentWidth / 2;button.y = display.contentHeight / 2;

[/lua]

Now Here’s my actual project code:

[lua]

local storyboard = require( “storyboard” )
local scene = storyboard.newScene()
local widget = require"widget";
local database = require"database";

local _W = display.contentWidth;
local _H = display.contentHeight;

local screenGroup;
local textfield;

local bg;
local button = {}
local navBar = {}
local categories = {}
categories.list = {}
categories.idlist = 1
local category_items = {
    “Creat your own”,
    “Appliances”,
    “Baby related equipment”,
    “Electronics”,
    “Furnitures”,
    “Tools”,
    “Personal care”,
    “Apparel”
}
local t = {}

local catButtons = {}

local donotHide = true;

local releasedItem = false

local showdelete = false

local currentItem;
local currentObject;
local currentItem_id;
local currentItem_id_list;

local function hidekeyboard()
    if (textfield ~= nil and donotHide == false) then
        donotHide = true;
        textfield:removeSelf()
        textfield = nil
        native.setKeyboardFocus(nil)
    else
        donotHide = false;
    end
    if(categories.slide) then
        categories.slide = false;
        transition.to(categories.Group, {time = 100, y = categories.Group.y + 710})
    end
end

local function goback()
    storyboard.gotoScene( “create_inventory_screen_small”, “slideRight”, 200  )
end

local function onComplete(event)
    showdelete = false;
    if(event.index == 1) then
        database.deleteCategory(inventory.inventory, currentItem)
        local newy = 130
        local c_id = currentItem_id_list + 1
        categories.presenty = categories.presenty - newy;
        categories.presentlist[currentItem_id_list] = “”
        categories.list[currentItem_id_list]:removeSelf();
        categories.list[currentItem_id_list] = “”;
        for i = c_id, #categories.list do
            if(categories.list[i] ~= nil) then
                transition.to(categories.list[i], {time = 300, y = categories.list[i].y - newy})
            end
        end
        releasedItem = true
    end
end

function t:timer( event )
    if releasedItem then
        timer.cancel(event.source);
        releasedItem = false;
    else
        showdelete = true;
        local myEvent = {name=“touch”, phase=“ended”, target=currentObject}
        currentObject:dispatchEvent(myEvent)
        local function alertThis()
            native.showAlert(“Warning”, “Are you sure you want to delete this item?”, {“Yes”,“No”}, onComplete)
        end
        timer.performWithDelay(30, alertThis)
    end
end

local function catEvent(event)
    if event.phase == “began” then
        hidekeyboard()
        currentObject = event.target
        currentItem = event.target.name
        currentItem_id = event.target.id
        currentItem_id_list = event.target.id_list
        timer.performWithDelay(500, t, 1);
        releasedItem = false
    elseif event.phase == “moved” then
        local dx = math.abs( event.x - event.xStart )
        local dy = math.abs( event.y - event.yStart )
        if dx > 25 or dy > 25 then
            releasedItem = true;
            categories.Scroll:takeFocus(event);
        end
    elseif event.phase == “ended” then
        releasedItem = true;
        local function navtothis()
            if(showdelete == false) then
                local options =
                {
                    effect = “slideLeft”,
                    time = 200,
                    params =
                    {
                        inventory = categories.currentIventory,
                        category = event.target.name
                    }
                }
                storyboard:gotoScene(“room_inventory_screen_small”, options);
            end
        end
        timer.performWithDelay(100, navtothis)
    end
end

categories.textlistener = function(event)
    print(event.phase)
    if(event.phase == “began”) then
        
    elseif(event.phase == “editting”) then
        
    elseif(event.phase == “submitted”) then
        local present = false
        if(categories.presentlist ~= nil) then
            for i = 1, #categories.presentlist do
                if(categories.presentlist[i] == textfield.text) then
                    present = true;
                    break;
                end
            end
        end
    
        if(present) then
            present = false
            native.showAlert(“Warning”, “This category is already present in your current inventory”, {“Close”})
        else
            database.addCategory(textfield.text, inventory.inventory)
            categories.newCat = widget.newButton
            {
                defaultFile = “images/category_screen_small/presentCat.png”,
                overFile = “images/category_screen_small/presentCatOver.png”,
                width = 540,
                height = 120,
                fontSize = 26,
                label = textfield.text,
                labelXOffset = 40,
                onEvent = catEvent
            }
            categories.newCat.id = “custom”
            categories.newCat.id_list = categories.idlist
            categories.newCat.name = textfield.text
            categories.newCat.x = _W / 2 - 20; categories.newCat.y = categories.presenty
            categories.presentlist[#categories.presentlist+1] = textfield.text
            categories.presenty = categories.presenty + categories.newCat.contentHeight + 10;
            categories.list[#categories.list+1] = categories.newCat
            categories.Scroll:insert(categories.newCat);
            categories.idlist = categories.idlist + 1
            hidekeyboard()
        end
    end
end

local function slideCat()
    if(categories.slide) then
        categories.slide = false;
        transition.to(categories.Group, {time = 100, y = categories.Group.y + 710})
    else
        categories.slide = true;
        transition.to(categories.Group, {time = 100, y = categories.Group.y - 710})
    end
    print("Category y " … categories.Group.y)
end

local function addCat(id)
    local present = false
    if(categories.presentlist ~= nil) then
        for i = 1, #categories.presentlist do
            if(categories.presentlist[i] == category_items[id]) then
                present = true;
                break;
            end
        end
    end
    if(present) then
        present = false
        native.showAlert(“Warning”, “This category is already present in your current inventory”, {“Close”})
    else
        database.addCategory(category_items[id], inventory.inventory)
        categories.newCat = widget.newButton
        {
            defaultFile = “images/category_screen_small/presentCat.png”,
            overFile = “images/category_screen_small/presentCatOver.png”,
            width = 540,
            height = 120,
            fontSize = 26,
            label = category_items[id],
            labelXOffset = 40,
            onEvent = catEvent
        }
        categories.newCat.id = id
        categories.newCat.id_list = categories.idlist
        categories.newCat.name = category_items[id]
        categories.newCat.x = _W / 2 - 20; categories.newCat.y = categories.presenty
        categories.presentlist[#categories.presentlist+1] = category_items[id]
        categories.presenty = categories.presenty + categories.newCat.contentHeight + 10;
        categories.list[#categories.list+1] = categories.newCat
        categories.idlist = categories.idlist + 1
        categories.Scroll:insert(categories.newCat);
    end
end

local function showCat(event)
    print(event.target.id)
    if(event.target.id == 1) then
        textfield = native.newTextField(0, 0, _W, 90)
        textfield:addEventListener (“userInput”, categories.textlistener)
        
        local newFont = 24
        
        if( display.contentScaleY < 1 ) then
            newFont =  newFont /display.contentScaleY
        end
        
        textfield.size = newFont
        native.setKeyboardFocus(textfield)
        screenGroup:insert(textfield);
        slideCat()
    else
        addCat(event.target.id)
        slideCat()
    end
end

local function createCategoryOption()
    categories.y = 200;
    categories.slide = false;
    categories.Group = display.newGroup();
    categories.bg = display.newImageRect(“images/category_screen_small/categorybg.png”, 480, 700)
    categories.bg.x = _W / 2; categories.bg.y = _H / 2
    categories.Group:insert(categories.bg);
    
    for i = 1, #category_items do
        local c_item = widget.newButton
        {
            defaultFile = “images/category_screen_small/categorylistbg.png”,
            overFile = “images/category_screen_small/categorylistbgOver.png”,
            width = 400,
            height = 80,
            font = native.systemFont,
            fontSize = 30,
            label = category_items[i],
            onRelease = showCat
        }
        c_item.x = _W / 2; c_item.y = categories.y
        c_item.id = i
        c_item.name = category_items;
        categories.y = categories.y + (c_item.contentHeight / 2) + 40
        categories.Group:insert(c_item);
    end
    categories.Group.y = categories.Group.y + 830
    screenGroup:insert(categories.Group);
end

function scene:createScene( event )
    screenGroup = self.view
    inventory = event.params
    categories.currentIventory = inventory.inventory
    categories.presenty = 90
    categories.presentlist = database.getCategory(inventory.inventory)
    
    navBar.bg = display.newImageRect(“images/navBar.png”, _W, 130)
    navBar.bg.x = _W / 2; navBar.bg.y = 65;
    
    navBar.text = display.newText(inventory.inventory, 0, 0, 450, 0, native.systemFont, 45)
    navBar.text:setReferencePoint(display.CenterReferencePoint)
    navBar.text:setTextColor(0, 0, 0)
    navBar.text.x = _W / 2 - 60; navBar.text.y = navBar.text.contentHeight / 2 + 10
    
    bg = display.newImageRect(“images/bg.png”, 640, 960);
    bg.x = _W / 2; bg.y = _H / 2;
    
    categories.Scroll = widget.newScrollView
    {
        top = 120,
        left = 20,
        width = 600,
        height = 650,
        scrollWidth = 600,
        scrollHeight = 650,
        maskFile = “images/mask.png”,
        horizontalScrollDisabled = true,
        hideBackground = true
    }
    categories.Scroll:addEventListener(“tap”, hidekeyboard);
    
    if(categories.presentlist) then
        for i = 1, #categories.presentlist do
            categories.newCat = widget.newButton
            {
                defaultFile = “images/category_screen_small/presentCat.png”,
                overFile = “images/category_screen_small/presentCatOver.png”,
                width = 540,
                height = 120,
                fontSize = 26,
                label = categories.presentlist[i],
                labelXOffset = 40,
                onEvent = catEvent
            }
            categories.newCat.id = i
            categories.newCat.id_list = categories.idlist
            categories.newCat.name = categories.presentlist[i]
            categories.newCat.x = _W / 2 - 20; categories.newCat.y = categories.presenty
            categories.presenty = categories.presenty + categories.newCat.contentHeight + 10;
            categories.list[#categories.list+1] = categories.newCat
            categories.idlist = categories.idlist + 1
            categories.Scroll:insert(categories.newCat);
        end
    end
    
    button.back_button = widget.newButton
    {
        defaultFile = “images/back.png”,
        overFile = “images/backOver.png”,
        width = 170,
        height = 90,
        label = “Back”,
        font = native.systemFont,
        labelYOffset = 60,
        fontSize = 28,
        onRelease = goback
    }
    button.back_button.x = _W / 3; button.back_button.y =  _H - 100;
    
    button.add_new = widget.newButton
    {
        defaultFile = “images/room_inventory_screen_small/add.png”,
        overFile = “images/room_inventory_screen_small/addOver.png”,
        width = 170,
        height = 90,
        label = “New Category”,
        font = native.systemFont,
        labelYOffset = 60,
        fontSize = 28,
        onRelease = slideCat
    }
    button.add_new.x = (_W / 3) + (_W / 3); button.add_new.y =  _H - 100;
    
    screenGroup:insert(bg);
    screenGroup:insert(categories.Scroll);
    screenGroup:insert(button.back_button);
    screenGroup:insert(navBar.bg);
    screenGroup:insert(navBar.text);
    screenGroup:insert(button.add_new);
    
    createCategoryOption()
    
    bg:addEventListener(“touch”, hidekeyboard);
end

function scene:enterScene( event )
    local prev = storyboard.getPrevious()
    storyboard.removeScene(prev)
    
end

function scene:exitScene( event )
    hidekeyboard()
    scene:removeEventListener( “createScene”, scene )
    scene:removeEventListener( “enterScene”, scene )
    scene:removeEventListener( “exitScene”, scene )
    scene:removeEventListener( “destroyScene”, scene )
end

function scene:destroyScene( event )
    
end

scene:addEventListener( “createScene”, scene )
scene:addEventListener( “enterScene”, scene )
scene:addEventListener( “exitScene”, scene )
scene:addEventListener( “destroyScene”, scene )

return scene

[/lua]

[/lua]

Hi @larryeh,

So essentially, the entire code works perfectly in “sample” but fails in “actual”? And you’re getting no error reports in the Terminal/console? Where exactly does it fail, at the “show alert” stage or the “dispatch” part? This is probably going to be tricky to nail down… I glance at the code and don’t see anything immediately wrong, so it might require a step-by-step debugging process to figure out exactly where it’s going wrong.

Brent