Help us understand the problem. What is going on with this article?

【Electron入門】GithubのIssueを一瞬で確認できるアプリを作って業務効率化してみた #1 Alfredっぽいwindow作成編

完成品

option(alt) + Spaceで表示/非表示が切り替えられます。

scc.gif

ソースコード

https://github.com/ikkei12/git-app.pub

はじめに

image.png

Alfred最高ですよね。
彼のおかげでマウスを使う頻度が激減して助かっています。

Alfredと同じ手軽さで、自分がアサインされているissueを確認できるデスクトップアプリが作りたいなと思ったので、Electronで作ってみようと思いました。

Electronには

  • JavaScriptで作れる
  • Chromiumベースなのでwebエンジニアにも優しい

といった利点があり、HTML/CSS/JavaScriptを学んだ初心者の方でも扱いやすいかと思います!

Electronのはじめかた

基本的に公式ドキュメントを参考にElectronのセットアップをするだけですが、一部変更を加えています。

1. 以下のコマンドを実行

mkdir git-app && cd git-app
npm init -y
npm i --save-dev electron
npm i --save-dev electron-builder

2. html/jsファイルを作成

標準的なNode.jsアプリと同様に以下のような構成で始めます。

git-app/
├── package.json
├── main.js
└── index.html
main.js
const { app, BrowserWindow } = require('electron')

function createWindow () {
  const win = new BrowserWindow({
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: true,
    },
    frame: false,
    alwaysOnTop: true,
    useContentSize: true,
    transparent: true,
  })

  win.loadFile('index.html')

  win.on("blur", (e) => {
    // window外をクリックしたタイミング(blur)で閉じる
    app.hide();
  });
}

app.whenReady().then(createWindow)

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

app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow()
  }
})
index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World!</title>
    <meta
      http-equiv="Content-Security-Policy"
      content="script-src 'self' 'unsafe-inline';"
    />
  </head>
  <body style="-webkit-app-region: drag">
    <div style="background: #fff; height: 300px">
      <h1>Hello World!</h1>
    </div>
  </body>
</html>

3. package.jsonを修正

package.jsonは以下のように書き換えます。

package.json
{
  "name": "git-app",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "NODE_ENV=development electron .",
    "build": "NODE_ENV=production electron-builder"
  },
  "build": {
    "appId": "git-app",
    "mac": {
      "category": "git-app"
    }
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "electron": "^10.1.5"
  }
}

4. 起動

npm start
でこのようなwindowが表示されると思います。

image.png

どこからでもショートカットでアプリを呼び出せるようにする

このままではwindowの表示/非表示を切り替えられないし、PCの起動時に毎回アプリを立ち上げる必要があります。

Alfredのような挙動を実現するには
 1. electronアプリを常駐で起動させておいて、
 2. 表示/非表示を切り替えるショートカットを登録する
必要があります。

1. electronアプリを常駐で起動させる

main.js
app.dock.hide();

if (process.env.NODE_ENV !== "development") {
  app.setLoginItemSettings({
    openAtLogin: true,
    path: app.getPath("exe"),
  });
}

解説

app.dock.hide()
常駐のアプリをDockに表示したくないので、Dockから非表示にします。

app.setLoginItemSettings()
でログイン時に自動で起動してくれるようになります。
ローカルでは起動したくないので、NODE_ENVで判定しています。

・macではログイン時に起動されるアプリは
ユーザーとグループ > ログイン項目に追加されます。
image.png

2. 表示/非表示を切り替えるショートカットを登録する

main.js
app.on("ready", function () {
  globalShortcut.register("alt+space", function () {
    // 現在focusしているwindowを取得
    const window = BrowserWindow.getFocusedWindow();
    // windowが存在すればhide、なければshow
    window ? hideWindow(window) : showWindow();
  });
});

app.on("will-quit", function () {
  // 終了するタイミングで全てのglobalShortcutを解除
  globalShortcut.unregisterAll();
});

function showWindow() {
  // focusさせる事でBrowserWindowのblurイベントを検知させる
  app.focus({ steal: true });
  app.show();
}

function hideWindow(window) {
  // center()する事でshowする時に中央で表示される
  window.center();
  app.hide();
}

解説

・アプリがready状態になった段階で、ショートカットキーを登録しています。自分はalt+spaceで起動したいのでregisterの第一引数に渡しています。

・第二引数ではショートカットキーが押されたタイミングで実行する関数を登録しています。現在focusされているwindowを取得し、存在する場合はhideメソッド、しなければshowメソッドを実行する事で表示を切り替えています。

globalShortcutと言うのがポイントで、普通のショートカット(localShortcut)ではElectronアプリがフォアグラウンドになっている場合にしか反応しません。


このように動くと思います!

test.gif

Tips

Windowをドラッグできるようにする

<body style="-webkit-app-region: drag">

参考: https://www.electronjs.org/docs/api/frameless-window#draggable-region

まとめ

ご覧いただきありがとうございました!
次回はGithub APIからIssueを取得して表示する部分を作成していきます!

#2 GithubAPI編

Twitterのフォローもお願い致します!
https://twitter.com/1keiuu

ikkei12
都内のスタートアップでインターンをしている学生です。 週1~2の更新を目標に頑張ってます! Twitterのフォローもお願いします!
https://1k-cove.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away