katekichiのゆるブログ

普段の作業メモや日常の出来事とか

「Electronではじめるアプリ開発」を写経してみた ④

G.W.は、何もしないで終わってしまったので、また写経を再開しました。チャットアプリ の続きをやります。

目次:

npmスクリプトの登録

package.jsonにnpmスクリプト(scripts)を記述すると コマンドのエイリアス登録をできます。

  "scripts": {
    "watch": "babel --out-dir .tmp src --watch",
    "start": "electron .",
  },

$ npm start で electron . と同様となります。

ルーティングの実装

reactreact-router で各画面とルーティングを実装していきます。

src/main/Login.jsx(ログイン画面)

import React from "react";
import { Link } from "react-router";

export default class Login extends React.Component {
    render() {
        return (
            <div>
                <h2>Login</h2>
                <Link to="/rooms">Login</Link> <br />
                <Link to="/signup">Create new account</Link>                
            </div>
        );
    }
}

src/main/SignUp.jsx(サインアップ画面)

import React from "react";
import { Link } from "react-router";

export default class Login extends React.Component {
    render() {
        return (
            <div>
                <h2>Signup</h2>
                <Link to="/rooms">Login</Link> <br />
                <Link to="/login">cancel</Link>                
            </div>
        );
    }
}

src/main/Rooms.jsx(チャットルーム一覧画面)

import React from "react";
import { Link } from "react-router";

export default class Login extends React.Component {
    render() {
        return (
            <div>
                <h2>Rooms</h2>
                <ul>
                    <li><Link to="/rooms/1">Room 1</Link></li>
                    <li><Link to="/rooms/2">Room 2</Link></li>                    
                </ul>
                <div>{this.props.children}</div>
            </div>
        );
    }
}

src/main/Room.jsx(チャットルーム詳細画面)

import React from "react";

export default class Login extends React.Component {
    render() {
        return (
            <div>
                <h3>Room</h3>
            </div>
        );
    }
}

src/renderer/app.jsx(ルーティングの実装)

import React from "react";
import { render } from "react-dom";
import { Router, Route, hashHistory } from "react-router";
import Login from "./Login";
import Signup from "./Signup";
import Rooms from "./Rooms";
import Room from "./Room";

const appRouting = (
    <Router history={hashHistory}>
        <Route path="/">
            <Route path="login" component={Login} />
            <Route path="signup" component={Signup} />
            <Route path="rooms" component={Rooms}>
                <Route path=":roomId" component={Room} />
            </Route>            
        </Route>
    </Router>
);

if (!location.hash.length) {
    location.hash = "#/login";
}

render(appRouting, document.getElementById("app"));

メニューの作成

もろもろメニュー項目を追加します。 単純作業で地味にツラったです・・

src/main/setAppMenu.jsx(ルーティングの実装)

import { app, Menu } from "electron";
import createWindow from "./createWindow";

function setAppMenu() {

    const template = [
        {
            label: "File",
            submenu: [
                { label: "New Window", accelerator: "CmdOrCtrl+N", click: createWindow },
                { type: "separator" },
                { label: "Close", accelerator: "CmdOrCtrl+W", role: "close" },                
            ],                     
        },
        {
            label: "Edit",
            submenu: [
                { label: "Copy", accelerator: "CmdOrCtrl+C", role: "copy" },
                { label: "Paste", accelerator: "CmdOrCtrl+V", role: "paste" },
                { label: "Cut", accelerator: "CmdOrCtrl+X", role: "cut" },
                { label: "Select All", accelerator: "CmdOrCtrl+A", role: "selectall" }                
            ],                     
        },
        {
            label: "View",
            submenu: [
                { 
                    label: "Reload", 
                    accelerator: "CmdOrCtrl+R", 
                    click: (item, focusedWindow) => focusedWindow && focusedWindow.reload()
                },
            ],                     
        },
        {
            label: "Toggle DevTools",
            submenu: [
                { 
                    label: "Reload", 
                    accelerator: process.platform === "darwin" ? "Alt+Command+I" : "Ctrl+Shift+I",             
                    click: (item, focusedWindow) => focusedWindow && focusedWindow.toggleDevTools()
                },
            ],                     
        },
    ];

    if (process.platform === "darwin") {

        template.unshift({
            label: app.getName(),
            submenu: [
                { role: "about" },
                { type: "separator" },
                { role: "services", submenu:[] },
                { type: "separator" },
                { role: "hide" },            
                { role: "hideothers" },
                { role: "unhide" },
                { type: "separator" },
                { role: "quit" }
            ],        
        });
    }

    template.push({
        role: "window",
        submenu: [
            { role: "minimize" },
            { role: "zoom" },            
        ]
    });

    const appMenu = Menu.buildFromTemplate(template);
    Menu.setApplicationMenu(appMenu);        
}

export default setAppMenu;

src/main/index.js(アプリケーションメニューを追加)

import { app } from "electron";
import createWindow from "./createWindow";
import setAppMenu from "./setAppMenu";

app.on("ready", () => {
    setAppMenu();
    createWindow();
});

app.on("window-all-closed", () => {
    if(process.platform !== "darwin") {
        app.quit();
    }
});

app.on("activate", (_e, hasVisibleWindows) => {
    if(!hasVisibleWindows) {
        createWindow();
    }
});

こんな感じになりました。

f:id:katekichi:20170514001241p:plain

f:id:katekichi:20170514001252p:plain

f:id:katekichi:20170514001259p:plain

f:id:katekichi:20170514001301p:plain

今回は、メニュー作成するのが少々単純作業で辛かったです・・。 次回は、Firebaseを使用するので、テクニカルな面白味はありそうです。