Skip to content

develersrl/lilt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LILT Firenze Seno License

A LILT app for iOS/Android smartphones and tablets about breast cancer prevention.

iOS

Android

The following guide assumes that node and npm commands are available in the system, and Xcode is installed.

The Lilt Xcode project has some Cocoa dependencies. If you do not have cocoapods installed in your system, you have to install it with the following command:

$ brew install cocoapods

Or, if you prefer gem:

$ gem install cocoapods

If this is your first time using CocoaPods, run to create a local CocoaPods spec mirror.

Now go into app/ios folder and run pod install to install the dependencies (the Mixpanel dependency for now).

The react-native mobile app is located in the app directory. To setup react-native dependencies run the following commands inside the app directory (assuming that node and npm commands are available):

$ npm install
...
$ react-native link

Application code is partially generated from a Python script which requires a virtualenv. Just cd to the app dir and load the Python (2.7) virtualenv from requirements file.

Example using virtualenvwrapper:

$ mkvirtualenv lilt
...
$ (lilt) pip install -r requirements.txt

Now you can launch the code generation and packager:

$ npm run gen
...
$ npm start

Now you can open the Xcode app project and launch the app.

App settings are stored inside a json file. We use different json files for development and production environment. The development settings are stored inside config.dev.json file under the app directory. Production settings must be stored inside a config.prod.json file in the same directory. The production settings file is git-ignored.

The App is also available for the Android platform.

In addition to the configuration steps described in the above sections, you have to modify your gradle.properties file (usually located in ./gradle directory of the home folder).

Inside the gradle.properties file you have to specify some variables:

LILT_FIRENZE_SENO_RELEASE_STORE_FILE=...
LILT_FIRENZE_SENO_RELEASE_KEY_ALIAS=...
LILT_FIRENZE_SENO_RELEASE_STORE_PASSWORD=...
LILT_FIRENZE_SENO_RELEASE_KEY_PASSWORD=...

as described in the following guide: https://facebook.github.io/react-native/docs/signed-apk-android.html.

Application content is partially generated by a gen.py Python script. To generate the application react-native code, cd to the app directory, setup the Python virtualenv (see this section for details) and run:

(lilt-venv)$ npm run gen

If you see a warning message in terminal output, maybe you did not set the LILT_EDITOR_DATA_DIR environment variable (see next section for details).

The app code generation is splitted in two steps: the first one imports app data from editor output directory (see App Content Editor section for details about the app data editor) into a processable directory structure (app/content directory); the second step generates the actual code.

To properly execute the first step, the generation script must know where the editor output directory is located. You can specify it through the LILT_EDITOR_DATA_DIR environment variable (if you do not set it a warning message is displayed).

The second generation step takes an array of page descriptors as input, and generates the corresponding react native page components. Page descriptors array is the union of:

  • page descriptors imported from step 1
  • page descriptors defined in pages.json (inside content directory)

In general, all the stuff used as input for the second generation step process is located under the app/content directory.

To simplify the explanation we will focus on pages.json file structure, which looks like this:

[
    { ... }, // page 1 descriptor
    { ... }, // page 2 descriptor
    ...,
    { ... }  // page n descriptor
]

All page descriptors have the same structure. For example, suppose that we want to generate a page that contains only one button; when the user press the button we want to switch to an hardcoded page. We can define our page in this way:

{
    "id": "1",  // unique page identifier
    "title": "My Title",  // page title
    "style": "my_page",  // page style (see later)
    "content": {  // page content
        "myButton": {
            "type": "button",
            "text": "Press Me!",
            "link": "hardcoded_page"
        }
    }
}

Each page has a unique id and a title.

The style property identifies the page template. In the example we use the template my_page. Page templates are located inside the templates directory. The template filename is computed from the style property in the json by adding the .tmpl.js suffix. So in the example the targeted template would be my_page.tmpl.js.

Let's pretend that our page template is the following:

'use strict';

import React, { Component } from 'react';
import { View } from 'react-native';

import * as style from '../../style';
import * as blocks from '../../blocks';


export default class MyPage extends Component {
  render() {
    const { flexible, stretch } = style.common;
    const { Button } = blocks;

    return (
      <View style={[flexible, stretch]}>
        {{myButton}}
      </View>
      );
  }
}

The content object describes the page content to be generated.

Each content item is identified by a name: the key of the item (myButton in the example). The "myButton" string must refer to a placeholder in the corresponding page template, so that the generation script knows where to put the generated code.

Each item has at least the type property that identifies the kind of item (button in the example). For now, the supported types are button and markdown.

Each item can then have other properties, that are specific to the particular item type. The generation script iterates through the page content and generates the react-native code relative to the content items.

After the code generation step, the script places the generated react-native components inside the js/pages/generated directory. This is an important detail, because every relative path you use in page templates (e.g. import paths, require paths) must be relative to the generated page directory (not the page template directory).

The following sections describe some components generated by the script, but this is not a comprehensive list.

An example of button item is:

{
    "type": "button",
    "text": "Press Me!",
    "link": "#1"
}

All properties are required.

  • type: identifies the item type and must be the "button" string;
  • text: this is the button text;
  • link: identifies the page this button leads to. As of now, two type of links are supported:
    • links to a generated page: in this case the link must be in the form "#[target_page_id]", where target_page_id is a valid page identifier in pages.json file;
    • links to custom (i.e. not-generated) pages: in this case the link string must be the navigator route key explicitly defined in navigator_data.tmpl.js file.

A markdown item example is:

{
    "type": "markdown",
    "source": "my_markdown.md"
}

All properties are required.

  • type: identifies the item type and must be the "markdown" string;
  • source: the name of source markdown file. In the above example, the generation script searches for a file named my_markdown.md inside the app/content/markdown directory.

A ScrollView react-native component is generated for each markdown item. The scroll view shows the rendered markdown inside it.

Navigation between app pages is partially generated, too. The reference template file is navigator_data.tmpl.js inside the templates directory.

Navigator routes are aggregated into the routes object. Each route is identified by its key in the routes object, and it has a title and component property.

The final routes object is the aggregation of two sub-objects:

  • the customRoutes object, which hold "hardcoded" routes;
  • the generatedRoutes object, generated by the script from the informations in pages.json file.

Another important variable here is the initialRouteId string, which must be set to the id of app start route (either a generated route or an "hardcoded" route).

The markdown syntax that is currently supported is a subset of gfm (Github Flavoured Markdown):

  • headers (e.g. ## <header-string>);

  • paragraphs (blocks of text separated by a blank line);

  • bold style (e.g. ** bold text **);

  • images (e.g. ![alt-text](img)) An image can be either "local" or identified by an url:

    • "local" image example: ![local-image](my_local_image.png) In case of local images the markdown renderer "requires" (in react-native sense) that image from the app/content/images/static folder;
    • "remote" image example: ![remote-image](http://www.mysite.com/img.png) In case of "remote" image, the markdown renderer downloads the image and put it into the app/content/images/downloaded directory. Once the download is finished, the renderer "requires" the downloaded image from the downloaded folder.
  • bulleted lists

  • links

The mobile app sends registered users data to a Google Spreadsheet. The spreadsheet is accessed through a Google Apps Script, that exposes a POST endpoint to the mobile app. The Google Apps Script can be found in users-backend directory.

If you want to deploy the webapp elsewhere in order to use another spreadsheet, follow these steps:

  • create the Google Spreadsheet and identify its "spreadsheet id". The spreadsheet id is part of the spreadsheet url: https://docs.google.com/spreadsheets/d/<spreadsheet-id>/edit#gid=0
  • annotate the name of the sheet where you want to store users data (this will be referred as sheet-id);
  • create a new Google Apps Script project, then copy and paste the code from users_manager.gs into an empty gs file;
  • In the "Main Variables" section fill the spreadsheetId variable with the spreadsheet id and the usersSheetName variable with sheet-id;
  • deploy the script as a webapp

The repository contains a simple markdown editor based on electron inside the content-editor folder.

To launch the editor from scratch:

cd content-editor
npm install
npm start

Next time you will use the npm start command only.

The markdown editor allows you to edit md documents inside a folder. By default, the ./markdown folder is used (relative to the app directory), but you can pass another folder:

  • With the LILT_EDITOR_DATA_DIR environment variable
  • Via command-line as the first (and only) parameter (in this case the command-line argument has priority over the environment variable)
  • At program startup through the interface

Optionally you can show the developer tools specifying the LILT_EDITOR_SHOW_DEVTOOLS environment variable, and setting its value to 1.

To deploy a new editor version from a Mac, make sure you have electron-packager installed globally:

npm install -g electron-packager

The wine command must be available too, because we are going to generate a Windows executable.

At this point:

  • adjust the editor version in package.json file
  • run the deploy.sh script

The deploy.sh script packages the app for mac (x64) and Windows platform. If everything goes well an out folder containing two zip files (one per platform) will be created. You can now git-tag the new version and upload the new release on github.

See the LICENSE file for license rights and limitations (BSD-3).