React-native-navigation (wix) how to skip route - ios

I have 3 screens
ScreenA,
ScreenB,
ScreenC
Routes
ScreenA->ScreenB, ScreenB-back->ScreenA
ScreenA->ScreenC, ScreenC-back->ScreenA
ScreenA->ScreenB->ScreenC
My question is regarding 3rd route, when user is on ScreenC and he/she pressed backbutton/backnavbarbutton ScreenA will be shown instead of Screen B
Environment
React Native Navigation version: 1.1.431
React Native version: 0.54.4
Platform(s) (iOS, Android, or both?): iOS

You can use the setOnNavigatorEvent or the addOnNavigatorEvent which will replace the existing navigator for custom handling of back button..
so in your constructor
class ScreenC extends Component {
constructor(props) {
super(props);
this.props.navigator.setOnNavigatorEvent(
this.onNavigatorEvent.bind(this)
);
}
...
onNavigatorEvent(event) {
switch (event.id) {
case 'backPress':
... what ever you want
}
}
... rest of your code
}
You can read more about them here

Related

How can I Get Xamarin iOS Application to Automatically Sense Light and Dark Changes?

Someone here (thanks sushihangover!) helped me get my application to read the iOS Settings Dark or Light theme on command. I'm using Xamarin (not Forms). I also need the following (just for iOS):
iOS Settings Theme is Light
App is set to Automatic, so it uses current the iOS Settings Theme (Light)
App launched is Light
Home button press
Change iOS Settings to Dark
Bring app to foreground
App still look Light, but it should look Dark.
I realize the AppDelegate has a WillEnterForeground method, but I don't know how to wire that up so the App looks Dark when it comes to the foreground. I'm using MvvmCross. The following link looks promising.
https://forums.xamarin.com/discussion/181648/best-approach-to-handle-dark-theme
I don't understand how to apply the link's contents to my MvvmCross architecture.
Your help is appreciated!
Thanks!
Larry
The best way to react on application changes while using the MVVM pattern would be to implement a IThemeService interface as shown in your link.
xamarin forms iOS
But I think it's not possible to react to configuration changes in Xamarin.Forms.iOS plattform while using MvvmCross. I looked into the source code of the MvvmCross.Forms.iOS project and couldn't find any equivalent to the MvvmCross.Forms.Android setup methods like OnConfigurationChanged.
On Android you can easily refresh the app-theme while change the system theme in the MainActivity.
public class MainActivity : MvxFormsAppCompatActivity
{
public override void OnConfigurationChanged(Configuration newConfig)
{
base.OnConfigurationChanged(newConfig);
this.UpdateTheme(newConfig);
}
protected override void OnResume()
{
base.OnResume();
UpdateTheme(Resources.Configuration);
}
protected override void OnStart()
{
base.OnStart();
this.UpdateTheme(Resources.Configuration);
}
private void UpdateTheme(Configuration newConfig)
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.Froyo)
{
var uiModeFlags = newConfig.UiMode & UiMode.NightMask;
switch (uiModeFlags)
{
case UiMode.NightYes:
Mvx.IoCProvider.Resolve<IThemeService>().UpdateTheme(BaseTheme.Dark);
break;
case UiMode.NightNo:
Mvx.IoCProvider.Resolve<IThemeService>().UpdateTheme(BaseTheme.Light);
break;
default:
throw new NotSupportedException($"UiMode {uiModeFlags} not supported");
}
}
}
}
But in the AppDelegate on the iOS plattform, you don't have any of these functionalitys to override.
public class AppDelegate : MvxFormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
return base.FinishedLaunching(application, launchOptions);
}
}
I copied this code from this project.
native xamarin iOS
When you are using native iOS you could override the TraitCollectionDidChange method. It's the equivalent to the android OnConfigurationChanged function.
Maybee look here for more details. I adapted the android version to iOS for you. At First, you have to create a custom view controller.
// your supported theme versions
public enum BaseTheme
{
Inherit = 0,
Light = 1,
Dark = 2
}
public class MyViewController : UIViewController
{
public override void TraitCollectionDidChange(UITraitCollection previousTraitCollection)
{
base.TraitCollectionDidChange(previousTraitCollection);
if (TraitCollection.UserInterfaceStyle != previousTraitCollection.UserInterfaceStyle)
{
UpdateTheme(TraitCollection.UserInterfaceStyle);
}
}
private void UpdateTheme(UIUserInterfaceStyle newConfig)
{
switch(newConfig)
{
case UIUserInterfaceStyle.Dark:
Mvx.IoCProvider.Resolve<IThemeService>().UpdateTheme(BaseTheme.Dark);
break;
case UIUserInterfaceStyle.Light:
Mvx.IoCProvider.Resolve<IThemeService>().UpdateTheme(BaseTheme.Light);
break;
default:
throw new NotSupportedException($"UiMode {uiModeFlags} not supported");
}
}
}
I uploaded a project where I simplify coded an implementation for native IOS and android here. Complete and improve some things and it will work. Also look at the StarWars and TipCalc Project in the mvvmcross sample repo.
mvvmcross ioc
your interface structure could look like so;
IThemeService (base project) - ThemeService (base project) - ThemeService(iOS project)
And you have to register the interface of course.
Mvx.IoCProvider.RegisterSingleton<IThemeService>(() => new ThemeService());

Dialog causes drag done events to not propagate

I'm using a popup dialog during a drag and drop operation. When the drop happens a dialog pops up and when it is dismissed the event chain should continue and allow something to happen when the drag operation ends. If the popup dialog is FX then there is no problem but if it's Gluon the drag done operation doesn't happen.
Here is a sample code:
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Label;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DataFormat;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import com.gluonhq.charm.glisten.mvc.View;
public class MainView extends View {
HBox root;
public MainView(String name) {
super(name);
Label source = new Label("Source");
configureDragSource(source);
Label target = new Label("Target");
configureDragTarget(target);
Label popupTarget = new Label("Popup Target");
configureDragPopupTarget(popupTarget);
root = new HBox(40, source, target, popupTarget);
setCenter(root);
}
private void configureDragSource(Label source) {
source.setOnDragDetected(e -> {
root.setBackground(new Background(new BackgroundFill(Color.RED, null, null)));
Dragboard db = source.startDragAndDrop(TransferMode.ANY);
ClipboardContent content = new ClipboardContent();
content.put(DataFormat.PLAIN_TEXT, source.getText());
db.setContent(content);
});
source.setOnDragDone(e -> root.setBackground(new Background(new BackgroundFill(null, null, null))));
}
private void configureDragTarget(Label target) {
target.setOnDragOver(e -> e.acceptTransferModes(TransferMode.ANY));
}
private void configureDragPopupTarget(Label popupTarget) {
popupTarget.setOnDragOver(e -> e.acceptTransferModes(TransferMode.ANY));
popupTarget.setOnDragDropped(e -> {
javafx.scene.control.Alert popup1 = new javafx.scene.control.Alert(AlertType.INFORMATION);
com.gluonhq.charm.glisten.control.Alert popup2 = new com.gluonhq.charm.glisten.control.Alert(AlertType.INFORMATION);
popup1.showAndWait();
});
}
}
The source should be dragged upon which the background changes to red. When the drag operation is done the backgrounds should return to default. The regular drop target does nothing and the color change works. But when dropping on the popup target the dialog appears and when it is closed the color changes only for the FX dialog and not for the gluon dialog. Change popup1.showAndWait(); to popup2.
If important this is the application class
import com.gluonhq.charm.glisten.application.MobileApplication;
public class TestApplication extends MobileApplication {
#Override
public void init() {
addViewFactory(HOME_VIEW, () -> new MainView(HOME_VIEW));
}
public static void main(String[] args) {
launch(args);
}
}
and this is the gradle build file:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'org.javafxports:jfxmobile-plugin:1.3.5'
}
}
apply plugin: 'org.javafxports.jfxmobile'
apply plugin: 'eclipse'
jar {
manifest {
attributes 'Main-Class': 'com.test.TestApplication'
}
}
jfxmobile {
downConfig {
version = '3.3.0'
plugins 'display', 'lifecycle', 'statusbar', 'storage'
}
android {
compileSdkVersion = 19
// manifest = 'src/android/AndroidManifest.xml'
}
ios {
infoPList = file('src/ios/Default-Info.plist')
forceLinkClasses = [
'com.gluonhq.**.*',
'javax.annotations.**.*',
'javax.inject.**.*',
'javax.json.**.*',
'org.glassfish.json.**.*'
]
}
}
eclipse {
classpath {
downloadJavadoc = true
downloadSources = true
}
}
repositories {
jcenter()
maven {
url 'http://nexus.gluonhq.com/nexus/content/repositories/releases'
}
}
mainClassName = 'com.test.TestApplication'
dependencies {
compile 'com.gluonhq:charm:4.3.5'
}
task wrapper(type: Wrapper) {
gradleVersion = '4.2'
}
Happens also on compile 'com.gluonhq:charm:4.3.7' and 4.4.0.
Running on Java 8 b141. Why does this happen? Is this a bug?
JavaFX built-in dialogs and Gluon Dialogs are not the same. In fact, the latter extends from Layer, while being modal and blocking, like the former.
Running on Mac the posted code, I get a NPE after dropping over popupTarget, that can be easily solved using:
Platform.runLater(() -> popup2.showAndWait());
Also, given that the drag event is consumed by the dialog, a possible solution could be:
Platform.runLater(() ->
popup2.showAndWait()
.ifPresent(r ->
root.setBackground(new Background(new BackgroundFill(null, null, null)))));
So you could refactor the setOnDragDone method, and just create a method that could be called after the dialog is closed as well.
EDIT
These are the drag events that both target and source receive once the dnd event has started:
The target receives these events on a drag and drop gesture:
DRAG_OVER
DRAG_OVER
... // until drop is done:
// show Dialog
...
// hide Dialog
DRAG_DROPPED
DRAG_EXITED
DRAG_EXITED_TARGET
those work exactly the same with JavaFX and Gluon dialogs (at least on Windows. On Mac because of the NPE, using Platform.runLater() delays obviously the show Dialog and hide Dialog events, but lets just focus on Windows for now).
Right after that last event, the source receives:
DRAG_DONE
but only with a JavaFX dialog.
After some debugging, the reason why the Gluon's Dialog aborts the drag done event can be explained as follows:
The Scene class has a DnDGesture private class:
/**
* A Drag and Drop gesture has a lifespan that lasts from mouse
* PRESSED event to mouse RELEASED event.
*/
class DnDGesture {
...
}
And as it is explained in the comment, it has a lifespan from mouse pressed event to mouse release event.
Using JavaFX built-in dialog, this is displayed in a new Stage and therefore a new Scene. The key here is that this dialog (and all the set of mouse events) is displayed in a new modal stage, so once the dialog is hidden, the primary stage takes the focus again and resumes, finishing properly the dnd gesture as the mouse is released.
But using Gluon's dialog, there is no second stage. Everything happens in the same stage, and once the mouse is released, the Scene.DnDGesture becomes null, so when the DRAG_EXITED_TARGET event happens in the target, the proper call is done to finish the dnd process, but at this point dndGesture is null, and that call doesn't reach the source anymore.
I don't consider this a bug, but more like a tradeoff, as there are a number of reasons to avoid a second stage/scene on a mobile environment and keep the View/Layer (in one single stage) design.

Open a page after cliking on a push notification Ionic 2 iOS

Lately, I have been adding push notifications capability on my app. I am using FCN plugin found on this link and I developing using Ionic 2 framework. The notifications get delivered but when I tap on it it just opens the homepage of the app, and not the inner page that I need.
I have used this code
declare var FCMPlugin;
#Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage:any = HomePage;
horoscopePage:any = HoroscopeHomePage;
#ViewChild(Nav) nav: Nav;
**********************
FCMPlugin.onNotification(function(data){
if(data.wasTapped){
//Notification was received on device tray and tapped by the user.
if(data.topic =="horoskopi" && data.type=="list"){
console.log( JSON.stringify(data) );
this.nav.push(this.horoscopePage);
}
}else{
if(data.topic =="horoskopi" && data.type=="list"){
console.log( JSON.stringify(data) );
this.nav.push(this.horoscopePage);
}
}
});
});
Somehow this line of code this.nav.push(this.horoscopePage); doesn't do anything
When I use NavController instead it gives me this error:
MyApp_Host.html:1 ERROR Error: No provider for NavController!
at injectionError (core.es5.js:1231)
at noProviderError (core.es5.js:1269)
at ReflectiveInjector_._throwOrNull (core.es5.js:2770)
at ReflectiveInjector_._getByKeyDefault (core.es5.js:2809)
at ReflectiveInjector_._getByKey (core.es5.js:2741)
at ReflectiveInjector_.get (core.es5.js:2610)
at AppModuleInjector.NgModuleInjector.get (core.es5.js:3578)
at resolveDep (core.es5.js:11039)
at createClass (core.es5.js:10903)
at createDirectiveInstance (core.es5.js:10723)
You can add public navCtrl: NavController into constructor then change code as
this.navCtrl.push(this.horoscopePage);
Well after I took a look at the official documentation of Ionic, I found out that we can't use NavController in app.component.ts because you can't inject NavController because any components that are navigation controllers are children of the root component so they aren't available to be injected. For more click here.
The reason that I was unable to push a new Page inside FCM.onNotifications() functions was that it changed the scope of application. The solutions was simple: just use the arrow function:
FCMPlugin.onNotification(
(data)=>{
if(data.wasTapped){
//do something
}
else {
//do something
}
});

Ionic 2 open modal on platform resume

I am currently working on an Ionic 2 app which requires authentication each time the app moves into the background and resumes.
import { ModalController } from 'ionic-angular';
#Component({
selector: 'item-details',
templateUrl: 'item-details.html'
})
export class ItemDetailsPage {
private modalCtrl: ModalController) {
}
ionViewDidLoad() {
this.platform.resume.subscribe(() => {
let modal = this.modalCtrl.create(LoginModalPage, true);
modal.present();
});
}
The issue I am having is that when the app resumes, it is correctly detects that it has resumed but then gives the error:
EXCEPTION: Attempted to assign to readonly property
When I use web inspector attached to the simulator it seems to imply the modal is undefined but I am unsure why.
This is how you have created modal
let modal = this.modalCtrl.create(LoginModalPage, true);
But from docs, instance is created with create(component, data, opts) where data is an object. In your case it is a boolean. So you need to pass an object. Here is the doc

Aritchie userdialogs no background for ShowSuccess and ShowError on iOS

I have installed Aritchie userdialogs version 5 and I'm using Xamarin.Forms Version 2.2.
When I use UserDialogs.Instance.ShowSuccess or UserDialogs.Instance.ShowError, on Android a dark backgroud is displayed, on iOS is NOT displayed which makes this alert message pretty unreadable when the page behind is mostly white.
On iOS I just get the message and the icon in the center of the screen but no dark background.
Example code on iOS:
UserDialogs.Instance.ShowSuccess("Data saved correctly");
How can I solve it ?
Without and With ForceiOS6LookAndFeel:
In your iOS native app:
Add the Nuget BTProgressHUD
In your: AppDelegate (AppDelegate.cs):
add the using clause: using BigTed;
add the code BTProgressHUD.ForceiOS6LookAndFeel = true; in FinishedLaunching method
All done :-)
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
BTProgressHUD.ForceiOS6LookAndFeel = true;
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
Any calls within your Xamarin.Forms based code to ShowSuccess (or any other BTProgressHud dependent code) will default to 'older' style.
Is it possible to use a Toast instead? As you can set the background like so:
ToastConfig.SuccessBackgroundColor = System.Drawing.Color.BurlyWood;
create it like so:
Toast(ToastEvent.Success)
Either that or you are going to have to change the BTProgressHud settings that Acr.UserDialogs uses. I managed it by setting these values in Acr.UserDialogs.iOS UserDialogsImpl.cs:
public override void ShowSuccess(string message, int timeoutMillis)
{
UIApplication.SharedApplication.InvokeOnMainThread(() =>
{
BTProgressHUD.ForceiOS6LookAndFeel = true; // This is the line you need
BTProgressHUD.ShowSuccessWithStatus(message, timeoutMillis);
});
}
And it looks like this:

Resources