I need push new screen automatic on app startup (if user is login or sign out).
I am use scoped_model for auth so need navigate when user value is change in model.
I am follow Brian Egan suggestion here: https://github.com/brianegan/scoped_model/issues/43#issuecomment-442444143
class LoginScreenState extends State<LoginScreen> {
#override
void didChangeDependencies() {
ScopedModel.of<AuthModel>(context).addListener(_navigationListener);
super.didChangeDependencies();
}
#override
void dispose() {
ScopedModel.of<AuthModel>(context)
.removeListener(_navigationListener);
super.dispose();
}
void _navigationListener() {
switch (ScopedModel.of<AuthModel>(context).AuthStatus) {
case AuthStatus.NotAuth:
Navigator.of(context).pushNamed(‘/Login’);
break;
case AuthStatus.Auth:
Navigator.of(context).pushNamed(‘/Main’);
break;
case AuthStatus.Register:
Navigator.of(context).pushNamed(‘/Register’);
break;
}
AuthStatus is Enum. I change value in Model.
This is push route correct, but have issue:
Same route is push many times. For example, same Login page is push at least 5 times.
How to stop Navigator from push same screen multiple times?
Thanks!
In Brian Egan's example he had a boolean test in the _navigationListener method. His comment was:
// This function will be run every time the model changes! We will use it to
// check the navigate boolean. If it's set to true, we'll push a new screen!
//
// If not, we won't do anything.
So, a similar boolean needs to be used in your code to only navigate once despite how many times the method is called.
Related
Is it possible to use flutter to keep the notification badge on the app icon even after opening and closing the app? Ex.: user has a badge of value 6, opens app to read one message, closes app, badge now reads as 5.
How do I achieve this functionality? (Specifically looking for iOS solution, but also interested in hearing about Android side if you have tips)
One way of achieving this is using the flutter_app_badger package, which allows you to set the app badge using the updateBadgeCount function. The trick is that you need to call this function at least once when your app is in the foreground before the app is put to the background or closed. One way to do this is to extend WidgetsBindingObserver and override didChangeAppLifecycleState in one of your widgets at the top of the widget tree:
class HomeScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
print("app in resumed");
if (PushNotificationsManager.appBadgeSupported) {
FlutterAppBadger.updateBadgeCount(14);
}
break;
case AppLifecycleState.inactive:
print("app in inactive");
break;
case AppLifecycleState.paused:
print("app in paused");
break;
case AppLifecycleState.detached:
print("app in detached");
break;
}
}
}
The app badge will not persist by itself, which is why you need to call this function at least once each time your app is in the foreground and a great place to do that is in didChangeAppLifecycleState when AppLifecycleState changes. If you call updateBadgeCount in the AppLifecycleState.resumed state like above, you'll also need to call updateBadgeCount once when your app starts (you can do this in the init function of a class like PushNotificationsManager if you have one, otherwise just do it in one of your widgets init function).
You can also put updateBadgeCount in the other states like AppLifecycleState.inactive or AppLifecycleState.paused, which will work in most cases but be cautious about this because if the app is closed/terminated without the inactive or paused state triggering, then the app badge will not be updated because the updateBadgeCount function is not called.
For completeness: when your app is closed or in the background, you can update your app badge using Apple Push Notification service. Include the badge number in the payload, as shown here. Then when the user opens your app, the code above will execute and the badge number will be updated again so that when the user closes the app or the app goes into the background, the badge number will "persist" as seen by the user.
More about WidgetsBindingObserver and how to detect if app is in foreground/background here.
Suppose, I have a StatefulWidget, which periodically requests data from a server and this updates its state.
I prepared a Timer.periodic() to make the data get loaded off the main loop.
Now, if the widget leaves the screen, the Timer continues to call its callback.
What is the correct mount point to perform cleanup actions, when the widget get off the screen?
You have to overwrite deactivate() of the State<StatefulWidgeet>:
#override
void deactivate() {
super.deactivate();
...
}
See Flutter docs.
I'm wondering if anyone has figured out a way to properly handle timeouts in the JavaFX 8 (jdk 1.8.0_31) WebView. The problem is the following:
Consider you have an instance of WebView and you tell it to load a specific URL. Furthermore, you want to process the document once it's loaded, so you attach a listener to the stateProperty of the LoadWorker of the WebEngine powering the web view. However, a certain website times out during loading, which causes the stateProperty to transition into Worker.State.RUNNING and remain stuck there.
The web engine is then completely stuck. I want to implement a system that detects a timeout and cancels the load. To that end, I was thinking of adding a listener to the progressProperty and using some form of Timer. The idea is the following:
We start a load request on the web view. A timeout timer starts running immediately. On every progress update, the timer is reset. If the progress reaches 100%, the timer is invalidated and stopped. However, if the timer finishes (because there are no progress updates in a certain time frame we assume a time out), the load request is cancelled and an error is thrown.
Does anyone know the best way to implement this?
Kind regards
UPDATE
I've produced a code snippet with behavior described in the question. The only thing still troubling me is that I can't cancel the LoadWorker: calling LoadWorker#cancel hangs (the function never returns).
public class TimeOutWebEngine implements Runnable{
private final WebEngine engine = new WebEngine();
private ScheduledExecutorService exec;
private ScheduledFuture<?> future;
private long timeOutPeriod;
private TimeUnit timeOutTimeUnit;
public TimeOutWebEngine() {
engine.getLoadWorker().progressProperty().addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
if (future != null) future.cancel(false);
if (newValue.doubleValue() < 1.0) scheduleTimer();
else cleanUp();
});
}
public void load(String s, long timeOutPeriod, TimeUnit timeOutTimeUnit){
this.timeOutPeriod = timeOutPeriod;
this.timeOutTimeUnit = timeOutTimeUnit;
exec = Executors.newSingleThreadScheduledExecutor();
engine.load(s);
}
private void scheduleTimer(){
future = exec.schedule(TimeOutWebEngine.this, timeOutPeriod, timeOutTimeUnit);
}
private void cleanUp(){
future = null;
exec.shutdownNow();
}
#Override
public void run() {
System.err.println("TIMED OUT");
// This function call stalls...
// engine.getLoadWorker().cancel();
cleanUp();
}
}
I don't think that you can handle timeouts properly now. Looks at this method. As you can see it has hardcoded value for setReadTimeout method. Is it mean that SocketTimeoutException exception will be raised after one hour of loading site. And state will be changed to FAILED only after that event.
So, you have only one way now: try to hack this problem use Timers as you described above.
P.S.
Try to create issue in JavaFX issue tracker. May be anyone fixed it after 5 years...
I have the same problem and used a simple PauseTransition. Same behavior, not so complicated. =)
how to kill a thread in blackberry.
I am using below code in which i want to kill a thread when dialog popup.
On first time login failed it is working properly but on second time login failed it returns RunTimeException.
public void onAuthFailed(String message) {
//this.invokeAndWait(new NotifyDialog("Please enter correct username and password"));
UiApplication.getUiApplication().invokeLater(new Runnable(){
public void run(){
Dialog.alert("Please enter correct username and password.");
UiApplication.getUiApplication().pushScreen(loginscreen);
}
});
}
Code you posted is not dedicated to kill a thread. It will display a new screen. And I thing you are trying to display a screen object, that is already displayed. I. e loginscreen instance is already displayed. If loginscreen is not displayed, then there's confict (event lock) between new dialog box and screen to be displayed. Display dialog box and screen in different threads.
Check this tutorial: http://www.javabeginner.com/learn-java/java-threads-tutorial
I think it will help.
In my app I have a BrowserField2 loading different pages and I want to show a simple spinning progressbar/indicator. As simple as possible really, without percent etc. - just a small animation to indicate to the user that something is happening.
I come from Android development and there such a thing is called Progressbar, though for Blackberry it maybe is called something completely different? (Progressbar for Blackberry seems to always include calculating the progress made).
What should I be looking for?
I solved it in a rather unorthodox way, something I probably wouldn't recommend ANYONE but I'll write it anyway since maybe it will help someone who's in a hurry to get it done. Just remember this is a bad way of doing it.
My app basically consists of 4 buttons and a browserfield.
To display a spinning "load animation" I use alishaik786's tip (see his comments) of the custom PopupScreen triggered by a browserfieldlistener:
// BrowserFieldListener to catch when a page started loading and when it is finished
BrowserFieldListener listener = new BrowserFieldListener() {
public void documentCreated(BrowserField browserField, ScriptEngine scriptEngine, Document document) throws Exception{
displayLoadAnimation();
// see method below
}
public void documentLoaded(BrowserField browserField, Document document) throws Exception{
try{
popUp.close();
}catch(IllegalStateException es){
es.printStackTrace();
}
}
};
// The method for showing the popup
private void displayLoadAnimation(){
popUp = new LoadingPopupScreen();
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().pushScreen(popUp);
}
});
}
Then in my custom PopupScreen I check where the user is clicking in "protected boolean touchEvent(TouchEvent event)" by checking event.getGlobalY() & event.getGlobalX() of the touch and comparing it to the positions of the buttons. If the user presses within the X&Y of a button then the popup screen is closed and I trigger the button being pressed.
As I said this is a bad way of doing it (many things need to be static), but it works if you want a quick and dirty sollution.