Navigation action into another module: Navigation action/destination XXX cannot be found - androidx

I'm using Navigation framework:
def version_androidx_navigation = "2.5.3"
implementation "androidx.navigation:navigation-fragment:$version_androidx_navigation"
implementation "androidx.navigation:navigation-ui:$version_androidx_navigation"
I have 2 feature modules:
module A:
implements Fragment A
defines navigation graph "navigation_a.xml" with global action "action_global_to_fragment_a" with a destination "fragment A"
and module B:
depends on module A
implements Fragment B
defines navigation graph "navigation_b.xml" with include of "navigation_a.xml"
I am trying to put within the code of module B navigation to Fragment A:
NavController navController = NavHostFragment.findNavController(this);
navController.navigate(R.id.action_global_to_fragment_a)
The project compiles OK, but in runtime throws exception:
Caused by: java.lang.IllegalArgumentException: Navigation action/destination XXX:id/action_global_to_fragment_a cannot be found from the current destination Destination(XXX:id/fragment_B)
class=XXX.FragmentB
at androidx.navigation.NavController.navigate(NavController.kt:1540)
at androidx.navigation.NavController.navigate(NavController.kt:1472)
at androidx.navigation.NavController.navigate(NavController.kt:1930)
The official guide (https://developer.android.com/guide/navigation/navigation-multi-module) mentions you cannot navigate between feature modules using actions (only deep links). However in my case, the module B is directly dependent on module A. It seems it should work, so why it doesn't ?

Related

QML/qdoc : How to define inheritance and important statement for my qml components?

I am writting a documentation for my QML project with QDoc. So far, I am able to make a simple one with a description of my functions/signals/properties. Now, I would like to define the inheritance and the important statements like in the Qt doc (see below).
According to the Qt documentation, the inheritance is defined with \inherits command. However, I don't see any result when I want to make my objects inherit from Item and I don't have any warning/error when I run the qdoc.
According the Qt wiki, QDoc considers the version specified in the command as the import statement. Following the example, I tried to define my own import statement since my qml files will be available with a specific import only (let's say MyLib 2.0 here). Like the inheritance, qdoc doesn't seem to understand because I have the following result:
Any idea of what I missed? You can find below a simple example of what I have (the css file is very simple so I don't think it is relevant to show it).
My environment:
Qt 5.10.10 with msvc2015
LLVM 9.0.0 (for qdoc)
config.qdocconf
sourcedirs = .
headerdirs = .
imagedirs = .
sources.fileextensions = "*.qml"
outputdir = ./doc/
outputformats = HTML
HTML.stylesheets = style.css
HTML.headerstyles = "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/style.css\"/>\n"
CustomItem.qml
import QtQuick 2.10;
/*!
MyLib 2.0 //! What should I write to get the import statement?
\qmltype CustomItem
\inherits Item //! What should I write to get the "Inherits"?
\brief A simple example of object that inherits of Item.
I can safely assume that the properties and signals work well.
*/
Item {
id: customItem;
/*!
prop1 description
*/
property color prop1;
/*!
prop2 description
*/
property int prop2: 6;
}
Thank you for your help !
I think you need to specify the QML module using the \inqmlmodule property and a module.qdoc file.
Example for the mylib.qdoc:
/*!
\qmlmodule MyLib 2.0
\title MyLib 2.0 QML types
MyLib is a collection of types ...
...
*/
In your QML type file:
import QtQuick 2.10;
/*!
\qmltype CustomItem
\inherits Item
\inqmlmodule MyLib
...
*/
Item {
...
}
For inheritance you can prefix the type with its module:
\inherits QtQuick::Item
If your type is defined in a C++ class, also add the \instanciates property:
\instanciates MyType
Full example:
/*!
\qmltype CustomType
\inqmlmodule MyLib
\inherits QtQuick::Item
\brief Provides a custom item type.
CustomType provides a component for use as ...
*/
In order for \inherits to work, the type it inherits must be defined somewhere that QDoc can find. Since Item is a type provided by Qt, your .qdocconf file must depend on the module that provides the documentation for Item.
You can do this by adding the following lines to your .qdocconf file.
depends += \
qtquick
Documentation on depends
Relevant section:
The depends variable defines a list of other documentation projects that this project depends on for resolving link targets for type inheritance and anything else the documentation needs to link to.
But you also need to tell QDoc where the index files for those dependencies are.
When invoking QDoc on a project that has dependencies and uses the depends variable, one or more -indexdir path(s) must be passed as command line option(s). QDoc uses these paths to search for the dependencies' index files.
qdoc mydoc.qdocconf -outputdir $PWD/html -indexdir $QT_INSTALL_DOCS
With above, QDoc will search for a file $QT_INSTALL_DOCS/qtquick/qtquick.index for a dependency to qtquick. If an index file for a dependency is not found, QDoc will output a warning.
Which means you need to build the Qt documentation and pass the location of the installed documentation to qdoc
Link on building the Qt documentation
Once you've done that, using \inherits Item should provide the following line in your produced documentation.
Inherits: Item

Can't infer proper type myself in Kotlin when using JavaFX

I just started to study Kotlin and JavaFX by following tutorial.
I could see blank JavaFX windows, and I proceed next step that using FXML.
import javafx.application.Application
import javafx.fxml.FXMLLoader
import javafx.scene.Scene
import javafx.stage.Stage
class AppMain : Application() {
override fun start(primaryStage: Stage) {
primaryStage.title = "Try JavaFX"
val fxml = javaClass.getResource("fxml/Main.fxml")
val root = FXMLLoader.load(fxml) // ERRORS here! `load`
val scene = Scene(root)
primaryStage.scene = scene
primaryStage.show()
}
}
However, I couldn't figure out that how to avoid the type inferencing error like:
Error:(12, 31) Kotlin: Type inference failed: Not enough information to infer parameter T in fun <T : Any!> load(p0: URL!): T! Please specify it explicitly.
From the message, I understand that I have to write the type of variable fxml explicitly.
But I have no idea that what type should be labeled to fxml.
I tried to read the document about JavaFX, but I couldn't figure it out.(I'm not familiar with Java and Kotlin)
I tried to type like URL but it does not make sense.
Many JavaFX & Kotlin example codes that I could find from google does not seems to have the problem like this. (Are the example codes written in previous version?)
What type should I put for the variable?
Or did I miss something other?
Environment and Codes
Environment
JDK 11
JavaFX 11
Kotlin 1.2.71
My complete trial code
https://github.com/QuietJoon/StudyKotlin-JavaFX/tree/fxml
The problem isn't the parameter to the FXMLLoader.load function (which is a java.net.URL object, as returned by javaClass.getResource). It's that this function returns a generic type:
public static <T> T load(URL location)
The Kotlin compiler needs to know what type your root variable will be (as you've not explicitly defined it), but it can't know that as there's nothing in the code that will allow it to infer this.
A quick Google returned this example which has this code in it (in Java):
Parent root = FXMLLoader.load(getClass().getResource("fxml_example.fxml"));
As you can see here, the root variable is of type Parent. So what you need to do is provide this type (i.e. what you expect the load function to return) in some way. Here are two different ways you could do this:
Specify the type explicitly when declaring the variable: val root: Parent = FXMLLoader.load(fxml)
Specify the generic type when calling the method: val root = FXMLLoader.load<Parent>(fxml)
Note also that in your build.gradle file in your github repo there's a mistake that means the code didn't immediately compile when I fetched it:
compile "org.openjfx.javafx.fxml:11:$platform" should be compile "org.openjfx:javafx-fxml:11:$platform" (one of the dots should be a colon).

How do you wire up states and flows in separate CorDapps for ScheduableState/ScheduableFlow

We have been following the same framework as in the template (Corda v1.0 onwards) to separate the ContractAndStates and Flow into 2 CorDapps in our development work but ran into some issues when we are using SchedulableFlow. It seems that the SchedulableState and the SchedulableFlow needs to be in the same CorDapp because of the dependencies. We are following the heartbeat CorDapp example to create our ScheduabeState for a cyclic flow to be initiated (https://github.com/joeldudleyr3/heartbeat).
override fun nextScheduledActivity(thisStateRef: StateRef, flowLogicRefFactory: FlowLogicRefFactory): ScheduledActivity? {
// A heartbeat will be emitted every second.
// We get the time when the scheduled activity will occur in the constructor rather than in this method. This is
// because calling Instant.now() in nextScheduledActivity returns the time at which the function is called, rather
// than the time at which the state was created.
return ScheduledActivity(flowLogicRefFactory.create(HeartbeatFlow::class.java, thisStateRef), nextActivityTime)
As a result of this dependency in the ScheduableState (see above), we would have to create the flow in the same CorDapp as in the ContractAndState, which we have decided not to do. Rather, our workaround is to do the scheduling on the spring backend for the time-being.
Currently to add dependencies to the flow CorDapp, you add to the flow CorDapp project, the ContractAndState in the build.gradle. To make the ContractAndState depend on the flow, you can't add the dependency into its build.gradle else it creates a circular reference. The only way we have found is still to add to the ContractAndState CorDapp project the flow that the ScheduableState is dependent on, so its not really working if we follow the template. Are there workarounds or have we not wire-up the dependencies correctly?
There is a special FlowLogicRefFactory.create method exactly for this use-case.
You are using fun create(flowClass: Class<out FlowLogic<*>>, vararg args: Any?): FlowLogicRef, which requires a FlowLogic class.
Instead, you can use fun create(flowClassName: String, vararg args: Any?): FlowLogicRef, which takes a fully-qualified class name.

What does Gluon SceneBuilder look for in JAR files?

Using Clojure, I'm trying to write a custom JavaFX component for use in Gluon SceneBuilder, to be loaded up from a .jar file. That is, I'd like to point SceneBuilder to the .jar with my custom class, and have the thing show up in the list of draggable items on the left.
I can make the visual structure show up with FXML only, but I'd like to include some behavior as well.
After doing the (:gen-class) stuff in my Clojure source, running lein uberjar, and using the fx:root construct in the FXML, I'm able to use the resulting class in a modified version of the official Java example.
When I instantiate my custom class in the CustomControlExample, I see evidence of the Clojure init code running (via printlns and other stuff in the graphics).
So my custom class appears to work normally. It has two constructors -- with and without a String argument, and extends from HBox. I can verify these when I view the resulting .class file in NetBeans and also using JarExplorer. The class has a ton more stuff in it, due to being a Clojure constructed class, but it has at least the same number and type of constructors as the example.
The problem is my custom component does not appear in the SceneBuilder when I import the uberjar file.
So the question is: What exactly does SceneBuilder need to see in the class to make it appear as a custom draggable component?
Here is the relevant portion of my one source file (it includes a utility library for dealing with starting up the FX runtime).
src/toyui/GridSettingsPane.clj:
(ns toyui.GridSettingsPane
(:gen-class
:extends javafx.scene.layout.HBox
:post-init post-init
:init init
:constructors {[] []
[String] []})
(:use [jfxutils.core :exclude [-main]]))
(defn -init
([]
(-init "unnamed-init"))
([name]
(println "hi from -init")
[[] []]))
(defn -post-init
([this]
(-post-init this "unnamed-post-init"))
([this name]
(println "hi from -post-init")
(jfxutils.core/app-init)
(let [loader (javafx.fxml.FXMLLoader. (clojure.java.io/resource "GridSettingsPane.fxml"))]
(.setRoot loader this)
(.setController loader this)
(.load loader)
loader))))
I discovered that SceneBuilder was using some real-time class loading. Clojure defaults to *use-context-classloader* = true, so I was able to get the class to load, sort of, by modifying the scenebuilder code a little as in my comment above. However it still was having some trouble with finding some type of resource. I figured it was still probably due to class paths and the like.
In the process I also discovered that the SceneBuilder dynamically creates a little FXML file (stream, actually), which says, among other things, <?import toyui.GridSettingsPane?>, and the runs the regular FXML loader on that stream.
So I went and modified FXMLExample to import my Clojure class from within the .fxml file and it worked.
So the conclusion is yes, my class will work as-is in the FXML when running from a regular program, but for some reason doesn't load up when the jar explorer is looking.

Trouble passing a pointer between child ViewControllers in iOS6

My problem is with an iOS 6 tabbed application. My work-in-progress has 5 tabs and several tabs are gateways to other view controllers. Most pages need access to a Model object, which contains data stored as arrays, strings, and so on. A bare-bones model is populated at runtime and the user can add to it throughout the application lifespan. For example, the code listed below is from my AppDelegate file , where it is passing a pointer to the bare-bones Model to the Project View Controller. This works fine: the tab application uses the navigation controller array stack; because I know the Project page is at index 2, I can send the model to it.
My problem has to do with the sub views of the Project page. For example, as a sub view to the Project page there is (or should be) a File_IO page where the user handles file operations. The File_IO page also needs access to the Model object. But when I try to send the Model pointer from the Project page to the File_IO page, the technique I used previously (from the AppDelegate to the Project) does not work. I point to an empty Model in the FileIO ViewController.
Example code: this is in the AppDelegate, and it works fine: the bare-bones Model in the Project ViewController is populated with the data.
//To the Project View Controller...
UINavigationController *project_NavigationController =
[[tabBarController viewControllers] objectAtIndex:2];
Project_ViewController *project_ViewController =
[[project_NavigationController viewControllers] objectAtIndex:0];
//This hides the navigation bar on the project page but it also removes the bar on any subsequent pages! They need to be programmmatically reset in ViewDidLoad.
[project_NavigationController setNavigationBarHidden:YES animated:YES];
project_ViewController.currentGeoModel = newGeoModel;
Now, my Project_ViewController is embedded in a NavigationController and has 4 child ViweControllers. One is named FileIO_ViewController. I want to pass the currentModel from the Project_ViewController to the FileIO_ViewController. Under the - (void)viewDidLoad method I have tried a number of things, which do not work. For example,
UINavigationController *project_NavigationController = (UINavigationController *) self.presentedViewController;
FileIO_ViewController *fileIO_ViewController = [[project_NavigationController viewControllers] objectAtIndex:1];
fileIO_ViewController.currentModel = currentModel;
compiles but when I try to access currentModel inside the FileIO_ViewController methods, it is empty.
If anyone can take the time to help I would be very appreciative. The best answer for me would be in the form of an explicit code example showing how to pass the pointer to an object like my Model from a ViewController to another ViewController where you do not explicitly know where in the stack the child VC lies. (In my example I used Index 1 but I do not actually know at which Index the FileIO_ViewController lives as I have three other ViewControllers under the Project_ViewController. I've tried several integers with no success.)
If you do answer this, please consider me a New Guy when it comes to iOS 6 and objective C -- climbing Mount Apple has been a long haul and I isn't anywhere near the top yet!
Thanks
Tim Redfield
Norway
If you have a shared single model for your app, you shouldn't proactively pass the pointer around, you should make the model available from a single location and leave it to individual objects to access this same model when they need to. A good location for your model pointer is in your Application delegate.
In the appDelegate's .h file, declare a property for your model:
//appDelegate.h
#property (nonatomic, strong) MyAppModel* appModel;
After you instantiate your model in the appDelegate, just assign it to the property:
//appDelegate.m
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.appModel = [[MyAppModel alloc] init];
//set up bare-bones appModel here
return YES;
}
Then you can access this property from any viewController that needs model data thus:
#import appDelegate.h;
AppDelegate* appDelegate = [UIApplication sharedApplication] delegate;
MyModel* model = appDelegate.model
(Better still, make the model object into it's own Singleton object, but using the appDelegate will get you started)
If you need to pass models around, then you need to take care that you are passing them to the right object. This is where your existing code is breaking. For example you are making many assumptions about the structure of a NavigationController stack. But whenever you move back down a stack by popping a controller off the top, you lose that top controller instance completely. When you 'return' to that controller by going forwards on the stack, in fact a new instance is created (unless you have taken care to keep a pointer hanging around and make sure to push to that pointer). If you need more help on this aspect, you will need to describe exactly the layout of your app, and how you are creating your viewControllers, navigationController stack, etc.
update (following your comments)
If your changes to the model are valid throughout the app, then I don't see why you can't just access the model when you need to from wherever you happen to be in the app via appDelegate.model. If you have concurrent versions of the model, you could look at making a singleton data manager object which could handle the details of storing an array of models (or a model history) and providing the correct model as per request. The principle is the same - rather than proactively passing model objects into your viewControllers, let them request data from a centralised source as they need it.
Regarding your description "Now, my Project_ViewController is embedded in a NavigationController and has 4 child ViewControllers.", I don't think you have quite grasped the distinction between Classes, Storyboard scenes, and instances.
You have this arrangement in a part of your storyboard:
UINavigationController
| push push push
|->UIViewController1 -----> UIViewController2 -----> UIViewController3 ----->
segue segue segue
You talk about passing data directly from VC1 (say) to VC3 by accessing the NavController's stack.
What you need to consider is that the storyboard describes a template showing how instances will interrelate when they are instantiated. They are not instantiated just because the storyboard is loaded. When you have arrived at VC1, the ability to segue to VC2 and VC3 is laid out before you in the template, but neither VC2 nor VC3 - as instances - exist until you initiate the segue. The segue process instantiates it's destinationViewController Therefore it makes no sense to pass data from VC1 directly into VC3. When you are at VC1, the navController's stack only contains one item (a VC1 instance); when you segue to VC2, it then contains instances of VC1 and VC2, and it is only when you actually segue to VC3 that the instance is created and placed in the stack.
Stepping through your code:
UINavigationController *project_NavigationController =
(UINavigationController *) self.presentedViewController;
the presentedViewController property works with modal segues, where you have a presenting, and a presented, view Controller. NavControllers on the other hand work with push segues (as they push child viewControllers onto their viewControllers stack, which is where you can obtain pointers to them from).
In this context, self.presentedViewController is nil, which you are assigning to a new variable. The code does nothing, but the compiler won't complain.
FileIO_ViewController *fileIO_ViewController =
[[project_NavigationController viewControllers] objectAtIndex:1];
project_NavigationControlle is nil, so it's properties are all nil. fileIO_ViewController gets nil.
Likewise in the last line you are sending a message to nil, which is not an error, but faintly redundant.

Resources