Compare commits

...

36 Commits

Author SHA1 Message Date
stoat-release[bot] c1e4d4ee91 chore(main): release 1.3.0 (#128)
Co-authored-by: stoat-release[bot] <245062572+stoat-release[bot]@users.noreply.github.com>
2026-02-18 09:09:14 +00:00
Jacob Schlecht ffe17ec2c5 fix: flatpak icons not building correctly and wayland support (#132)
This commit was made without the use of generative AI.

Signed-off-by: Jacob Schlecht <dadadah@echoha.us>
2026-02-18 09:05:56 +00:00
Mihai 63b9ea818a fix: firstLaunch = false after initial setup (#131)
fix: don't re-enable abutostart

Signed-off-by: Mihai <cristian@mihaimuresan.com>
Co-authored-by: Mihai <cristian@mihaimuresan.com>
2026-02-17 22:33:46 -05:00
Paul Makles 58ccb63d23 fix: use template icon for macOS tray, use higher res icons for other platforms (#130) 2026-02-17 20:36:25 +00:00
Mihai 8284117e76 feat: minimise-to-tray-on-startup (#126)
* feat: minimise-to-tray-on-startup

Signed-off-by: Mihai <cristian@mihaimuresan.com>

* feat: minimise-to-tray-on-startup

Signed-off-by: Mihai <cristian@mihaimuresan.com>

* fix: redundant call

Signed-off-by: Mihai <cristian@mihaimuresan.com>

* fix: redundant call

Signed-off-by: Mihai <cristian@mihaimuresan.com>

---------

Signed-off-by: Mihai <cristian@mihaimuresan.com>
Co-authored-by: Mihai <cristian@mihaimuresan.com>
2026-02-17 20:28:29 +00:00
Mihai 897d706983 fix: try to restore maximised windows to correct display (#92)
fix: App-maximized-2nd-monitor

Signed-off-by: Mihai <cristian@mihaimuresan.com>
Signed-off-by: Mihai <45673304+mihaicm93@users.noreply.github.com>
Co-authored-by: Mihai <cristian@mihaimuresan.com>
2026-02-17 20:27:01 +00:00
dxty522 7d2f296ca7 fix: replace default dialog with notification (#98)
Signed-off-by: dxty522 <261609953+dxty522@users.noreply.github.com>
2026-02-17 20:05:26 +00:00
Abel Ortolan 17d6d174ae chore: changing flatpak runtime version to newest stable release (#120)
Update forge.config.ts

Changing Flatpak runtime version from 21.08 (EOL) to 25.08 (newest stable version)

Signed-off-by: Abel Ortolan <70042422+TrojanHorse-bot@users.noreply.github.com>
2026-02-17 20:02:46 +00:00
trendwhore 742a95f3cb fix: toggle window visibility on tray click instead of always showing (#103) 2026-02-17 20:02:17 +00:00
a distraction 2b962c5d06 fix: allow CTRL+"+" to also zoom in. (#108)
Allow "+" to also zoom in.

Signed-off-by: a distraction <106486896+dresklaw@users.noreply.github.com>
Co-authored-by: Paul Makles <me@insrt.uk>
2026-02-17 19:59:18 +00:00
a distraction def29f9b3c fix: Add common zoom-reset shortcut. (#112)
Add common zoom reset shortcut.

Signed-off-by: a distraction <106486896+dresklaw@users.noreply.github.com>
Signed-off-by: marcy <69540471+reeesespuffs@users.noreply.github.com>
Co-authored-by: marcy <69540471+reeesespuffs@users.noreply.github.com>
2026-02-17 14:35:57 -05:00
Paul Makles e2dc20b755 chore: Nix, mise, CI configuration (#129)
* chore: update Nix flake and setup mise for toolchains

* ci: use workflows
2026-02-17 19:29:43 +00:00
Mihai 2e99b19353 feat: Reload/Refresh shortcut (#119)
Signed-off-by: Mihai <cristian@mihaimuresan.com>
Co-authored-by: Mihai <cristian@mihaimuresan.com>
2026-02-17 14:21:57 -05:00
sfalken 1243f88b21 chore: add files to manage flathub details upstream (#104)
* Add files for flathub compliance

Please see: https://github.com/flathub/flathub/pull/7783

This adds the requested files to the upstream git repo, and adds the
screenshot.png so it may be sourced from Stoat, rather than from a user
repository.

* chore: update product screenshot

* chore: update desktop entry comment

* chore: update icon

* chore: update summary to current github tag

---------

Co-authored-by: Shawn W Dunn <sfalken@opensuse.org>
Co-authored-by: izzy <me@insrt.uk>
2026-02-17 19:04:04 +00:00
V3RM1N 7d3d80ae6e docs: add installation section to README (#81)
Add Installation section with Repology badge and links to download page and GitHub releases

Signed-off-by: V3RM1N <mail@v3rm1n.dev>
2026-02-17 18:59:29 +00:00
stoat-release[bot] b765e84151 chore(main): release 1.2.0 (#79)
Co-authored-by: stoat-release[bot] <245062572+stoat-release[bot]@users.noreply.github.com>
2026-02-14 00:51:45 +00:00
Paul Makles 8910dcba92 feat: new branding (#87)
Signed-off-by: izzy <me@insrt.uk>
2026-02-14 00:41:34 +00:00
Mihai 127d1430a9 fix: App Autostart (#68)
Signed-off-by: Mihai <cristian@mihaimuresan.com>
Co-authored-by: Mihai <cristian@mihaimuresan.com>
2026-02-13 00:25:05 -05:00
Jespercal 3bf697d1a9 feat: persist and restore window size and position (#74)
Finished up saving and restoring of window position and size

Signed-off-by: Jespercal <chap600@hotmail.com>
2026-02-13 00:16:53 -05:00
Paul Makles a162219668 Revert "fix: add NixOS compatibility for electron startup (#23)" (#42)
This reverts commit 3eb9b8e84b.

Signed-off-by: izzy <me@insrt.uk>
2026-02-09 19:38:58 +00:00
stoat-tofu[bot] dad885aa1d chore: modify .github/workflows/release-webhook.yml 2026-01-10 16:33:15 +00:00
stoat-tofu[bot] 7b9918f43b chore: modify .github/workflows/release-webhook.yml 2026-01-10 13:19:22 +00:00
stoat-release[bot] 6ca1143c22 chore(main): release 1.1.12 (#28)
Co-authored-by: stoat-release[bot] <245062572+stoat-release[bot]@users.noreply.github.com>
2025-12-29 18:06:33 +00:00
Paul Makles e431f205c2 refactor: move publish.yml workflow into release please workflow (#29) 2025-12-29 18:05:26 +00:00
Paul Makles eac8195f68 chore: configure release please (#27) 2025-12-29 17:55:58 +00:00
Paul Makles ea7c57962b chore: use Stoat name for auto launch entry (#24) 2025-12-29 17:55:55 +00:00
Paul Makles 96fa8cc647 fix: event listener accumulation from rpc client (#26) 2025-12-29 17:47:33 +00:00
Paul Makles 6817b554e5 fix: correctly load badge count; expose to renderer (#25) 2025-12-29 17:47:24 +00:00
Paul Makles cb373b6dc6 fix: rpc should define largeImageText (#21) 2025-12-29 17:00:09 +00:00
Paul Makles 532af4a680 fix: use the correct argument for auto start (#22)
fixes #20
2025-12-29 16:59:49 +00:00
Paul Makles 3eb9b8e84b fix: add NixOS compatibility for electron startup (#23)
- Add start.sh script that auto-detects NixOS and configures electron path
- Script dynamically finds the correct electron version from nix store
- Keeps original electron-forge start available as start:forge
- Fixes electron launch issues on NixOS systems

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-29 16:59:31 +00:00
stoat-tofu[bot] 6907a33dc7 chore: modify .github/workflows/validate-pr-title.yml 2025-11-14 20:24:54 +00:00
izzy 1aa5f7e1c3 chore: update assets submodule [skip ci]
docs: remove pub. notes
2025-10-20 15:04:24 +01:00
Paul Makles e11c0490fc merge: pull request #4 from e1berd/fix/macos-tray-icon 2025-10-14 17:33:56 +01:00
l 61ffe199ee chore(macos): remove useless comment 2025-10-10 19:29:43 +03:00
l 5eecab5943 fix(macos): tray icon size 2025-10-10 19:24:53 +03:00
28 changed files with 429 additions and 76 deletions
+5 -10
View File
@@ -1,7 +1,8 @@
on: on:
push: push:
branches: branches:
- "**" - main
pull_request:
jobs: jobs:
build: build:
@@ -15,16 +16,10 @@ jobs:
- name: Checkout assets - name: Checkout assets
run: git -c submodule."assets".update=checkout submodule update --init assets run: git -c submodule."assets".update=checkout submodule update --init assets
- name: Install pnpm - name: Setup Mise
uses: pnpm/action-setup@v4 uses: immich-app/devtools/actions/use-mise@cd24790a7f5f6439ac32cc94f5523cb2de8bfa8c # use-mise-action-v1.1.0
with: with:
run_install: false github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: "pnpm"
- name: Install dependencies - name: Install dependencies
run: pnpm install run: pnpm install
+19
View File
@@ -0,0 +1,19 @@
name: Git Town
on:
pull_request:
jobs:
git-town:
name: Display the branch stack
runs-on: ubuntu-slim
if: ${{ !startsWith(github.head_ref, 'release-please--') }}
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: stoatchat/action-git-town@4bc5c942e4603bffa0806b51d5fe5f0bc5deb0ac
@@ -1,11 +1,41 @@
name: Release Please
on: on:
push: push:
tags: branches: [main] # updates/opens the release PR when commits land on main
- v* workflow_dispatch:
permissions:
contents: write
pull-requests: write
id-token: write
concurrency:
group: release-please
cancel-in-progress: true
jobs: jobs:
release: release-please:
name: Release Please
runs-on: ubuntu-latest
outputs:
release_created: ${{ steps.rp.outputs.release_created }}
steps:
- id: app-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.GH_STOAT_RELEASE_APP_ID }}
private-key: ${{ secrets.GH_STOAT_RELEASE_APP_PRIVATE_KEY }}
- id: rp
uses: googleapis/release-please-action@v4
with:
token: ${{ steps.app-token.outputs.token }}
config-file: release-please-config.json
publish-release:
name: Publish App name: Publish App
needs: release-please
if: needs.release-please.outputs.release_created == 'true'
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
permissions: permissions:
+19
View File
@@ -0,0 +1,19 @@
name: Release Webhook
on:
workflow_dispatch:
release:
types: [published]
jobs:
release-webhook:
name: Send Release Webhook
runs-on: ubuntu-latest
steps:
- name: Send release notification webhook
run: |
RELEASE_URL="https://github.com/${{ github.repository }}/releases/tag/${{ github.event.release.tag_name }}"
curl -X POST "${{ secrets.STOAT_WEBHOOK_UPDATES_URL }}" \
-H "Content-Type: application/json" \
-d "{\"content\": \"$RELEASE_URL\"}"
+20
View File
@@ -0,0 +1,20 @@
name: "Lint PR"
on:
pull_request_target:
types:
- opened
- reopened
- edited
- synchronize
jobs:
main:
name: Validate PR title
runs-on: ubuntu-latest
permissions:
pull-requests: read
steps:
- uses: amannn/action-semantic-pull-request@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+3
View File
@@ -0,0 +1,3 @@
{
".": "1.3.0"
}
+48
View File
@@ -0,0 +1,48 @@
# Changelog
## [1.3.0](https://github.com/stoatchat/for-desktop/compare/v1.2.0...v1.3.0) (2026-02-18)
### Features
* minimise-to-tray-on-startup ([#126](https://github.com/stoatchat/for-desktop/issues/126)) ([8284117](https://github.com/stoatchat/for-desktop/commit/8284117e76c0fcff4091de3ef623014e4594a593))
* Reload/Refresh shortcut ([#119](https://github.com/stoatchat/for-desktop/issues/119)) ([2e99b19](https://github.com/stoatchat/for-desktop/commit/2e99b19353fbd45d9fdf1d148bae3a8a19c788ed))
### Bug Fixes
* Add common zoom-reset shortcut. ([#112](https://github.com/stoatchat/for-desktop/issues/112)) ([def29f9](https://github.com/stoatchat/for-desktop/commit/def29f9b3c1205944aab58beb8000815d41633b5))
* allow CTRL+"+" to also zoom in. ([#108](https://github.com/stoatchat/for-desktop/issues/108)) ([2b962c5](https://github.com/stoatchat/for-desktop/commit/2b962c5d066787601223368ee7dcc1e46a345b8a))
* App-maximized-2nd-monitor ([897d706](https://github.com/stoatchat/for-desktop/commit/897d706983a347938a2fb42ba8e58e40794bba13))
* don't re-enable abutostart ([63b9ea8](https://github.com/stoatchat/for-desktop/commit/63b9ea818a9f32ca8535948e18752726c0f50a12))
* firstLaunch = false after initial setup ([#131](https://github.com/stoatchat/for-desktop/issues/131)) ([63b9ea8](https://github.com/stoatchat/for-desktop/commit/63b9ea818a9f32ca8535948e18752726c0f50a12))
* flatpak icons not building correctly and wayland support ([#132](https://github.com/stoatchat/for-desktop/issues/132)) ([ffe17ec](https://github.com/stoatchat/for-desktop/commit/ffe17ec2c54fca6967435b8a4ada7fa8d4da7b33))
* replace default dialog with notification ([#98](https://github.com/stoatchat/for-desktop/issues/98)) ([7d2f296](https://github.com/stoatchat/for-desktop/commit/7d2f296ca72bbd7ad694c66a917d47067f883fc5))
* toggle window visibility on tray click instead of always showing ([#103](https://github.com/stoatchat/for-desktop/issues/103)) ([742a95f](https://github.com/stoatchat/for-desktop/commit/742a95f3cb820c5b5398c815b7b45017b6b06053))
* try to restore maximised windows to correct display ([#92](https://github.com/stoatchat/for-desktop/issues/92)) ([897d706](https://github.com/stoatchat/for-desktop/commit/897d706983a347938a2fb42ba8e58e40794bba13))
* use template icon for macOS tray, use higher res icons for other platforms ([#130](https://github.com/stoatchat/for-desktop/issues/130)) ([58ccb63](https://github.com/stoatchat/for-desktop/commit/58ccb63d23541a03e05a48a37a98f883a2ba0d3f))
## [1.2.0](https://github.com/stoatchat/for-desktop/compare/v1.1.12...v1.2.0) (2026-02-14)
### Features
* new branding ([#87](https://github.com/stoatchat/for-desktop/issues/87)) ([8910dcb](https://github.com/stoatchat/for-desktop/commit/8910dcba923b55df789c0541b59a6a6321a28768))
* persist and restore window size and position ([#74](https://github.com/stoatchat/for-desktop/issues/74)) ([3bf697d](https://github.com/stoatchat/for-desktop/commit/3bf697d1a9aba739b6954c8469223f51093497cc))
### Bug Fixes
* App Autostart ([#68](https://github.com/stoatchat/for-desktop/issues/68)) ([127d143](https://github.com/stoatchat/for-desktop/commit/127d1430a9c630e0429c9cc50d57ee316a63ebe5))
## [1.1.12](https://github.com/stoatchat/for-desktop/compare/v1.1.11...v1.1.12) (2025-12-29)
### Bug Fixes
* add NixOS compatibility for electron startup ([#23](https://github.com/stoatchat/for-desktop/issues/23)) ([3eb9b8e](https://github.com/stoatchat/for-desktop/commit/3eb9b8e84bf05debf9843b80c468911fd095f4a0))
* correctly load badge count; expose to renderer ([#25](https://github.com/stoatchat/for-desktop/issues/25)) ([6817b55](https://github.com/stoatchat/for-desktop/commit/6817b554e57c5a65b7b4aca7d1cc4e05cd6f01b7))
* event listener accumulation from rpc client ([#26](https://github.com/stoatchat/for-desktop/issues/26)) ([96fa8cc](https://github.com/stoatchat/for-desktop/commit/96fa8cc647029cb53e5d619b94debc6cdfdf32f6))
* **macos:** tray icon size ([5eecab5](https://github.com/stoatchat/for-desktop/commit/5eecab59431cb4966eaa1fc907a8e5c16c813230))
* rpc should define largeImageText ([#21](https://github.com/stoatchat/for-desktop/issues/21)) ([cb373b6](https://github.com/stoatchat/for-desktop/commit/cb373b6dc62630147151039c3711aef74c8c2d88))
* use the correct argument for auto start ([#22](https://github.com/stoatchat/for-desktop/issues/22)) ([532af4a](https://github.com/stoatchat/for-desktop/commit/532af4a680069f72734148b0ccdacec6c435e640)), closes [#20](https://github.com/stoatchat/for-desktop/issues/20)
+8 -8
View File
@@ -13,6 +13,14 @@ Application for Windows, macOS, and Linux.
</div> </div>
<br/> <br/>
## Installation
<a href="https://repology.org/project/stoat-desktop/versions">
<img src="https://repology.org/badge/vertical-allrepos/stoat-desktop.svg" alt="Packaging status" align="right">
</a>
- All downloads and instructions for Stoat can be found on our [Website](https://stoat.chat/download).
## Development Guide ## Development Guide
_Contribution guidelines for Desktop app TBA!_ _Contribution guidelines for Desktop app TBA!_
@@ -74,11 +82,3 @@ git -c submodule."assets".update=checkout submodule update --init assets
``` ```
Currently, this is required to build, any forks are expected to provide their own assets. Currently, this is required to build, any forks are expected to provide their own assets.
## Publishing Guide
To publish a new version, simply tag a new release by:
1. Edit `package.json` with the new version
2. Create a new tag from latest commit by `git tag v1.0.0`
3. Push the tag and commit by `git push --atomic origin main v1.0.0`
+1 -1
Submodule assets updated: 628eb2f825...bd432f2298
+11
View File
@@ -0,0 +1,11 @@
[Desktop Entry]
Name=Stoat
Comment=Open source, user-first chat platform
Exec=stoat-desktop
Terminal=false
Type=Application
Icon=chat.stoat.StoatDesktop
Categories=Network;InstantMessaging
StartupWMClass=stoat-desktop
X-Desktop-File-Install-Version=0.26
X-Flatpak=chat.stoat.StoatDesktop
+70
View File
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop">
<id>chat.stoat.StoatDesktop</id>
<launchable type="desktop-id">chat.stoat.StoatDesktop.desktop</launchable>
<name>Stoat</name>
<developer id="chat.stoat">
<name>Revolt Platforms Ltd</name>
</developer>
<summary>Open source, user-first chat platform</summary>
<metadata_license>CC0-1.0</metadata_license>
<project_license>AGPL-3.0</project_license>
<icon type="remote" height="256" width="256">
https://raw.githubusercontent.com/stoatchat/assets/f106946659af67ad4f008588ac51570029b2fd47/desktop/icon.png</icon>
<description>
<p>Stoat is an open source, user-first chat platform. Send messages, share
images, mention users, and join voice channels — all from a native desktop
application.</p>
</description>
<screenshots>
<screenshot type="default">
<caption>Main window</caption>
<image>screenshot.png</image>
</screenshot>
</screenshots>
<releases>
<release date="2026-02-14" version="1.2.0">
<description>
<p>Features:</p>
<ul>
<li>New Branding</li>
<li>Persist and restore window size and position</li>
</ul>
<p>Bug Fixes:</p>
<ul>
<li>App Autostart</li>
</ul>
</description>
</release>
<release date="2025-12-29" version="1.1.12">
<description>
<p>Bug fixes:</p>
<ul>
<li>Add NixOS compatibility for electron startup</li>
<li>Correctly load badge count; expose to renderer</li>
<li>Fix event listener accumulation from rpc client</li>
<li>Fix macOS tray icon size</li>
<li>Fix RPC largeImageText</li>
<li>Use the correct argument for auto start</li>
</ul>
</description>
</release>
</releases>
<url type="bugtracker">https://github.com/stoatchat/for-desktop/issues</url>
<url type="homepage">https://stoat.chat</url>
<url type="vcs-browser">https://github.com/stoatchat/for-desktop</url>
<content_rating type="oars-1.1">
<content_attribute id="social-chat">intense</content_attribute>
<content_attribute id="social-info">intense</content_attribute>
<content_attribute id="social-audio">intense</content_attribute>
<content_attribute id="social-contacts">intense</content_attribute>
</content_rating>
<requires>
<display_length compare="ge">940</display_length>
<internet>always</internet>
</requires>
<supports>
<control>keyboard</control>
<control>pointing</control>
</supports>
</component>
+16 -9
View File
@@ -1,16 +1,13 @@
{ { pkgs ? import (fetchTarball {
pkgs ? import <nixpkgs> { }, url = "https://github.com/NixOS/nixpkgs/archive/77ef7a29d276c6d8303aece3444d61118ef71ac2.tar.gz";
sha256 = "0pm4l48jq8plzrrrisimahxqlcpx7qqq9c99hylmf7p3zlc3phsy";
}) {},
}: }:
pkgs.mkShell rec { pkgs.mkShell rec {
buildInputs = [ buildInputs = with pkgs; [
# Tools # Tools
pkgs.git pkgs.mise
pkgs.gh
# Node
pkgs.nodejs
pkgs.nodejs.pkgs.pnpm
# Electron # Electron
(pkgs.writeShellScriptBin "electron-nix" '' (pkgs.writeShellScriptBin "electron-nix" ''
@@ -29,5 +26,15 @@ pkgs.mkShell rec {
pkgs.flatpak-builder pkgs.flatpak-builder
pkgs.elfutils pkgs.elfutils
# flatpak remote-add --if-not-exists --user flathub https://dl.flathub.org/repo/flathub.flatpakrepo # flatpak remote-add --if-not-exists --user flathub https://dl.flathub.org/repo/flathub.flatpakrepo
(writeShellScriptBin "fish" ''
exec ${pkgs.fish}/bin/fish -C 'mise activate fish | source' "$@"
'')
]; ];
shellHook = ''
export ELECTRON_OVERRIDE_DIST_PATH="${pkgs.electron}/bin"
export MISE_NODE_COMPILE=false
eval "$(mise activate bash)"
'';
} }
+10 -3
View File
@@ -58,8 +58,15 @@ if (!process.env.PLATFORM) {
description: STRINGS.description, description: STRINGS.description,
productName: STRINGS.name, productName: STRINGS.name,
productDescription: STRINGS.description, productDescription: STRINGS.description,
runtimeVersion: "21.08", runtimeVersion: "25.08",
icon: `${ASSET_DIR}/icon.png`, icon: {
"16x16": `${ASSET_DIR}/hicolor/16x16.png`,
"32x32": `${ASSET_DIR}/hicolor/32x32.png`,
"64x64": `${ASSET_DIR}/hicolor/64x64.png`,
"128x128": `${ASSET_DIR}/hicolor/128x128.png`,
"256x256": `${ASSET_DIR}/hicolor/256x256.png`,
"512x512": `${ASSET_DIR}/hicolor/512x512.png`,
} as unknown,
categories: ["Network"], categories: ["Network"],
modules: [ modules: [
// use the latest zypak -- Electron sandboxing for Flatpak // use the latest zypak -- Electron sandboxing for Flatpak
@@ -77,7 +84,7 @@ if (!process.env.PLATFORM) {
finishArgs: [ finishArgs: [
// default arguments found by running // default arguments found by running
// DEBUG=electron-installer-flatpak* pnpm make // DEBUG=electron-installer-flatpak* pnpm make
"--socket=x11", "--socket=fallback-x11",
"--share=ipc", "--share=ipc",
"--device=dri", "--device=dri",
"--socket=pulseaudio", "--socket=pulseaudio",
+5
View File
@@ -0,0 +1,5 @@
[tools]
node = "25.4.0"
pnpm = "10.28.1"
gh = "2.25.0"
"github:git-town/git-town" = "22.4.0"
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "stoat-desktop", "name": "stoat-desktop",
"productName": "stoat-desktop", "productName": "stoat-desktop",
"version": "1.1.11", "version": "1.3.0",
"main": ".vite/build/main.js", "main": ".vite/build/main.js",
"repository": "stoatchat/desktop", "repository": "stoatchat/desktop",
"scripts": { "scripts": {
+2
View File
@@ -1,7 +1,9 @@
nodeLinker: hoisted nodeLinker: hoisted
onlyBuiltDependencies: onlyBuiltDependencies:
- bufferutil
- electron - electron
- electron-winstaller - electron-winstaller
- esbuild - esbuild
- register-scheme - register-scheme
- utf-8-validate
+14
View File
@@ -0,0 +1,14 @@
{
"packages": {
".": {
"changelog-path": "CHANGELOG.md",
"release-type": "node",
"bump-minor-pre-major": false,
"bump-patch-for-minor-pre-major": false,
"draft": false,
"prerelease": false,
"include-component-in-tag": false
}
},
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 702 KiB

+4
View File
@@ -6,6 +6,10 @@ declare type DesktopConfig = {
hardwareAcceleration: boolean; hardwareAcceleration: boolean;
discordRpc: boolean; discordRpc: boolean;
windowState: { windowState: {
x: number;
y: number;
width: number;
height: number;
isMaximised: boolean; isMaximised: boolean;
}; };
}; };
+17 -5
View File
@@ -1,6 +1,6 @@
import { updateElectronApp } from "update-electron-app"; import { IUpdateInfo, updateElectronApp } from "update-electron-app";
import { BrowserWindow, app, shell } from "electron"; import { BrowserWindow, Notification, app, shell } from "electron";
import started from "electron-squirrel-startup"; import started from "electron-squirrel-startup";
import { autoLaunch } from "./native/autoLaunch"; import { autoLaunch } from "./native/autoLaunch";
@@ -24,21 +24,33 @@ if (!config.hardwareAcceleration) {
// ensure only one copy of the application can run // ensure only one copy of the application can run
const acquiredLock = app.requestSingleInstanceLock(); const acquiredLock = app.requestSingleInstanceLock();
const onNotifyUser = (_info: IUpdateInfo) => {
const notification = new Notification({
title: "Update Available",
body: "Restart the app to install the update.",
silent: true,
});
notification.show();
};
if (acquiredLock) { if (acquiredLock) {
// start auto update logic // start auto update logic
updateElectronApp(); updateElectronApp({ onNotifyUser });
// create and configure the app when electron is ready // create and configure the app when electron is ready
app.on("ready", () => { app.on("ready", () => {
// create window and application contexts
createMainWindow();
// enable auto start on Windows and MacOS // enable auto start on Windows and MacOS
if (config.firstLaunch) { if (config.firstLaunch) {
if (process.platform === "win32" || process.platform === "darwin") { if (process.platform === "win32" || process.platform === "darwin") {
autoLaunch.enable(); autoLaunch.enable();
} }
config.firstLaunch = false;
} }
// create window and application contexts
createMainWindow();
initTray(); initTray();
initDiscordRpc(); initDiscordRpc();
+17 -9
View File
@@ -5,15 +5,23 @@ import { ipcMain } from "electron";
import { mainWindow } from "./window"; import { mainWindow } from "./window";
export const autoLaunch = new AutoLaunch({ export const autoLaunch = new AutoLaunch({
name: "Revolt", name: "Stoat",
}); });
ipcMain.on("isAutostart?", () => ipcMain.handle("getAutostart", async () => {
autoLaunch const enabled = await autoLaunch.isEnabled();
.isEnabled() return enabled;
.then((enabled) => mainWindow.webContents.send("isAutostart", enabled)), });
);
ipcMain.on("setAutostart", (state) => ipcMain.handle("setAutostart", async (_event, state: boolean) => {
state ? autoLaunch.enable() : autoLaunch.disable(), if (state) {
); await autoLaunch.enable();
console.log("Received new configuration autoStart: true");
} else {
await autoLaunch.disable();
console.log("Received new configuration autoStart: false");
}
const enabled = await autoLaunch.isEnabled();
return enabled;
});
+4 -2
View File
@@ -1,6 +1,6 @@
import dbus from "@homebridge/dbus-native"; import dbus from "@homebridge/dbus-native";
import { NativeImage, app, nativeImage } from "electron"; import { NativeImage, app, ipcMain, nativeImage } from "electron";
import { mainWindow } from "./window"; import { mainWindow } from "./window";
@@ -21,7 +21,7 @@ export async function setBadgeCount(count: number) {
nativeIcons[count] = nativeImage.createFromDataURL( nativeIcons[count] = nativeImage.createFromDataURL(
await import( await import(
`../../assets/desktop/badges/${Math.min(count, 10)}.ico?asset` `../../assets/desktop/badges/${Math.min(count, 10)}.ico?asset`
), ).then((asset) => asset.default),
); );
mainWindow.setOverlayIcon( mainWindow.setOverlayIcon(
@@ -65,3 +65,5 @@ export async function setBadgeCount(count: number) {
break; break;
} }
} }
ipcMain.on("setBadgeCount", (_event, count: number) => setBadgeCount(count));
+36 -12
View File
@@ -16,6 +16,9 @@ const schema = {
minimiseToTray: { minimiseToTray: {
type: "boolean", type: "boolean",
} as JSONSchema.Boolean, } as JSONSchema.Boolean,
startMinimisedToTray: {
type: "boolean",
} as JSONSchema.Boolean,
spellchecker: { spellchecker: {
type: "boolean", type: "boolean",
} as JSONSchema.Boolean, } as JSONSchema.Boolean,
@@ -28,18 +31,18 @@ const schema = {
windowState: { windowState: {
type: "object", type: "object",
properties: { properties: {
// x: { x: {
// type: 'number' type: "number",
// } as JSONSchema.Number, } as JSONSchema.Number,
// y: { y: {
// type: 'number' type: "number",
// } as JSONSchema.Number, } as JSONSchema.Number,
// width: { width: {
// type: 'number' type: "number",
// } as JSONSchema.Number, } as JSONSchema.Number,
// height: { height: {
// type: 'number' type: "number",
// } as JSONSchema.Number, } as JSONSchema.Number,
isMaximised: { isMaximised: {
type: "boolean", type: "boolean",
} as JSONSchema.Boolean, } as JSONSchema.Boolean,
@@ -53,10 +56,15 @@ const store = new Store({
firstLaunch: true, firstLaunch: true,
customFrame: true, customFrame: true,
minimiseToTray: true, minimiseToTray: true,
startMinimisedToTray: false,
spellchecker: true, spellchecker: true,
hardwareAcceleration: true, hardwareAcceleration: true,
discordRpc: true, discordRpc: true,
windowState: { windowState: {
x: 0,
y: 0,
width: 0,
height: 0,
isMaximised: false, isMaximised: false,
}, },
} as DesktopConfig, } as DesktopConfig,
@@ -71,6 +79,7 @@ class Config {
firstLaunch: this.firstLaunch, firstLaunch: this.firstLaunch,
customFrame: this.customFrame, customFrame: this.customFrame,
minimiseToTray: this.minimiseToTray, minimiseToTray: this.minimiseToTray,
startMinimisedToTray: this.startMinimisedToTray,
spellchecker: this.spellchecker, spellchecker: this.spellchecker,
hardwareAcceleration: this.hardwareAcceleration, hardwareAcceleration: this.hardwareAcceleration,
discordRpc: this.discordRpc, discordRpc: this.discordRpc,
@@ -119,6 +128,21 @@ class Config {
this.sync(); this.sync();
} }
get startMinimisedToTray() {
return (store as never as { get(k: string): boolean }).get(
"startMinimisedToTray",
);
}
set startMinimisedToTray(value: boolean) {
(store as never as { set(k: string, value: boolean): void }).set(
"startMinimisedToTray",
value,
);
this.sync();
}
get spellchecker() { get spellchecker() {
return (store as never as { get(k: string): boolean }).get("spellchecker"); return (store as never as { get(k: string): boolean }).get("spellchecker");
} }
+4 -2
View File
@@ -8,6 +8,9 @@ let rpc: Client;
export async function initDiscordRpc() { export async function initDiscordRpc() {
if (!config.discordRpc) return; if (!config.discordRpc) return;
// clean up existing client if one exists
rpc?.removeAllListeners();
try { try {
rpc = new Client({ transport: "ipc" }); rpc = new Client({ transport: "ipc" });
@@ -16,8 +19,7 @@ export async function initDiscordRpc() {
state: "stoat.chat", state: "stoat.chat",
details: "Chatting with others", details: "Chatting with others",
largeImageKey: "qr", largeImageKey: "qr",
// largeImageText: "Communication is critical use Revolt.", largeImageText: "Join Stoat!",
largeImageText: "",
buttons: [ buttons: [
{ {
label: "Join Stoat", label: "Join Stoat",
+17 -4
View File
@@ -1,6 +1,7 @@
import { Menu, Tray, nativeImage } from "electron"; import { Menu, Tray, nativeImage } from "electron";
import trayIconAsset from "../../assets/desktop/icon.png?asset"; import trayIconAsset from "../../assets/desktop/icon.png?asset";
import macOsTrayIconAsset from "../../assets/desktop/iconTemplate.png?asset";
import { version } from "../../package.json"; import { version } from "../../package.json";
import { mainWindow, quitApp } from "./window"; import { mainWindow, quitApp } from "./window";
@@ -8,19 +9,31 @@ import { mainWindow, quitApp } from "./window";
// internal tray state // internal tray state
let tray: Tray = null; let tray: Tray = null;
// load the tray icon // Create and resize tray icon for macOS
const trayIcon = nativeImage.createFromDataURL(trayIconAsset); function createTrayIcon() {
if (process.platform === "darwin") {
// trayIcon.setTemplateImage(true); const image = nativeImage.createFromDataURL(macOsTrayIconAsset);
const resized = image.resize({ width: 20, height: 20 });
resized.setTemplateImage(true);
return resized;
} else {
return nativeImage.createFromDataURL(trayIconAsset);
}
}
export function initTray() { export function initTray() {
const trayIcon = createTrayIcon();
tray = new Tray(trayIcon); tray = new Tray(trayIcon);
updateTrayMenu(); updateTrayMenu();
tray.setToolTip("Stoat for Desktop"); tray.setToolTip("Stoat for Desktop");
tray.setImage(trayIcon); tray.setImage(trayIcon);
tray.on("click", () => { tray.on("click", () => {
if (mainWindow.isVisible()) {
mainWindow.hide();
} else {
mainWindow.show(); mainWindow.show();
mainWindow.focus(); mainWindow.focus();
}
}); });
} }
+38 -1
View File
@@ -36,6 +36,10 @@ const windowIcon = nativeImage.createFromDataURL(windowIconAsset);
* Create the main application window * Create the main application window
*/ */
export function createMainWindow() { export function createMainWindow() {
// (CLI arg --hidden or config)
const startHidden =
app.commandLine.hasSwitch("hidden") || config.startMinimisedToTray;
// create the window // create the window
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
minWidth: 300, minWidth: 300,
@@ -45,6 +49,7 @@ export function createMainWindow() {
backgroundColor: "#191919", backgroundColor: "#191919",
frame: !config.customFrame, frame: !config.customFrame,
icon: windowIcon, icon: windowIcon,
show: !startHidden,
webPreferences: { webPreferences: {
// relative to `.vite/build` // relative to `.vite/build`
preload: join(__dirname, "preload.js"), preload: join(__dirname, "preload.js"),
@@ -57,6 +62,22 @@ export function createMainWindow() {
// hide the options // hide the options
mainWindow.setMenu(null); mainWindow.setMenu(null);
// restore last position if it was moved previously
if (config.windowState.x > 0 || config.windowState.y > 0) {
mainWindow.setPosition(
config.windowState.x ?? 0,
config.windowState.y ?? 0,
);
}
// restore last size if it was resized previously
if (config.windowState.width > 0 && config.windowState.height > 0) {
mainWindow.setSize(
config.windowState.width ?? 1280,
config.windowState.height ?? 720,
);
}
// maximise the window if it was maximised before // maximise the window if it was maximised before
if (config.windowState.isMaximised) { if (config.windowState.isMaximised) {
mainWindow.maximize(); mainWindow.maximize();
@@ -80,16 +101,22 @@ export function createMainWindow() {
// keep track of window state // keep track of window state
function generateState() { function generateState() {
config.windowState = { config.windowState = {
x: mainWindow.getPosition()[0],
y: mainWindow.getPosition()[1],
width: mainWindow.getSize()[0],
height: mainWindow.getSize()[1],
isMaximised: mainWindow.isMaximized(), isMaximised: mainWindow.isMaximized(),
}; };
} }
mainWindow.on("maximize", generateState); mainWindow.on("maximize", generateState);
mainWindow.on("unmaximize", generateState); mainWindow.on("unmaximize", generateState);
mainWindow.on("moved", generateState);
mainWindow.on("resized", generateState);
// rebind zoom controls to be more sensible // rebind zoom controls to be more sensible
mainWindow.webContents.on("before-input-event", (event, input) => { mainWindow.webContents.on("before-input-event", (event, input) => {
if (input.control && input.key === "=") { if (input.control && (input.key === "=" || input.key === "+")) {
// zoom in (+) // zoom in (+)
event.preventDefault(); event.preventDefault();
mainWindow.webContents.setZoomLevel( mainWindow.webContents.setZoomLevel(
@@ -101,6 +128,16 @@ export function createMainWindow() {
mainWindow.webContents.setZoomLevel( mainWindow.webContents.setZoomLevel(
mainWindow.webContents.getZoomLevel() - 1, mainWindow.webContents.getZoomLevel() - 1,
); );
} else if (input.control && input.key === "0") {
// reset zoom to default.
event.preventDefault();
mainWindow.webContents.setZoomLevel(0);
} else if (
input.key === "F5" ||
((input.control || input.meta) && input.key.toLowerCase() === "r")
) {
event.preventDefault();
mainWindow.webContents.reload();
} }
}); });
+2 -3
View File
@@ -8,10 +8,9 @@ contextBridge.exposeInMainWorld("desktopConfig", {
get: () => config, get: () => config,
set: (config: DesktopConfig) => ipcRenderer.send("config", config), set: (config: DesktopConfig) => ipcRenderer.send("config", config),
getAutostart() { getAutostart() {
ipcRenderer.send("isAutostart?"); return ipcRenderer.invoke("getAutostart") as Promise<boolean>;
return new Promise((resolve) => ipcRenderer.once("isAutostart", resolve));
}, },
setAutostart(value: boolean) { setAutostart(value: boolean) {
ipcRenderer.send("setAutostart", value); return ipcRenderer.invoke("setAutostart", value) as Promise<boolean>;
}, },
}); });
+2
View File
@@ -13,4 +13,6 @@ contextBridge.exposeInMainWorld("native", {
minimise: () => ipcRenderer.send("minimise"), minimise: () => ipcRenderer.send("minimise"),
maximise: () => ipcRenderer.send("maximise"), maximise: () => ipcRenderer.send("maximise"),
close: () => ipcRenderer.send("close"), close: () => ipcRenderer.send("close"),
setBadgeCount: (count: number) => ipcRenderer.send("setBadgeCount", count),
}); });