Skip to main content
Dfarr.1
Associate III
March 25, 2021
Solved

Call goto screen transition function from presenter>activate()

  • March 25, 2021
  • 21 replies
  • 4969 views

I'm trying to redirect away from a screen during activate() based on some model state information before anything is shown on screen. But I've only managed to get it working on some screens and not others even though I'm following the same pattern everywhere (call function defined in modelListener>call model defined function> call FrontEndApplication::gotoScreenNoTransition() ).

I feel like I'm missing something here. Is there an intended way to do this?

This topic has been closed for replies.
Best answer by Dfarr.1

I've pinpointed the problem. And settled on a solution for the time being.

This is a limit imposed by tGFX. You cannot make "nested" screen transition calls because the screen transition handler only stores a single pointer to represent the active/pending transition. You can't then change that pointer in the middle of a transition. I suspect this would have had to have been implemented as a stack to get around this limitation.

The problem is that I'm requesting a screen transition before the active pendingScreenTransitionCallback->execute(); has terminated. Once that call terminates, and before evaluatePendingScreenTransition() gets a chance to evaluate my newly submitted screen transition function pointer, the pointer gets cleared. presenter.activate() and view.setupScreen() are called by the screen transition execute(), so any transitions requested inside those two functions will get wiped out and ignored when the screen transition terminates.

The solution I chose:

define actions in each screen which is an entry point to the password protected screen.

override those actions in the view and test the authentication state of the model before calling the appropriate screen transition.

This means I have several screens where this logical test is being performed. But its the only way I found to perform the redirect before drawing the intermediate screen at all.

There was 1 special case, which was the password protected screen itself. I have implemented a stack for navigating between screens and returning to previous screens. I store function pointers to the gotoScreenNoTransition() functions from FrontEndApplication on this stack. So if I my protected screen is the "previous screen" and gets popped off the stack, the authentication check doesn't happen because that gotoScreenNoTransition() call is way above my overriden view action in the object hierarchy. I've had to compromise and use the "Screen is Entered" trigger on an interaction and tolerate the brief flash of the protected screen before it redirects to login. Not ideal.

I will definitely consider the ModalWindow widget next time I implement something like this.

21 replies

Alexandre RENOUX
Visitor II
March 25, 2021

Hello Dfarr.1,

If you want to change screen according the state of the Model before the current screen is displayed. An easier and probably safer way to do it is to get the current state of the Model in your ScreenView using the MVP concept and then perform the screen transition accordingly either in the constructor of ScreenView or in the initialize function before calling ScreenViewBase::initialize().

/Alexandre

Dfarr.1
Dfarr.1Author
Associate III
March 25, 2021

It was my understanding that the view isn't intended to "pull" data from the model. Nor should the view store data other than what it's currently displaying. As created by designer, the view doesn't actually have a handle to the model. The view doesn't even have a presenter handle it can use to daisy chain function calls down into the model to request state information.

I don't think I follow what you mean.

Alexandre RENOUX
Visitor II
March 25, 2021

Hello Dfarr.1,

Please follow this tutorial and you should understand that the View can definitely request info from the Model through the Presenter. That's the core of the MVP concept.

/Alexandre

Dfarr.1
Dfarr.1Author
Associate III
March 25, 2021

I just found the presenter handle in the view. I haven't been using it!

My application relies on hardware events passed to the presenter which cause model state changes which are then bubbled up to the View. I haven't yet needed the view to drive model changes, nor directly request model state (no touch screen, all hardbuttons). I've only been using the presenter in one direction!

I've been initializing my views in the presenter activate() function, which is why I started there to create the screen redirect behavior.

I've now created a presenter function, called it from the view to retrieve the model state during view.SetupScreen(). Then it calls application().gotoScreenNoTransition(). But this still doesn't cause a screen transition. Am I missing a step?

Alexandre RENOUX
Visitor II
March 25, 2021

For faster support, could you enclose your project ?

/Alexandre

Dfarr.1
Dfarr.1Author
Associate III
March 25, 2021

Unfortunately no.

Dfarr.1
Dfarr.1Author
Associate III
March 25, 2021

That tutorial suggests creating interactions from designer to trigger screen transitions. Its geared squarely towards touchscreen applications (which mine is not). Do you have a code example of a screen transition triggered from a view?

I'm getting the feeling my problem is that I'm requesting a screen transition while the transition onto the current screen is still in progress. But that's just a hunch.

Alexandre RENOUX
Visitor II
March 25, 2021

Hello Dfarr.1,

You need to use the action and trigger concept.

You create an action called changeScreen for instance and then you create an interaction that is triggered when this action is called. This interaction will initiate the screen transition. Then you just need to call changeScreen() in your View according to the state you received from the model.

0693W000008xqy8QAA.png 

/Alexandre

Dfarr.1
Dfarr.1Author
Associate III
March 25, 2021

Ok I created an action to trigger a change screen interaction in the designer. I'm calling that action in the view based on model state. This still doesn't cause a screen transition. No surprise really, since the interaction simply wraps application().gotoScreenNoTransition() which is what I was calling in my last attempt.

I can make screen transitions from just about anywhere without issue. Except presenter.activate() and view.SetupScreen(). Is some special consideration required when executing screen transition from these locations?

Dfarr.1
Dfarr.1Author
Associate III
March 25, 2021
void MasterEditConfigView::setupScreen()
{
 if (!presenter->Authenticate())
 {
 //not logged in yet. Change screens
 GoTo_MasterEditLogin();
 }
 
...
}

the presenter function simply retrieves a bool value from the model.

Dfarr.1
Dfarr.1Author
Associate III
March 25, 2021

To clarify, my action is GoTo_MasterEditLogin(). Its linked to an interaction that causes the screen transition I want. I've used this elsewhere in my application without issue, its definitely working properly. Except I don't see a screen transition when calling it from inside view.SetupScreen().

Alexandre RENOUX
Visitor II
March 25, 2021

Hello Dfarr.1,

Yes indeed maybe in setupScreen it's not possible but I need to investigate to confirm that. So in the meantime let's forget about this method. There's another one but I need more info on your UI concept.

I believe you don't need to prevent a screen from being displayed. So please could you provide more information ?

/Alexandre

Dfarr.1
Dfarr.1Author
Associate III
March 25, 2021

I'm implementing a basic login screen with persistence. If the user has logged in already this session, the login screen is bypassed and the screen is redirected to the password-protected screen without requiring re-login.

Similarly, the password-protected screen checks if the session is authenticated any time it loads. If not, it redirects away to the login screen to re-enter the password.

I was hoping to accomplish these redirects before drawing anything to the screen.

I've chosen to do it this way because there are multiple entry points into both the login screen and the password-protected screen. I could put the authentication check at each of those entry points instead, but its more code to maintain. If I can simply have the screen do the check before it draws, it would be centralized, easier to maintain. The authentication occurs where its actually needed, rather than on a handful of other screens that don't actually care about authentication.

MM..1
Super User
March 25, 2021

When you debug your call where is returned with ignore screen change?

And i create app without touchevents and dont use presenter completely...I use C memory struct variable to share between hw (other tasks), model, view.

Dfarr.1
Dfarr.1Author
Associate III
March 25, 2021

view.setupScreen() -> viewBase.action() -> application().gotoScreenNoTransition() -> FrontendApplicationBase::gotoScreenNoTransition

void FrontendApplicationBase::gotoMasterEditConfigScreenNoTransition()
{
 transitionCallback = touchgfx::Callback<FrontendApplicationBase>(this, &FrontendApplication::gotoMasterEditConfigScreenNoTransitionImpl);
 pendingScreenTransitionCallback = &transitionCallback;
}

Once the execution reaches this point, I don't see a change to the pendingScreenTransitionCallback variable if the screen transition is called from inside setupScreen(). transitionCallback does correctly contain the TransitionImpl. But 0x0 is stored to pendingScreenTransitionCallback,

If I call my action from anywhere else, pendingScreenTransitionCallback is set as expected to the function pointer of the TransitionImpl. But not when its called from inside view.setupScreen() or presenter.activate(). Code execution reaches that line (4), but the value isn't set. Its very strange. I feel like I'm overlooking something.

Later on MVPApplication rejects this screen transition pointer (0x0) as invalid, so no transition occurs.

 void evaluatePendingScreenTransition()
 {
 if (pendingScreenTransitionCallback && pendingScreenTransitionCallback->isValid())
 {
 pendingScreenTransitionCallback->execute();
 pendingScreenTransitionCallback = 0;
 }
 }

Dfarr.1
Dfarr.1Author
Associate III
March 25, 2021

I made a mistake. pendingScreenTransitionCallback is being set to the function pointer correctly.

But by the time evaluatePendingScreenTransition is reached, it has been set to 0x0.

I think what's happening is I'm calling a screen transition in the middle of another screen transition. And there's some cleanup code at the end of the screen transition execution that resets that function pointer when it ends. So the function pointer change I make during transition is wiped out before it gets a chance to be executed.

Dfarr.1
Dfarr.1Author
Associate III
March 25, 2021

Alright, I've tried another designer pathway for this problem. I've created an interaction which is triggered by "Screen is Entered". According to the documentation, this trigger actually fires when the screen transition is complete.

This works. It executes the screen transition I want. BUT, there's a visible flash of the view from which its called. I would much prefer not to draw the new screen at all until after this authentication has occurred.

Is it possible to suspend draw until after the "Screen is Entered" interaction is triggered?

MM..1
Super User
March 25, 2021

I mean use special screen for login and switch screens for this isnt best idea. Why you don use Modal window widget? ModalWindow | TouchGFX Documentation

Dfarr.1
Dfarr.1Author
Associate III
March 25, 2021

I understand. I will consider the use of a modal window.