Skip to content

Commit

Permalink
docs(mobile apps): add documentation for mobile apps
Browse files Browse the repository at this point in the history
added relevant documentation on mobile applications, in particular on their conception and
maintenance, explaining the mechanics of operation in the integrated use of web files for iOS and
Android, in each case showing how to work with web resources that are stored on the tablet.
  • Loading branch information
andresvcc committed May 8, 2024
1 parent 615535d commit 05e5338
Show file tree
Hide file tree
Showing 19 changed files with 985 additions and 92 deletions.
102 changes: 102 additions & 0 deletions apps/thymio-suite-mobile-android/IntroductionAndroid.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { Meta, Description } from '@storybook/addon-docs'

<Meta
title="Mobile app/Android/Introduction"
parameters={{
viewMode: 'docs',
previewTabs: {
canvas: { hidden: true }
},
}}
/>

# Welcome to the Thymio Suite Mobile for Android
---

Welcome to the Thymio Suite App for Android, a comprehensive mobile application designed to seamlessly interface with the Thymio2+ robotic system through Android tablets. Utilizing the power of React Native, this app offers a robust, cross-platform mobile environment specifically optimized for Android devices. This introduction provides an overview of key features, setup instructions, and operational guidelines to help you maximize the educational potential of your Thymio2+ robots.

#### Purpose of the App

The Thymio Suite App aims to facilitate direct interaction between Android tablets and Thymio2+ robots, enhancing the educational experience in both classroom and home settings. The app enables users to program and control Thymio robots with ease, leveraging the advanced capabilities of Android devices to make robotics education both accessible and engaging.

#### Features

- **Direct Connectivity:** Uses Bluetooth or Wi-Fi to connect directly with Thymio2+ robots, ensuring stable communication and real-time control.
- **Interactive Programming Interface:** Offers a user-friendly programming interface that is suitable for all ages, making it straightforward to create, modify, and execute robot programming tasks.
- **Customizable Robot Settings:** Users can customize robot settings directly from their Android device, providing a flexible and personalized educational tool.
- **Real-Time Feedback:** Provides real-time feedback and diagnostics to monitor robot performance and identify any issues during operation.

#### System Requirements

- **Compatible Devices:** Optimized for Android tablets.
- **Android Version:** Requires Android 10.0 or later.
- **Connectivity:** Wi-Fi capability necessary for connecting with the Thymio2+ dongle.

### Getting Started

#### Installation and Setup

This guide will walk you through the process of setting up the Thymio Suite app on an Android device. Follow these steps to ensure your development environment is ready and to run the app on an Android simulator or a physical device.

#### Prerequisites

1. **Node.js**: Ensure Node.js (v18 or later) is installed.
2. **Java JDK**: Install Java Development Kit (JDK 11 is recommended).
3. **Android Studio**: Install Android Studio which will also install the latest Android SDK. During installation, make sure to include the Android Virtual Device (AVD) to emulate Android devices.
4. **Environment Variables**:
- Set `JAVA_HOME` to your JDK path.
- Set `ANDROID_HOME` to your Android SDK location, typically `~/Library/Android/sdk` on macOS or `C:\Users\<Your-Username>\AppData\Local\Android\Sdk` on Windows.

#### Step 1: Install Yarn

Install Yarn globally using npm:

```bash
npm install -g yarn
```

#### Step 2: Go to the project folder

```bash
cd apps/thymio-suite-mobile-android
```

Run the following command in the project root directory to install all dependencies:

```bash
yarn install
```

#### Step 3: Set Up Android Development Environment

1. **Open Android Studio** and open your project by selecting the `android` folder within your project directory.
2. **Check for SDK Updates**: In Android Studio, open the SDK Manager and ensure the required SDK platforms and tools are installed for the Android version you are targeting.
3. **Create a Virtual Device**: If you don’t have a physical device, set up an AVD via Android Studio's AVD Manager.

#### Step 4: Prepare the Android Device

- **Physical Device**: Enable Developer options and USB debugging on your Android device.
- **Emulator**: Launch your AVD from Android Studio’s AVD Manager.

#### Step 5: Run the App

With your Android device ready and connected (or an emulator running), execute the following commands:

1. Start the Metro bundler in a separate terminal window:

```bash
yarn start
```

2. Run the app on Android:

```bash
yarn android
```

This command should install the app on the connected Android device or running emulator.

#### Step 6: Troubleshooting Common Issues

- **Build fails**: Check the build output for any errors. Common issues may relate to version incompatibilities or missing SDK tools.
- **App doesn’t connect to development server**: Ensure your device is on the same network as your development machine, and that the Metro bundler is running.
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,6 @@ export const de = {
welcome_message_phone:
'Um einen Thymio-Roboter zu programmieren, müssen Sie mindestens einen Thymio2-Roboter haben, der an einen Thymio2+-Router oder an einen Relay-Computer angeschlossen ist. Wenn dies nicht möglich ist, können Sie einen Simulator verwenden, der in der Thymio-Suite für PC oder MAC verfügbar ist.',
welcome_continue: 'Weiter zu den Programmiersprachen',
file_exist: 'Datei existiert bereits',
file_exist_message: 'Möchten Sie sie als {{name}} überschreiben?',
};
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ export const en = {
welcome_message_phone:
'To program a Thymio robot, you must have at least one Thymio2 robot connected to a Thymio2+ router or a relay computer. If this is not possible, you can use a simulator available in the Thymio-suite for PC or MAC.',
welcome_continue: 'Continue to programming languages',
file_exist: 'File already exists',
file_exist_message: 'Do you want to overwrite it as {{name}}?',
};
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,6 @@ export const es = {
welcome_message_phone:
'Para programar un robot Thymio, es necesario tener al menos un robot Thymio2 conectado a un router Thymio2+ o a un ordenador relé. Si esto no es posible, puedes utilizar un simulador disponible en Thymio-suite para PC o MAC.',
welcome_continue: 'Continuar hacia los lenguajes de programación',
file_exist: 'El archivo ya existe',
file_exist_message: '¿Quieres sobrescribirlo como {{name}}?',
};
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,6 @@ export const fr = {
welcome_message_phone:
"Pour programmer un robot Thymio, il est nécessaire de posséder au moins un robot Thymio2 connecté à un routeur Thymio2+ ou à un ordinateur relais. Si cela n'est pas possible, vous pouvez utiliser un simulateur disponible dans la Thymio-suite pour PC ou MAC.",
welcome_continue: 'Continuer vers les langages de programmation',
file_exist: 'Fichier déjà existant',
file_exist_message: 'Voulez-vous le sauvegarder sous le nom de {{name}} ?',
};
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,6 @@ export const it = {
welcome_message_phone:
'Per programmare un robot Thymio, è necessario possedere almeno un robot Thymio2 connesso a un router Thymio2+ o a un computer relè. Se ciò non è possibile, puoi utilizzare un simulatore disponibile nella Thymio-suite per PC o MAC.',
welcome_continue: 'Continua verso i linguaggi di programmazione',
file_exist: 'File già esistente',
file_exist_message: 'Vuoi sovrascriverlo come {{name}}?',
};
32 changes: 7 additions & 25 deletions apps/thymio-suite-mobile-android/src/scratch/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,9 @@ function App({navigation}: any): JSX.Element {
const newPath = `${documentDir}/${filename.split('.').slice(0, -1).join('.') + '(' + index + ')' + '.' + filename.split('.').pop()}`;
fileExists = await ReactNativeBlobUtil.fs.exists(newPath);
if (!fileExists) {
// Muestra una alerta preguntando si el usuario quiere guardar con el nuevo nombre
Alert.alert(
'Archivo ya existe',
`El archivo ya existe. ¿Quieres guardarlo como ${newPath.split('/').pop()}?`,
i18n.t('file_exist'),
i18n.t('file_exist_message', {name: filename}),
[
{
text: 'No',
Expand All @@ -192,9 +191,8 @@ function App({navigation}: any): JSX.Element {
style: 'cancel',
},
{
text: '',
text: 'OK',
onPress: async () => {
// El usuario acepta, guarda el archivo con el nuevo nombre
await ReactNativeBlobUtil.fs.createFile(
newPath,
base64,
Expand Down Expand Up @@ -224,7 +222,6 @@ function App({navigation}: any): JSX.Element {
}
}

// Si el archivo no existía inicialmente, procede a guardar sin preguntar
await ReactNativeBlobUtil.fs.createFile(path, base64, 'base64');
Alert.alert(
i18n.t('scratch_save_success'),
Expand Down Expand Up @@ -353,23 +350,20 @@ function App({navigation}: any): JSX.Element {
} else if (objectData.spec === 'alert') {
// console.log('Alerta', objectData.payload);
} else {
// console.log('Mensaje recibido:', objectData.spec);
setDialogVisible(objectData.payload);
}
} catch (error) {
console.log('Error al procesar el mensaje:', error);
console.log('Error to parse data:', error);
}
};

const deberíaDescargar = useCallback((_url: string) => {
// Ajusta esta lógica según tus necesidades
return _url.includes('blob:'); // Ejemplo para archivos JSON
return _url.includes('blob:');
}, []);

const handleNavigationStateChange = useCallback(
(event: any) => {
if (Platform.OS === 'android') {
// console.log('event:::->', event);
if (event.title === 'Scratch 3.0 GUI') {
setWebview('scratch');
setQueryParams(getQueryParams(event.url));
Expand All @@ -378,13 +372,9 @@ function App({navigation}: any): JSX.Element {
return;
}

// console.log('Evento de navegación:', event.url);
if (deberíaDescargar(event.url)) {
// Detiene la carga en el WebView y maneja la descarga
webViewRef.current?.stopLoading();
} else {
// Si no es una descarga, pasa el evento a la función onChange propuesta

setWebview(getPathAfterLocalhost(event.url));
setQueryParams(getQueryParams(event.url));
setUrl(event.url);
Expand All @@ -394,7 +384,6 @@ function App({navigation}: any): JSX.Element {
);

const handleSave = () => {
// setConfig(dialogVisible);
saveJsonFile(dialogVisible, fileName + '.sb3');
setDialogVisible(null);
};
Expand All @@ -411,22 +400,15 @@ function App({navigation}: any): JSX.Element {
.catch(err => console.error('An error occurred', err));
};

// useEffect Platform
useEffect(() => {
const newHost =
Platform.OS === 'android'
? 'file:///android_asset' // 'file:///android_asset'
: 'http://127.0.0.1:3000';
const newHost = 'file:///android_asset';

setHost(newHost);
setUrl(
`${newHost}/scanner/index.html?data=${JSON.stringify({...LTServices})}&gl=${JSON.stringify(
{
interface: 'scratch',
redirect:
Platform.OS !== 'android'
? 'file:///android_asset/scratch/index.html'
: 'http://127.0.0.1:3000/scratch/index.html',
redirect: 'file:///android_asset/scratch/index.html',
},
)}&lang=${language}&isTablet=${JSON.stringify(isTablet)}`,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { Meta, Description } from '@storybook/addon-docs'

<Meta
title="Mobile app/Android/Scratch"
parameters={{
viewMode: 'docs',
previewTabs: {
canvas: { hidden: true }
},
}}
/>

## Scratch Interface Documentation Android

Scratch is a widely recognized visual programming language developed to simplify the process of learning to code. It's particularly useful for educational purposes due to its intuitive drag-and-drop interface. In relation to the Thymio2+ robot, Scratch provides a friendly and engaging way for users, especially younger learners, to program and control their robots. By using Scratch with Thymio2+, students can visually assemble code blocks to control the robot's actions and responses to environmental inputs, making complex concepts in robotics and programming accessible and fun. This integration empowers educators and students to explore the fundamentals of robotics programming in an interactive and supportive environment.

## Integration of Scratch in the Thymio Suite Mobile App

To integrate the Scratch web interface into the Android mobile application, an underlying Android tool is used that allows for serving web files internally without the need for an external web server. Specifically, the files should be placed in the directory /android/app/src/main/assets. They can then be loaded into the WebView using the path file:///android_asset. This method simplifies the deployment process by utilizing the Android platform's native capabilities to handle local web content directly within the app.

### Generating the URL

To construct this URL, necessary data must first be acquired from the 'scanner' page, which can be accessed using the following URL pattern:

```javascript
http://127.0.0.1:3000/scanner/index.html?data=${
JSON.stringify({
...LTServices
})}&gl=${JSON.stringify(
{
interface: 'vpl3',
},
)}&lang=${language}`
```

Here, `LTServices` is an object containing device information structured as follows:

```typescript
interface DeviceInfo {
port: number;
txt: {
uuid: string;
'ws-port': string;
};
addresses: string[];
name: string;
fullName: string;
host: string;
}
interface DevicesMap {
[hostname: string]: DeviceInfo;
}
```

### Purpose of the Scanner Page

The scanner page uses the data from `LTServices` to scan each TDM and retrieve a list of connected robots. Users can select the appropriate robot on this page, which then enables the Scratch page to be loaded with all necessary data to initiate the interface correctly.


#### Example URL Structure

An example URL to access the Scratch interface might look like this:

- **device Host**: The uuid of the device, typically a Thymio2+ that hosts the TDM (Thymio Device Manager) with which Scratch communicates.
- **pass**: The password for accessing the Thymio Device Manager.
- **ws**: The WebSocket ip and port used by the TDM for real-time communication.

```
file:///android_asset/scratch/index.html?device=%7Bd768ed1a-5831-425a-89a0-50d10f8c1a4c%7D&ws=ws://127.0.0.1:8597&pass=CX87IR
```
## File Manager
The VPL3 interface uses a WebView to provide a block-based programming environment. File operations within this environment—specifically saving current projects and uploading existing ones—are facilitated through communication between the WebView and the native code via `postMessage`. This ensures a seamless integration of web-based components with mobile functionalities.
### Workflow Description
#### Saving Files
**1. Trigger Save Action:**
- The save process is initiated by the user from the VPL3 web interface, typically through a save button.
**2. Capture Data in WebView:**
- When the save action is triggered, the web environment captures the current state of the program, which is serialized into JSON format.
**3. PostMessage to Native App:**
- The serialized data is sent to the native side using `postMessage`. This message includes an action type, such as `{ action: "saveProgram", content: jsonData }`.
**4. Native Handling:**
- The native code listens for messages from the WebView. Upon receiving the data, it invokes file writing operations using React Native's file system libraries.
**5. Confirm and Alert User:**
- After the file is successfully saved, the native app can send a confirmation back to the WebView or display a native alert confirming the save.
```javascript
// React Native side
const handleFileUpload = async () => {
try {
const result = await DocumentPicker.pick({ type: [DocumentPicker.types.json] });
const fileContent = await ReactNativeBlobUtil.fs.readFile(result.uri, 'utf8');
webViewRef.current.postMessage(JSON.stringify({ action: "loadProgram", content: fileContent }));
} catch (err) {
console.error('File selection error:', err);
}
};
```

#### Uploading Files

**1. Open Document Picker:**
- The user initiates the upload process, prompting the native side to open a document picker for file selection.

**2. Read and Send Data:**
- Once a file is selected, its content is read into a string using file reading utilities.
- This content is then sent back to the WebView using `postMessage`, similar to `{ action: "loadProgram", content: fileString }`.

**3. Load Data in WebView:**
- Inside the WebView, an event listener processes the received message and loads the program content into the VPL3 environment.

```javascript
// React Native side
const handleSaveToFile = (jsonData) => {
const path = `${ReactNativeBlobUtil.fs.dirs.DocumentDir}/savedProgram.json`;
ReactNativeBlobUtil.fs.writeFile(path, jsonData, 'utf8')
.then(() => console.log('Save successful'))
.catch(err => console.error('Save failed', err));
};

// WebView side
window.ReactNativeWebView.postMessage(JSON.stringify({ action: "saveProgram", content: programData }));
```

```javascript
// WebView side
window.addEventListener('message', function(event) {
const data = JSON.parse(event.data);
if (data.action === 'loadProgram') {
loadProgramFromJSON(data.content);
}
});
```
Loading

0 comments on commit 05e5338

Please sign in to comment.