GraphFlow

Additional

Language
Java
Version
v1.2.0 (Jun 24, 2017)
Created
Jun 11, 2017
Updated
Jun 24, 2017 (Retired)
Owner
Santi Aguilera (saantiaguilera)
Contributor
Santi Aguilera (saantiaguilera)
1
Activity
Badge
Generate
Download
Source code

GraphFlow

GraphFlow is a lightweight library for designing 'logic based' UI flows. You create a graph of nodes logically connected where each node represents a UI renderable object (fragment/view/whatever).

Minimum api level

Per module:

  • :core: 9
  • :fragments: 9
  • :views: 14
  • :conductor: 16

This library was heavily influenced by a Reddit Post

Setup

Add dependencies in your build.gradle

dependencies {
  // Core library.
  compile "com.saantiaguilera.graphflow:core:<latest_version>"
  
  // For using it with fragments. Brings support-fragments
  compile "com.saantiaguilera.graphflow:fragments:<latest_version>"
  
  // For using it with views
  compile "com.saantiaguilera.graphflow:views:<latest_version>"
  
  // For using it with conductor
  compile "com.saantiaguilera.graphflow:conductor:<latest_version>"
}

Usage

  1. Create a Graph with nodes and connections. Lets say we have a signup application where:

    a. You set your name

    b. You set your age

    c. If you are <18 you validate something, else skips this

    d. You set your email

  // For this example I'll be using the View component (using fragments its the same but MView.class -> MFragment.class
  // Create the type of graph, for this example we use a shipped in DirectedAcyclicGraph
  Graph graph = new DirectedAcyclicGraph();

  // Create the name input node
  Node nameNode = new Node(NameInputView.class, new NodeSelector() {
    @Override
    public boolean select(@Nullable final Bundle args) {
      return true; // Always pick it, its the root?
    }
  });
  
  // Create the age input node
  Node ageNode = new Node(AgeInputView.class, new NodeSelector() {
    @Override
    public boolean select(@Nullable final Bundle args) {
      return true; // Always pick it if coming from the name.
    }
  });
  
  // Create the under 18 input node
  Node underEighteenNode = new Node(UnderEighteenView.class, new NodeSelector() {
    @Override
    public boolean select(@Nullable final Bundle args) {
      return args.getInteger("age") < 18;
    }
  });  

  // Create the email input node
  Node emailNode = new Node(EmailInputView.class, new NodeSelector() {
    @Override
    public boolean select(@Nullable final Bundle args) {
      return true; // Always pick, doesnt matter from where you come
    }
  });

  // Add the nodes to the graph, the order doesnt mind, when connected the shape will be formed.
  graph.add(emailNode);
  graph.add(underEighteenNode);
  graph.add(ageNode);
  graph.add(nameNode);

  // Connect them as we want. We will do it like this:
  // Name --> age --> underEighteen --> email
  //              \_________________/
  graph.connect(name, age);
  graph.connect(age, underEighteen);
  graph.connect(age, email);
  graph.connect(underEighteen, email);
  
  // Graph done!
  1. Create a node switcher! Node switcher is the class in charge of switching a node for another and make them "rendereable"
  // Following the example, we will use a NodeViewSwitcher. If using fragments it would be the same with NodeFragmentSwitcher
  NodeSwitcher<View> nodeSwitcher = new NodeViewSwitcher(activityContext, R.id.viewgroup_container_id);
  1. Finally, create a router and start using it!
  router = Router.<View>create()
    .with(graph)
    .switcher(nodeSwitcher)
    .build();

Router

The router is the class in charge of managing the whole graph flow. The router provides a lot of useful methods:

  • fromRoot: Starts the graph from the root node. The root node is considered the only point with no incoming edges and >1 outgoing edges.

  • addOnNodeCommitListener: Adds a listener that will be triggered everytime we move from one node to another.

  • removeOnNodeCommitListener: Removes a listener, since they are kept as strong references.

  • next: Moves to the immediate node in the graph that fulfills the bundle params

  • back: Moves to the previous node

  • jump: Jumps to a given node

Proguard

This library supports proguard transitively, no need to add extra rules :)

Contributing

Feel free to submit me issues or fork it and do pull requests with changes!