Jetpack compose `navController.popBackStack()` is not working with arguments - android-jetpack-compose

lets say I have 3 screens named A,B and C.
I can navigate to B from A and navigate to C from B.
when I want to navigate to B from A I dont have any argument to pass to B.
but when I want to get back into B while I am in C I might pass an argument.
my problem is when im in C and I want to back to B,navController.popBackStack is not working.
here is my NavHost:
val navigationController = rememberNavController()
NavHost(
navController = navigationController,
startDestination = Screen.Intro.name
) {
composable(
route = "B?countryCode={countryCode}",
arguments = listOf(navArgument("countryCode") {
nullable = true
type = NavType.StringType
defaultValue = null
})
) { navBackStack ->
val countryCode: String? =
navBackStack.arguments?.getString("countryCode")
B(navigationController, countryCode)
}
and here is navigationController.popBackStack() when I want to back to Bwhile im in C:
val backStackRoute = if (chosenCountry == null) "B"
else "B?countryCode=${chosenCountry.code}"
navigationController.popBackStack(
route = backStackRoute,
inclusive = false
)
when I press the Button which is responsible for going back to B nothing happens and I get this log:
I/NavController: Ignoring popBackStack to destination -1599746084 as it was not found on the current back stack
any idea why this is happening?

Related

Removing all items from Lua table in C

Is it possible to quickly remove all items from a Lua table in C without manually removing all items individually?
I know, I can do that in Lua by simply saying
t = {}
but I'm specifically looking for a solution in C that removes all items from a table that is somewhere on the stack.
It is often inappropriate to change something idiomatic of a language, for the sake of those unfamiliar.
If you want to make a clear that does the same as t={} you can use lua_replace.
emptying a table and t={} are not the same thing.
to illustrate:
local tab1 = {1,2,3,4,5}
local tab2 = tab1
function clear(t)
for k in pairs(t) do
t[k] = nil
end
end
clear(tab2)
for k, v in pairs(tab1) do
print(k, v)
end
This results in no values in tab1. This is because tab1 and tab2 reference the same table so changes made to tab2 are reflected in tab1.
local tab1 = {1,2,3,4,5}
local tab2 = tab1
tab2 = {}
for k, v in pairs(tab1) do
print(k, v)
end
Here we get
1 1
2 2
3 3
4 4
5 5
this is because tab2 was pointed to another table and did not alter the table it was previously referenced to.
If you wanted to do the first example in the c api you could do it like this:
/* name: clear
* function(t) */
static int lcf1_clear (lua_State * L) {
enum { lc_nformalargs = 1 };
lua_settop(L,1);
/* for k in pairs(t) do
* internal: local f, s, var = explist */
enum { lc1 = 1 };
lua_getfield(L,LUA_ENVIRONINDEX,"pairs");
lua_pushvalue(L,1);
lua_call(L,1,3);
while (1) {
/* internal: local var_1, ..., var_n = f(s, var)
* if var_1 == nil then break end
* var = var_1 */
lua_pushvalue(L,-3);
lua_pushvalue(L,-3);
lua_pushvalue(L,-3);
lua_call(L,2,1);
if (lua_isnil(L,-1)) {
break;
}
lua_pushvalue(L,-1);
lua_replace(L,-3);
/* internal: local k with idx 5 */
/* t[k] = nil */
lua_pushnil(L);
lua_pushvalue(L,5);
lua_insert(L,-2);
lua_settable(L,1);
assert(lua_gettop(L) == 5);
/* internal: stack cleanup on scope exit */
lua_pop(L,1);
}
lua_settop(L,lc1);
assert(lua_gettop(L) == 1);
return 0;
}
This was generated using lua2c for lua 5.1, it is something that could use some improvement but to get the general idea of how to do something in the c api it works, and it can be a helpful tool for getting some understanding.
that all said again I strongly suggest you dont change something idiomatic like this.

Computercraft function that returns an array, use first element for boolean

Edited for more details:
I'm trying to have a turtle that is sitting in front of a sapling wait for it to grow before cutting it down. It compares the log to the item in front until it matches. The system I'm currently using works, but I was hoping there was a slightly more minimal way to write it.
checkTarget = {
forward = function(tgt)
check = {turtle.inspect()} --creates table with first as boolean, second as information table
local rtn = {false, check[2]}
if type(tgt) == "table" then
for k, v in pairs(tgt) do
if check[2].name == v then
rtn = {true, v}
break
end
end
elseif tgt == nil then
return check[1]
elseif check[2].name == tgt then
rtn[1] = true
end
return rtn
end,--continued
This takes an argument, either a string or an array of strings, to compare against. When it checks the block in front it saves the detailed information to the second element in rtn and the first to a default of false. If the string matches the checked block's name, then it changes rtn[1] to true and returns all of it, which is the table at the bottom when doing checkTarget.forward("minecraft:log").
My question was, I am currently making a disposable variable to store the array that is returned from checkTarget, and then calling the variable's first element to get if it's true or not. I was hoping there was a way to include it in the if statement without the disposable variable (tempV)
repeat
local tempV = fox.checkTarget.forward("minecraft:log")
if tempV[1] then
cut()
fox.goTo({x = 0, y = 0, z = 0})
fox.face(0)
end
tempV = fox.checkTarget.forward("minecraft:log")
until not run
{
false,
{
state = {
stage = 0,
type = "birch",
},
name = "minecraft:sapling",
metadata = 2
}
}
Instead of
local tempV = fox.checkTarget.forward("minecraft:log")
if tempV[1] then
end
You can do
if fox.checkTarget.forward("minecraft:log")[1] then
end
and then calling the variable's first element to get if it's true or
not.
With tempV[1] you're not calling the first element, you're indexing it.
To call something you have to use the call operator () which doesn't make sense as a boolean is not callable.

Lua: Get table value within itself [duplicate]

This question already has answers here:
Use table key inside same (anonymous) table
(2 answers)
Closed 5 years ago.
So I'm trying something which i think should be very easy, but I just can't get it to work...
Basically what I'm trying to do is:
myTable = {
a = 1,
b = a + 1
}
This is not working, I get the error that "a" is nil. Reasonable.
What i have already tried is
myTable = {
a = 1,
b = myTable.a + 1
}
and
myTable = {
a = 1,
b = self.a + 1
}
But it gives me the error me that "myTable"/"self" is nil.
I got the feeling that the solution is rather simple but i couldn't find it out by myself and google wasn't that helpful as well.
There's no way of doing this in one statement (at least not without calling any functions or using metatables). That's because in a statement like foo = bar, the foo variable isn't assigned until the bar expression has been evaluated.
In your second example, the myTable variable isn't assigned until the closing curly brace, so the myTable in myTable.a + 1 is treated as an unnassigned global variable, and gets a value of nil. The self in your third example is the same, only you don't try to assign anything to it later. (In Lua, self is only special inside functions written with the colon syntax.)
To do what you want to do, you have to do something like this:
myTable = {
a = 1
}
myTable.b = myTable.a + 1
Or this:
local a = 1
myTable = {
a = a,
b = a + 1
}

How to get variables that not declared yet but will declared soon?

How can I get variables that not declared yet?
Here are simple example:
a = b
b = 123
What I want from these 2 lines is a << 123. But obv it doesn't work.
I know the easy way to get the answer a = 123 is cut 1st line and paste it to lower than 2nd line.
But I'm in some problem. I need some function like 'WillDeclaredVar()' that I can use in like this:
a = WillDeclaredVar(b)
sheepCount = 123
b = sheepCount
print(a)
so I can get the answer '123'.
Or there are any built-in functions that will allows me to do similar thing?
===
I think the link given by timrau is not telling my case. the key point is how to get Variables 'that not declared yet'.
===
Adding actual Code:
triggerCount = 0 -- Counting number of 'Trigger' function
local Trigger = function (t)
triggerCount = triggerCount + 1
return Trigger (t)
end
-- following Triggers are same as while statement.
-- following Triggers doing: Add 1 MarineCount until get 64000 MarineCount
Trigger { -- Here the Trigger function. Now triggerCount = 1.
players = {P1}
actions = {
SetDeaths(P1, Add, 1, "Terran Marine")
},
flag = {preserved},
}
Portal(LoopStart);
-- function Portal(VariableName) returns VariableName = triggerCount. So LoopStart = 1.
Trigger { -- Now triggerCount = 2.
players = {P1}
actions = {
LinkList(LoopEnd, LoopStart);
-- function LinkList(From, To) changes 'From' Trigger's next pointer to the 'To' Trigger.
-- But now the problem happens. Because 'LoopEnd' is not declared yet.
},
flag = {preserved},
}
Trigger { -- Now triggerCount = 3.
players = {P1}
conditions = {
Deaths(P1, Exactly, 64000, "Terran Marine");
}
actions = {
_LinkList(LoopEnd);
-- Reset LoopEnd's next pointer(= LoopEscape) if MarineCount hits 64000
},
flag = {preserved},
}
Portal(LoopEnd); -- LoopEnd = 3.
Changing Order of Triggers will break the Trigger logic(while statement).
All i want is get easy to coding. To put in bluntly, I don't need to solve this problem(get undeclared var). I can imagine a few ways to avoid it. But if i using these ways then the coding work will be very complicated and the difficulty of coding will increases greatly. The difficulty made me stop coding in recent months.
How can I get variables that not declared yet?
Short of time travel, you can't.
Your example code doesn't explain the motivation for the question, because this:
a = WillDeclaredVar(b)
sheepCount = 123
b = sheepCount
print(a)
Can trivially be rearranged into this:
sheepCount = 123
b = sheepCount
a = WillDeclaredVar(b)
print(a)
It would be easier to answer your question if you showed the actual problem you're trying to solve (to avoid an XY problem).
However, as stated there are few things we can note.
First, you need to distinguish between declaring a variable and giving it a value. In Lua you can say:
local b
To declare b as a local variable, which presumably will make a slot for it in the stack frame and let you bind closures to it, before you give it a value. However, the line:
a = WillDeclaredVar(b)
Will pass WillDeclaredVar the value that b currently has, and there's no way for a to change retroactively as a result of b being assigned a new value. That's simply not going to happen, ever. Neither a nor WillDeclaredVar are even aware that b exists, they are receive the value it contains at the point of call.
You could however bind the variable b to a closure which will fetch b's current value when needed.
-- declare b before giving it a value, aka "forward reference"
local b
a = function() return b end
sheepCount = 123
b = sheepCount
print(a()) -- call a to get b's current value
Another way to do that would be to make b a global variable, which is really just a key into your environment table, so you could say:
a = WillDeclaredVar('b')
And have a be some object that can fetch the current value of __ENV['b'] when required.
However, neither of these will support this syntax:
print(a)
a needs to be a function, something that looks up the value of b when needed rather than simply holding a previously computed value. You could do it in this particular instance (i.e. a needs to be convertable to a string), by creating a proxy object that implements __tostring.
function WillDeclaredVar(variableName)
local proxy = { environment = _ENV or _G, variableName = variableName }
return setmetatable(proxy, {
__tostring = function(proxy)
return proxy.environment[proxy.variableName]
end
})
end
-- a will compute a value based on the current value of b when needed
a = WillDeclaredVar('b')
sheepCount = 123
b = sheepCount
print(a)
Output:
123
To make var1 be a reference for var2 write var1 = ReferenceF or var2 (please note a space inside "ReferenceFor"!)
do
local values, references, reference_flag = {}, {}
setmetatable(_G, {
__index = function (_, name)
if name == 'ReferenceF' then
reference_flag = true
elseif reference_flag then
reference_flag = false
return {[references] = name}
elseif references[name] then
return _G[references[name]]
else
return values[name]
end
end,
__newindex = function (_, name, val)
if type(val) == 'table' and val[references] then
references[name] = val[references]
else
values[name] = val
end
end
})
end
a = ReferenceF or b -- a is Reference For b
b = ReferenceF or c -- b is Reference For c
sheepCount = 123
c = sheepCount
print(a, b, c) --> 123 123 123

Lua Insert table to table

Basic table, how they should be. But me need do it by function, how i can do that?
local mainMenu = {
caption = "Main Window",
description = "test window",
buttons = {
{ id = 1, value = "Info" },
{ id = 2, value = "Return" },
{ id = 3, value = "Ok" },
{ id = 4, value = "Cancel" }
},
popup = true
}
Table should be based on outside params, and code one table for each variable of options - not better way. I make a function for that, they should create basic options like caption or description and pop up, and insert values to buttons table (if option enabled - add button). But here the problem, they wont insert to tmp table, buttons table and their values for next options.
function createMenu()
tmp = {}
--buttons insert
if(config.info) then
table.insert(tmp, {buttons = {id = 1, value = "Info"}});
elseif(config.return) then
table.insert(tmp, {buttons = {id = 2, value = "Return"}});
end
--table main
table.insert(tmp, {
caption = "Main Window",
description = "test window",
popup = true
})
return tmp
end
How i can fixing them?
From looking at your createMenu function, two obvious problems stick out:
assigning to global tmp a new table every time createMenu is
called.
using the return keyword as a key in config.
One can be a problem if you use tmp somewhere else in your code outside the createMenu function. The obvious fix is to change it to:
local tmp = {}
For the second problem, you can use a lua keyword as a table key if you really want but you won't be able to use the . dot syntax to access this since Lua will parse this the wrong way. Instead, you need to change:
config.return
to
config["return"].
Edit: After reading your comment and checking the example table, it looks like only the button table is accessed by numerical index. In that case, you'll want to use table.insert only on button. If you want to create the table to have associative keys then you'll have to do something like this:
function createMenu()
local tmp =
{
--table main
caption = "Main Window",
description = "test window",
popup = true,
--button table
buttons = {}
}
--buttons insert
if config.info then
table.insert(tmp.buttons, {id = 1, value = "Info"});
elseif config['return'] then
table.insert(tmp.buttons, {id = 2, value = "Return"});
end
return tmp
end
This will produce the mainMenu table you're describing in your question.

Resources