Skip to content

Commit cc4433c

Browse files
Add support for linux Desktop
1 parent b3b3e3d commit cc4433c

File tree

17 files changed

+346
-104
lines changed

17 files changed

+346
-104
lines changed

.github/workflows/dev-build.yml

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ on:
44
push:
55
branches:
66
- dev
7+
- linux-desktop
78
paths:
89
- 'application/**'
910

1011
jobs:
11-
build-desktop-app:
12+
build-windows-app:
1213
runs-on: windows-latest
1314
steps:
1415
- uses: actions/checkout@v2
@@ -110,3 +111,46 @@ jobs:
110111
path: |
111112
application/dist/Keyboard-Sounds-Setup-windows-x64.exe
112113
application/dist/Keyboard-Sounds-Setup-windows-x64.exe.blockmap
114+
115+
build-linux-app:
116+
runs-on: ubuntu-latest
117+
steps:
118+
- uses: actions/checkout@v2
119+
- name: Set up Python
120+
uses: actions/setup-python@v2
121+
with:
122+
python-version: '3.12'
123+
- name: Install Python dependencies
124+
run: |
125+
python -m pip install --upgrade pip
126+
pip install pyinstaller
127+
pip install -r requirements.txt
128+
- name: Build Runtime
129+
run: ./build-runtime.sh
130+
- name: Copy profiles to application
131+
run: |
132+
Copy-Item -Path ./keyboardsounds/profiles -Destination ./application/.runtime/profiles -Recurse
133+
shell: pwsh
134+
- name: Install Node.js
135+
uses: actions/setup-node@v1
136+
with:
137+
node-version: '18'
138+
- name: Install dependencies
139+
run: npm install
140+
working-directory: ./application
141+
- name: Package Webpack
142+
run: npm run package
143+
working-directory: ./application
144+
- name: Build Installer
145+
run: npm run make-installer:linux
146+
working-directory: ./application
147+
env:
148+
GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
149+
- name: Rename Installer
150+
run: mv "dist/kbs_*.deb" "dist/Keyboard-Sounds-x86_64.deb"
151+
working-directory: ./application
152+
- name: Upload artifacts
153+
uses: actions/upload-artifact@v4
154+
with:
155+
name: build-artifacts
156+
path: application/dist/Keyboard-Sounds-x86_64.deb

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ __pycache__
22
dist
33
keyboardsounds.egg-info
44
build
5-
app-version.txt
5+
app-version.txt
6+
version.py

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Keyboard Sounds is a free application that makes any keyboard sound like a Mecha
3232
<br><br>
3333

3434
> [!NOTE]\
35-
> The desktop application is only available for **Windows**. The [command line application](#command-line-macos-linux-or-windows) can be used on any platform that supports Python.
35+
> The desktop application is only available for **Windows** and **Linux**. The [command line application](#command-line-macos-linux-or-windows) can be used on any platform that supports Python.
3636
3737
## Features
3838

@@ -114,13 +114,15 @@ To enable this window you have several options:
114114

115115
## Uninstalling
116116

117-
You can uninstall the Keyboard Sounds Desktop Application from the "Apps" section of your system Settings application.
117+
### Desktop Application
118118

119-
- Uninstalling the desktop app will **not** remove the Python package from your system, you will need to do this manually if you no longer wish to use the Python package using the following command:
119+
You can uninstall the Keyboard Sounds Desktop Application from the "Apps" section of your system Settings application.
120120

121-
```sh
122-
$ pip uninstall keyboardsounds
123-
```
121+
### Command Line Application
122+
123+
```sh
124+
$ pip uninstall keyboardsounds
125+
```
124126

125127
## Development
126128

application/app_icon.icns

247 KB
Binary file not shown.

application/app_icon.png

80.1 KB
Loading

application/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "kbs-electron",
2+
"name": "kbs",
33
"productName": "Keyboard Sounds",
44
"version": "2.2.0",
55
"description": "https://keyboardsounds.net/",
@@ -33,13 +33,15 @@
3333
},
3434
"linux": {
3535
"target": "deb",
36-
"category": "AudioVideo"
36+
"category": "AudioVideo",
37+
"icon": "./app_icon.icns"
3738
}
3839
},
3940
"scripts": {
4041
"start": "cross-env NODE_ENV=development electron-forge start",
4142
"package": "electron-forge package",
4243
"make-installer:win": "electron-builder -w \"-c.extraMetadata.main=.webpack\\x64\\main\\index.js\"",
44+
"make-installer:linux": "electron-builder -l \"-c.extraMetadata.main=.webpack/x64/main/index.js\"",
4345
"lint": "echo \"No linting configured\""
4446
},
4547
"devDependencies": {

application/src/api/core.js

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ const kbs = {
3030
? path.join(process.cwd(), '.runtime')
3131
: path.join(process.resourcesPath, '.runtime');
3232

33-
return Promise.resolve(path.join(runtimePath, 'kbs.exe'));
33+
const appName = process.platform === 'win32' ? 'kbs.exe' : 'kbs';
34+
35+
return Promise.resolve(path.join(runtimePath, appName));
3436
},
3537

3638
kbsCli: function (cmd, print=true) {
@@ -50,6 +52,10 @@ const kbs = {
5052
});
5153
},
5254

55+
isLinux: function() {
56+
return Promise.resolve(`${process.platform !== 'win32'}`);
57+
},
58+
5359
setSimulateProd: function(val) {
5460
this.simulateProd = val;
5561
},
@@ -722,12 +728,21 @@ const kbs = {
722728
newHeightNum = Number(newHeight);
723729
} catch (e) {}
724730

725-
animateBounds(this.mainWindow, {
726-
x: width - 510,
727-
y: height - newHeightNum - 10,
728-
width: 500,
729-
height: newHeightNum
730-
});
731+
if (process.platform !== 'win32') { // isLinux
732+
animateBounds(this.mainWindow, {
733+
x: this.mainWindow.getBounds().x,
734+
y: this.mainWindow.getBounds().y,
735+
width: 500,
736+
height: newHeightNum
737+
});
738+
} else {
739+
animateBounds(this.mainWindow, {
740+
x: width - 510,
741+
y: height - newHeightNum - 10,
742+
width: 500,
743+
height: newHeightNum
744+
});
745+
}
731746

732747
this.mainWindow.setResizable(false);
733748
}

application/src/main.js

Lines changed: 62 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { app, ipcMain, shell, BrowserWindow, Menu, Tray, screen, dialog } = require('electron');
1+
const { app, ipcMain, shell, BrowserWindow, Menu, Tray, screen, dialog, Notification } = require('electron');
22

33
import path from 'path';
44

@@ -21,7 +21,7 @@ let justShownWindow = false;
2121

2222
// When enabled, even if NODE_ENV=development, the application will still
2323
// act as if it is running in a production state.
24-
const simulateProd = false;
24+
const simulateProd = true;
2525

2626
const toggleWindow = () => {
2727
console.log('toggleWindow() called');
@@ -57,33 +57,23 @@ const toggleWindow = () => {
5757
const { width, height } = screen.getPrimaryDisplay().workAreaSize;
5858
// Calculate the x and y position for the window
5959
// Position the window on the bottom right of the screen
60-
const x = width - appWidth - 10;
61-
const y = height - appHeight - 10;
62-
63-
var extraVars = {};
64-
console.log(`(container) process.env.NODE_ENV=${process.env.NODE_ENV}`);
65-
if (process.env.NODE_ENV === 'development' && !simulateProd) {
66-
extraVars = {
67-
frame: true,
68-
show: true,
69-
resizable: true,
70-
minimizable: true,
71-
skipTaskbar: false,
72-
movable: true,
60+
const coords = {};
61+
62+
if (process.platform === 'win32') {
63+
coords = {
64+
x: width - appWidth - 10,
65+
y: height - appHeight - 10
7366
};
7467
}
7568

76-
// Create the browser window.
77-
mainWindow = new BrowserWindow({
78-
x: x,
79-
y: y,
69+
let appVars = {
70+
...coords,
8071
frame: false,
8172
resizable: false,
8273
movable: false,
8374
minimizable: false,
8475
maximizable: false,
8576
closable: false,
86-
alwaysOnTop: true,
8777
fullscreenable: false,
8878
hiddenInMissionControl: true,
8979
show: false,
@@ -93,12 +83,49 @@ const toggleWindow = () => {
9383
webPreferences: {
9484
preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
9585
},
86+
}
9687

97-
...extraVars,
98-
});
88+
switch(process.platform) {
89+
case 'win32': {
90+
if (process.env.NODE_ENV === 'development' && !simulateProd) {
91+
appVars = {
92+
...appVars,
93+
frame: true,
94+
show: true,
95+
resizable: true,
96+
minimizable: true,
97+
skipTaskbar: false,
98+
alwaysOnTop: true,
99+
movable: true,
100+
}
101+
} else {
102+
appVars = {
103+
...appVars,
104+
alwaysOnTop: true,
105+
}
106+
}
107+
}
108+
109+
default: {
110+
appVars = {
111+
...appVars,
112+
frame: true,
113+
show: true,
114+
minimizable: true,
115+
movable: true,
116+
}
117+
}
118+
}
119+
120+
// Create the browser window.
121+
mainWindow = new BrowserWindow(appVars);
99122

100-
// Close the window when it loses focus.
101123
if (process.env.NODE_ENV !== 'development' || simulateProd) {
124+
mainWindow.setMenuBarVisibility(false);
125+
}
126+
127+
// Close the window when it loses focus.
128+
if ((process.env.NODE_ENV !== 'development' || simulateProd) && process.platform === 'win32') {
102129
mainWindow.on('blur', async () => {
103130
// Don't hide if we just showed the window (prevents race condition)
104131
if (justShownWindow) {
@@ -268,21 +295,23 @@ app.whenReady().then(async () => {
268295
toggleWindow();
269296

270297
// Wait for the main window to be ready before proceeding
271-
await new Promise((resolve) => {
272-
if (mainWindow && !mainWindow.isDestroyed()) {
273-
if (mainWindow.webContents.isLoading()) {
274-
mainWindow.webContents.once('did-finish-load', () => {
298+
if (process.platform === 'win32') {
299+
await new Promise((resolve) => {
300+
if (mainWindow && !mainWindow.isDestroyed()) {
301+
if (mainWindow.webContents.isLoading()) {
302+
mainWindow.webContents.once('did-finish-load', () => {
303+
mainWindow.hide();
304+
resolve();
305+
});
306+
} else {
275307
mainWindow.hide();
276308
resolve();
277-
});
309+
}
278310
} else {
279-
mainWindow.hide();
280311
resolve();
281312
}
282-
} else {
283-
resolve();
284-
}
285-
});
313+
});
314+
}
286315

287316
// Initialize system tray
288317
await initializeSystemTrayAndApp();

application/src/ui/app.jsx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ function App() {
152152
const [runOnStartUp, setRunOnStartup] = useState(true);
153153
const [enableDaemonWindow, setEnableDaemonWindow] = useState(true);
154154
const [runSoundDaemonOnStartup, setRunSoundDaemonOnStartup] = useState(true);
155+
const [isLinux, setIsLinux] = useState(false);
155156

156157
// Get the version from the backend
157158
useEffect(() => {
@@ -168,6 +169,13 @@ function App() {
168169
};
169170
run();
170171
}, []);
172+
useEffect(() => {
173+
const run = async () => {
174+
const isLinux = await execute("isLinux");
175+
setIsLinux(isLinux === `${true}`);
176+
};
177+
run();
178+
}, []);
171179

172180
// Load the profile, volume, pitch shift and notification preferences from the backend
173181
useEffect(() => {
@@ -497,9 +505,9 @@ function App() {
497505
useEffect(() => {
498506
if (selectedTab === 0) { // Audio
499507
execute(`setHeight 790`);
500-
} else if (selectedTab === 3) { // Settings
501-
execute(`setHeight 932`);
502-
} else if (selectedTab === 4) { // Community
508+
} else if (selectedTab === (isLinux ? 2 : 3)) { // Settings
509+
execute(`setHeight ${isLinux ? 852 : 932}`);
510+
} else if (selectedTab === (isLinux ? 3 : 4)) { // Community
503511
execute(`setHeight 796`);
504512
} else { // All Other Pages
505513
execute(`setHeight 800`);
@@ -604,7 +612,7 @@ function App() {
604612
>
605613
<Tooltip title="Audio" arrow><Tab icon={<GraphicEqIcon />} /></Tooltip>
606614
<Tooltip title="Profiles" arrow><Tab icon={<LibraryMusicIcon />} /></Tooltip>
607-
<Tooltip title="Rules" arrow><Tab icon={<GavelIcon />} /></Tooltip>
615+
{!isLinux && (<Tooltip title="Rules" arrow><Tab icon={<GavelIcon />} /></Tooltip>)}
608616
<Tooltip title="Settings" arrow><Tab icon={<SettingsIcon />} /></Tooltip>
609617
<Tooltip title="Community" arrow><Tab icon={<ForumIcon />} /></Tooltip>
610618
</Tabs>
@@ -644,7 +652,7 @@ function App() {
644652
/>
645653
)}
646654

647-
{selectedTab === 2 && (
655+
{selectedTab === 2 && !isLinux && (
648656
<AppRules
649657
appRules={appRules}
650658
appRulesLoaded={appRulesLoaded}
@@ -654,7 +662,7 @@ function App() {
654662
/>
655663
)}
656664

657-
{selectedTab === 3 && (
665+
{selectedTab === (isLinux ? 2 : 3) && (
658666
<Settings
659667
appVersion={appVersion}
660668
backEndVersion={backEndVersion}
@@ -673,7 +681,7 @@ function App() {
673681
/>
674682
)}
675683

676-
{selectedTab === 4 && (
684+
{selectedTab === (isLinux ? 3 : 4) && (
677685
<About />
678686
)}
679687
</Box>

0 commit comments

Comments
 (0)