Ventajas de usar Electron
Te contamos las principales ventajas de usar Electron a la hora de desarrollar aplicaciones de escritorio.
En la cuarta parte de este tutorial de Electron, vamos a trabajar en una implementación en OpenChat que nos permitirá enviar y recibir imágenes en nuestro chat
Tabla de contenidos
Anteriormente aprendimos a crear la sala de chat en la que recibimos y enviamos mensajes, todo ello centralizado en la base de datos de Firebase. En esta parte, vamos a trabajar en una implementación en OpenChat que nos permitirá enviar y recibir imágenes en nuestro chat. Para ello trabajaremos con imágenes que quedarán guardadas en Firebase Storage, como hemos visto en la sección anterior.
Para ello, en el componente SendBox
añadiremos el método PostImage()
, el cual se encarga de llamar a un evento de Electron que crearemos en el siguiente paso. Es importante que creemos un botón que llame al método para así poder iniciar el proceso de subida de imágenes. Quedaría algo tal que así:
import React from 'react'
import { ipcRenderer } from 'electron'
class SendBox extends React.Component {
constructor(props) {
super(props)
this.sendMessage = this.sendMessage.bind(this)
this.postImage = this.postImage.bind(this)
}
sendMessage() {
const messageObject = {
message: document.getElementById('send-message').value,
userURL: 'https://avatars.slack-edge.com/2017-11-27/279122939639_c199c00a34366734b118_72.jpg',
userName: 'Miguh Ruiz'
}
ipcRenderer.send('newMessage', messageObject)
}
postImage() {
ipcRenderer.send('upload-dialog')
}
render() {
return(
<div className="grid-x grid-margin-x">
<a className="button warning large-1 cell" onClick={this.postImage}>Foto</a>
<input type="text" id="send-message" className="large-10 cell" placeholder="Escribe tu mensaje aqui" />
<a className="button success large-1 cell" onClick={this.sendMessage}>Enviar</a>
</div>
)
}
}
export default SendBox
upload-dialog
En el archivo index.js
de Electron procederemos a añadir un listener para dicho evento. Debemos destacar que tendremos que usar la API de dialog
que nos permite abrir ventanas emergentes para seleccionar archivos, directorios… Para ello usamos el método dialog.showOpenDialog()
pues pretendemos poder seleccionar un archivo. Este método lleva un objeto de configuración como segundo parámetro que nos permitirá definir cosas como los filters
. Los filters
nos ayudan para delimitar el tipo de archivos que puede seleccionar el usuario. Como puedes apreciar en esta ocasión el usuario solo puede seleccionar archivos con extensión JPG, PNG y GIF pues estamos buscando que el usuario suba imágenes. El resultado debe de ser parecido a:
ipcMain.on('upload-dialog', (ev) => {
dialog.showOpenDialog(win, {
title: 'Elige la imagen que deseas subir',
properties: [
'openFile'
],
filters: [
{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }
]
}, (dir) => {
uploadImage(dir[0]) // dir[0] => Ruta del archivo
})
})
La función uploadImages()
será la encargada de subir nuestra imagen a Firebase. Esta la vamos a crear en nuestro archivo de utilidades(/utilities.js
) y la importaremos al principio del archivo en el que nos encontramos:
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
const admin = require('firebase-admin')
const { uploadImage } = require('./utilities')
[...]
Usando los métodos que vimos en la sección anterior procedemos a inicializar el módulo de Google Cloud Storage que necesitaremos instalar usando:
$ npm i @google-cloud/storage
Procedamos una vez tengamos instalado el módulo a crear la función que mencionamos en el paso anterior. Como vimos en la introducción a Firebase Storage tendremos que usar el módulo de Google Cloud.
Antes que nada(dentro de la función) para comenzar con el método crearemos una instancia del módulo, a esta le pasaremos datos como el id de nuestra aplicación de Firebase y el JSON con las claves.
El método esencial para construir el puente entre Google Cloud y Firebase será el método storage.bucket()
al que le pasaremos la URL de nuestro bucket. La puedes encontrar en el panel de administración de Firebase y viene precedida por el protocolo gs://
.
A esto le añadimos la llamada al método bucket.upload()
que pasándole como parámetro la ruta en la que se encuentra nuestro archivo, la cual la hemos obtenido anteriormente de la ventana emergente. Debe de quedarte algo como lo siguiente:
const Storage = require('@google-cloud/storage')
const fs = require('fs')
const uploadImage = function(imageDir) {
const storage = new Storage({
projectId: 'openchat17',
keyFilename: './firebase_key.json'
})
const bucket = storage.bucket('openchat17.appspot.com')
bucket.upload(imageDir, (err, file) => {
if(err) throw err
})
}
module.exports = {
uploadImage
}
Retomando la manera en la que estamos grabando los mensajes en la base de datos, nos encontramos que el objeto que se le manda a Firebase y que es parte de nuestro componente esta construido tal que así:
const messageObject = {
message: document.getElementById('send-message').value,
userURL: 'https://avatars.slack-edge.com/2017-11-27/279122939639_c199c00a34366734b118_72.jpg',
userName: 'Miguh Ruiz'
}
Para poder comenzar a trabajar con imágenes deberemos de adaptar este objeto pues tras subir las imágenes tendremos que referenciarlas en la base de datos, pudiéndolas desplegar de esta manera cuando carguen los mensajes. Convertiremos la propiedad message
que hasta ahora era un String a Objeto de manera que contenga a su vez una propiedad type
para diferenciar los mensajes que son textos de los que son imágenes. Debería de quedarte algo como:
const messageObject = {
message:
{
type: 'text',
value: document.getElementById('send-message').value
},
userURL: 'https://avatars.slack-edge.com/2017-11-27/279122939639_c199c00a34366734b118_72.jpg',
userName: 'Miguh Ruiz'
}
Una vez tenemos la estructura para la base de datos bien definida, tendremos que obtener la dirección de la imagen que estamos subiendo e incorporarla a un objeto de mensaje para de esta manera subirla a la base de datos. actualizaremos la función uploadImage()
y usaremos el método file.getSignedUrl()
para llevar este procedimiento a cabo:
const uploadImage = function(ev, imageDir) {
const storage = new Storage({
projectId: 'openchat17',
keyFilename: './firebase_key.json'
})
const bucket = storage.bucket('openchat17.appspot.com')
bucket.upload(imageDir, (err, file) => {
if(err) throw err
file.getSignedUrl({
action: 'read',
expires: '12-31-2999'
},)
.then(urls => {
const messageObject = {
message:
{
type: 'image',
value: urls[0]
},
userURL: 'https://avatars.slack-edge.com/2017-11-27/279122939639_c199c00a34366734b118_72.jpg',
userName: 'Miguh Ruiz'
}
sendMessage(db, messageObject)
})
})
}
Si te fijas estamos usando una función llamada sendMessage()
que no hace más que transmitir este objeto hacia la base de datos usando los métodos que ya hemos visto, la función quedó así:
const sendMessage = function(message) {
const docRef = db.ref('messages')
docRef.push(message)
}
Una vez estemos diferenciando en la base de datos los mensajes que los usuarios envían deberemos de reflejar estos cambios en las vistas. Para ello en el componente Message
crearemos un if que nos permitirá distinguir los mensajes de tipo texto y los de tipo imagen:
import React from 'react'
function Message(props) {
if(props.message.message.type == 'image') {
return(
<div className="Message row">
<img src={props.message.userURL} className="large-2 columns"/>
<div className="large-10 columns">
<b>{props.message.userName}</b>
<img src={props.message.message.value} />
</div>
</div>
)
} else {
return(
<div className="Message row">
<img src={props.message.userURL} className="large-2 columns"/>
<div className="large-10 columns">
<b>{props.message.userName}</b>
<p>{props.message.message.value}</p>
</div>
</div>
)
}
}
export default Message
Como hemos visto, nuestra aplicación no es más que un puzzle al que le vamos añadiendo piezas, que sin dudas son totalmente opcionales y que pueden ser tantas como queramos. En la próxima sección haremos un inciso en el desarrollo tal como en la sección anterior pero esta vez para explicar los fundamentos de Firebase Auth y, como puedes predecir, tras ello retomaremos el desarrollo para comenzar a trabajar con la autenticación.
También te puede interesar
Te contamos las principales ventajas de usar Electron a la hora de desarrollar aplicaciones de escritorio.
El curso Electron te enseñará los elementos fundamentales del Framework Electrón para desarrollar aplicaciones de escritorio usando...
En esta segunda parte del Tutorial de Electron, veremos el concepto de eventos en profundidad y crearemos nuestras sala de chat de...