mirror of
https://github.com/safing/portmaster
synced 2025-09-02 02:29:12 +00:00
Merge pull request #1675 from safing/fix/clipboard-bug
Fix clipboard issue when coping debug info
This commit is contained in:
commit
cfd877757d
12 changed files with 739 additions and 346 deletions
147
desktop/angular/package-lock.json
generated
147
desktop/angular/package-lock.json
generated
|
@ -23,13 +23,13 @@
|
||||||
"@fortawesome/free-brands-svg-icons": "^6.4.0",
|
"@fortawesome/free-brands-svg-icons": "^6.4.0",
|
||||||
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
||||||
"@tauri-apps/api": ">=2.0.0-beta.0",
|
"@tauri-apps/api": ">=2.0.0-rc.1",
|
||||||
"@tauri-apps/plugin-cli": ">=2.0.0-beta.0",
|
"@tauri-apps/plugin-cli": ">=2.0.0-rc.1",
|
||||||
"@tauri-apps/plugin-clipboard-manager": ">=2.0.0-beta.0",
|
"@tauri-apps/plugin-clipboard-manager": ">=2.0.0-rc.1",
|
||||||
"@tauri-apps/plugin-dialog": ">=2.0.0-beta.0",
|
"@tauri-apps/plugin-dialog": ">=2.0.0-rc.1",
|
||||||
"@tauri-apps/plugin-notification": ">=2.0.0-beta.0",
|
"@tauri-apps/plugin-notification": ">=2.0.0-rc.1",
|
||||||
"@tauri-apps/plugin-os": ">=2.0.0-beta.0",
|
"@tauri-apps/plugin-os": ">=2.0.0-rc.1",
|
||||||
"@tauri-apps/plugin-shell": "^2.0.0-beta",
|
"@tauri-apps/plugin-shell": "^2.0.0-rc",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"d3": "^7.8.4",
|
"d3": "^7.8.4",
|
||||||
"data-urls": "^5.0.0",
|
"data-urls": "^5.0.0",
|
||||||
|
@ -4406,77 +4406,67 @@
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/api": {
|
"node_modules/@tauri-apps/api": {
|
||||||
"version": "2.0.0-beta.4",
|
"version": "2.0.0-rc.4",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.0.0-beta.4.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.0.0-rc.4.tgz",
|
||||||
"integrity": "sha512-Nxtj28NYUo5iwYkpYslxmOPkdI2WkELU2e3UH9nbJm9Ydki2CQwJVGQxx4EANtdZcMNsEsUzRqaDTvEUYH1l6w==",
|
"integrity": "sha512-UNiIhhKG08j4ooss2oEEVexffmWkgkYlC2M3GcX3VPtNsqFgVNL8Mcw/4Y7rO9M9S+ffAMnLOF5ypzyuyb8tyg==",
|
||||||
"engines": {
|
"license": "Apache-2.0 OR MIT",
|
||||||
"node": ">= 18",
|
|
||||||
"npm": ">= 6.6.0",
|
|
||||||
"yarn": ">= 1.19.1"
|
|
||||||
},
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
"url": "https://opencollective.com/tauri"
|
"url": "https://opencollective.com/tauri"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/plugin-cli": {
|
"node_modules/@tauri-apps/plugin-cli": {
|
||||||
"version": "2.0.0-beta.1",
|
"version": "2.0.0-rc.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-cli/-/plugin-cli-2.0.0-rc.1.tgz",
|
||||||
|
"integrity": "sha512-EcSTRfEU3zzlNbgwVtZVzqB19z3PNjyXD9H+YXuuLpV+Hwuh6Oi1fhUdCI0mp5zr9HSMWE+HzHkpBI7sVP1RyA==",
|
||||||
"license": "MIT or APACHE-2.0",
|
"license": "MIT or APACHE-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-beta.2"
|
"@tauri-apps/api": "^2.0.0-rc.4"
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@tauri-apps/plugin-cli/node_modules/@tauri-apps/api": {
|
|
||||||
"version": "2.0.0-beta.2",
|
|
||||||
"license": "Apache-2.0 OR MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18",
|
|
||||||
"npm": ">= 6.6.0",
|
|
||||||
"yarn": ">= 1.19.1"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/tauri"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/plugin-clipboard-manager": {
|
"node_modules/@tauri-apps/plugin-clipboard-manager": {
|
||||||
"version": "2.0.0-beta.2",
|
"version": "2.0.0-rc.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-clipboard-manager/-/plugin-clipboard-manager-2.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-clipboard-manager/-/plugin-clipboard-manager-2.0.0-rc.1.tgz",
|
||||||
"integrity": "sha512-yue7KTO9r9rlpgjcyRB9xcMyZKTrGOP2bWQnL/EoyVkECsr+8e8W8UMlvajXjv1hinFoiycXJe6GaSTPGO0Jlg==",
|
"integrity": "sha512-hFgUABMmQuVGKwHb8PR9fuqfk0WRkedbWUt/ZV5sL4Q6kLrsp3JYJvtzVPeMYdeBvMqHl8WXNxAc/zwSld2h9w==",
|
||||||
|
"license": "MIT or APACHE-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-beta.4"
|
"@tauri-apps/api": "^2.0.0-rc.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/plugin-dialog": {
|
"node_modules/@tauri-apps/plugin-dialog": {
|
||||||
"version": "2.0.0-beta.2",
|
"version": "2.0.0-rc.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.0.0-rc.1.tgz",
|
||||||
"integrity": "sha512-WugTn/8d5jYA0GL1JRIJgA1OSxG0h2V4PSZZzehgA3v7rPlIU6w9s2+dSRqj55aMj6hm3Az9YbQqC18nuaHkpw==",
|
"integrity": "sha512-H28gh6BfZtjflHQ+HrmWwunDriBI3AQLAKnMs50GA6zeNUULqbQr7VXbAAKeJL/0CmWcecID4PKXVoSlaWRhEg==",
|
||||||
|
"license": "MIT or APACHE-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-beta.4"
|
"@tauri-apps/api": "^2.0.0-rc.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/plugin-notification": {
|
"node_modules/@tauri-apps/plugin-notification": {
|
||||||
"version": "2.0.0-beta.2",
|
"version": "2.0.0-rc.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-notification/-/plugin-notification-2.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-notification/-/plugin-notification-2.0.0-rc.1.tgz",
|
||||||
"integrity": "sha512-OxMuKawWkXGR04hALFrPhRXhA3vGRyMy+kRT3vdHoAwngZHcBGetRqm6CuW0tSNWCgwuUYXpN57636CfUReg5g==",
|
"integrity": "sha512-ddDj7xM8XR7Zv2vdpofNXlLjcp49p/VjlL0D+/eBcMuyooaLNMor3jz/+H6s23iHerdxMWA50mzy26BRN1BySA==",
|
||||||
|
"license": "MIT or APACHE-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-beta.4"
|
"@tauri-apps/api": "^2.0.0-rc.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/plugin-os": {
|
"node_modules/@tauri-apps/plugin-os": {
|
||||||
"version": "2.0.0-beta.2",
|
"version": "2.0.0-rc.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-os/-/plugin-os-2.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-os/-/plugin-os-2.0.0-rc.1.tgz",
|
||||||
"integrity": "sha512-rhJ/sEYvEAeMUQt6UiFODi5dT6F/ciNZYBQrbFTwhIqwQ2fp87dmzsscMy7FQ9LOor8AW+kL1KWoadfgzA/mSA==",
|
"integrity": "sha512-PV8zlSTmYfiN2xzILUmlDSEycS7UYbH2yXk/ZqF+qQU6/s+OVQvmSth4EhllFjcpvPbtqELvpzfjw+2qEouchA==",
|
||||||
|
"license": "MIT or APACHE-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-beta.4"
|
"@tauri-apps/api": "^2.0.0-rc.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tauri-apps/plugin-shell": {
|
"node_modules/@tauri-apps/plugin-shell": {
|
||||||
"version": "2.0.0-beta.2",
|
"version": "2.0.0-rc.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-shell/-/plugin-shell-2.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-shell/-/plugin-shell-2.0.0-rc.1.tgz",
|
||||||
"integrity": "sha512-9rWsfN7Wt+EuWmpmNnK8bCs+04fzhEYrHtWyLIAYxb9diFdcJrEoctCP9YM2v+Uf8/y8qFC7VCbZ/9VQHANymQ==",
|
"integrity": "sha512-JtNROc0rqEwN/g93ig5pK4cl1vUo2yn+osCpY9de64cy/d9hRzof7AuYOgvt/Xcd5VPQmlgo2AGvUh5sQRSR1A==",
|
||||||
|
"license": "MIT or APACHE-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-beta.4"
|
"@tauri-apps/api": "^2.0.0-rc.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tootallnate/once": {
|
"node_modules/@tootallnate/once": {
|
||||||
|
@ -21077,59 +21067,56 @@
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"@tauri-apps/api": {
|
"@tauri-apps/api": {
|
||||||
"version": "2.0.0-beta.4",
|
"version": "2.0.0-rc.4",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.0.0-beta.4.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.0.0-rc.4.tgz",
|
||||||
"integrity": "sha512-Nxtj28NYUo5iwYkpYslxmOPkdI2WkELU2e3UH9nbJm9Ydki2CQwJVGQxx4EANtdZcMNsEsUzRqaDTvEUYH1l6w=="
|
"integrity": "sha512-UNiIhhKG08j4ooss2oEEVexffmWkgkYlC2M3GcX3VPtNsqFgVNL8Mcw/4Y7rO9M9S+ffAMnLOF5ypzyuyb8tyg=="
|
||||||
},
|
},
|
||||||
"@tauri-apps/plugin-cli": {
|
"@tauri-apps/plugin-cli": {
|
||||||
"version": "2.0.0-beta.1",
|
"version": "2.0.0-rc.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-cli/-/plugin-cli-2.0.0-rc.1.tgz",
|
||||||
|
"integrity": "sha512-EcSTRfEU3zzlNbgwVtZVzqB19z3PNjyXD9H+YXuuLpV+Hwuh6Oi1fhUdCI0mp5zr9HSMWE+HzHkpBI7sVP1RyA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@tauri-apps/api": "2.0.0-beta.2"
|
"@tauri-apps/api": "^2.0.0-rc.4"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@tauri-apps/api": {
|
|
||||||
"version": "2.0.0-beta.2"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@tauri-apps/plugin-clipboard-manager": {
|
"@tauri-apps/plugin-clipboard-manager": {
|
||||||
"version": "2.0.0-beta.2",
|
"version": "2.0.0-rc.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-clipboard-manager/-/plugin-clipboard-manager-2.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-clipboard-manager/-/plugin-clipboard-manager-2.0.0-rc.1.tgz",
|
||||||
"integrity": "sha512-yue7KTO9r9rlpgjcyRB9xcMyZKTrGOP2bWQnL/EoyVkECsr+8e8W8UMlvajXjv1hinFoiycXJe6GaSTPGO0Jlg==",
|
"integrity": "sha512-hFgUABMmQuVGKwHb8PR9fuqfk0WRkedbWUt/ZV5sL4Q6kLrsp3JYJvtzVPeMYdeBvMqHl8WXNxAc/zwSld2h9w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@tauri-apps/api": "2.0.0-beta.4"
|
"@tauri-apps/api": "^2.0.0-rc.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@tauri-apps/plugin-dialog": {
|
"@tauri-apps/plugin-dialog": {
|
||||||
"version": "2.0.0-beta.2",
|
"version": "2.0.0-rc.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.0.0-rc.1.tgz",
|
||||||
"integrity": "sha512-WugTn/8d5jYA0GL1JRIJgA1OSxG0h2V4PSZZzehgA3v7rPlIU6w9s2+dSRqj55aMj6hm3Az9YbQqC18nuaHkpw==",
|
"integrity": "sha512-H28gh6BfZtjflHQ+HrmWwunDriBI3AQLAKnMs50GA6zeNUULqbQr7VXbAAKeJL/0CmWcecID4PKXVoSlaWRhEg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@tauri-apps/api": "2.0.0-beta.4"
|
"@tauri-apps/api": "^2.0.0-rc.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@tauri-apps/plugin-notification": {
|
"@tauri-apps/plugin-notification": {
|
||||||
"version": "2.0.0-beta.2",
|
"version": "2.0.0-rc.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-notification/-/plugin-notification-2.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-notification/-/plugin-notification-2.0.0-rc.1.tgz",
|
||||||
"integrity": "sha512-OxMuKawWkXGR04hALFrPhRXhA3vGRyMy+kRT3vdHoAwngZHcBGetRqm6CuW0tSNWCgwuUYXpN57636CfUReg5g==",
|
"integrity": "sha512-ddDj7xM8XR7Zv2vdpofNXlLjcp49p/VjlL0D+/eBcMuyooaLNMor3jz/+H6s23iHerdxMWA50mzy26BRN1BySA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@tauri-apps/api": "2.0.0-beta.4"
|
"@tauri-apps/api": "^2.0.0-rc.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@tauri-apps/plugin-os": {
|
"@tauri-apps/plugin-os": {
|
||||||
"version": "2.0.0-beta.2",
|
"version": "2.0.0-rc.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-os/-/plugin-os-2.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-os/-/plugin-os-2.0.0-rc.1.tgz",
|
||||||
"integrity": "sha512-rhJ/sEYvEAeMUQt6UiFODi5dT6F/ciNZYBQrbFTwhIqwQ2fp87dmzsscMy7FQ9LOor8AW+kL1KWoadfgzA/mSA==",
|
"integrity": "sha512-PV8zlSTmYfiN2xzILUmlDSEycS7UYbH2yXk/ZqF+qQU6/s+OVQvmSth4EhllFjcpvPbtqELvpzfjw+2qEouchA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@tauri-apps/api": "2.0.0-beta.4"
|
"@tauri-apps/api": "^2.0.0-rc.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@tauri-apps/plugin-shell": {
|
"@tauri-apps/plugin-shell": {
|
||||||
"version": "2.0.0-beta.2",
|
"version": "2.0.0-rc.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-shell/-/plugin-shell-2.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-shell/-/plugin-shell-2.0.0-rc.1.tgz",
|
||||||
"integrity": "sha512-9rWsfN7Wt+EuWmpmNnK8bCs+04fzhEYrHtWyLIAYxb9diFdcJrEoctCP9YM2v+Uf8/y8qFC7VCbZ/9VQHANymQ==",
|
"integrity": "sha512-JtNROc0rqEwN/g93ig5pK4cl1vUo2yn+osCpY9de64cy/d9hRzof7AuYOgvt/Xcd5VPQmlgo2AGvUh5sQRSR1A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@tauri-apps/api": "2.0.0-beta.4"
|
"@tauri-apps/api": "^2.0.0-rc.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@tootallnate/once": {
|
"@tootallnate/once": {
|
||||||
|
|
|
@ -37,13 +37,13 @@
|
||||||
"@fortawesome/free-brands-svg-icons": "^6.4.0",
|
"@fortawesome/free-brands-svg-icons": "^6.4.0",
|
||||||
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
||||||
"@tauri-apps/api": ">=2.0.0-beta.0",
|
"@tauri-apps/api": ">=2.0.0-rc.1",
|
||||||
"@tauri-apps/plugin-cli": ">=2.0.0-beta.0",
|
"@tauri-apps/plugin-cli": ">=2.0.0-rc.1",
|
||||||
"@tauri-apps/plugin-clipboard-manager": ">=2.0.0-beta.0",
|
"@tauri-apps/plugin-clipboard-manager": ">=2.0.0-rc.1",
|
||||||
"@tauri-apps/plugin-dialog": ">=2.0.0-beta.0",
|
"@tauri-apps/plugin-dialog": ">=2.0.0-rc.1",
|
||||||
"@tauri-apps/plugin-notification": ">=2.0.0-beta.0",
|
"@tauri-apps/plugin-notification": ">=2.0.0-rc.1",
|
||||||
"@tauri-apps/plugin-os": ">=2.0.0-beta.0",
|
"@tauri-apps/plugin-os": ">=2.0.0-rc.1",
|
||||||
"@tauri-apps/plugin-shell": "^2.0.0-beta",
|
"@tauri-apps/plugin-shell": "^2.0.0-rc",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"d3": "^7.8.4",
|
"d3": "^7.8.4",
|
||||||
"data-urls": "^5.0.0",
|
"data-urls": "^5.0.0",
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { writeText } from '@tauri-apps/plugin-clipboard-manager';
|
||||||
import { open } from '@tauri-apps/plugin-shell';
|
import { open } from '@tauri-apps/plugin-shell';
|
||||||
import { listen, once } from '@tauri-apps/api/event';
|
import { listen, once } from '@tauri-apps/api/event';
|
||||||
import { invoke } from '@tauri-apps/api/core'
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
import { getCurrent, Window } from '@tauri-apps/api/window';
|
import { getCurrentWindow, Window } from '@tauri-apps/api/window';
|
||||||
|
|
||||||
// Returns a new uuidv4. If crypto.randomUUID is not available it fals back to
|
// Returns a new uuidv4. If crypto.randomUUID is not available it fals back to
|
||||||
// using Math.random(). While this is not as random as it should be it's still
|
// using Math.random(). While this is not as random as it should be it's still
|
||||||
|
@ -102,7 +102,7 @@ export class TauriIntegrationService implements IntegrationService {
|
||||||
// we waste some system resources due to tauri window objects and the angular
|
// we waste some system resources due to tauri window objects and the angular
|
||||||
// application.
|
// application.
|
||||||
|
|
||||||
getCurrent().hide()
|
getCurrentWindow().hide()
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ export class TauriIntegrationService implements IntegrationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
openApp() {
|
openApp() {
|
||||||
Window.getByLabel("splash")?.close();
|
Window.getByLabel("splash").then(splash => { splash?.close();});
|
||||||
const current = Window.getCurrent()
|
const current = Window.getCurrent()
|
||||||
|
|
||||||
current.isVisible()
|
current.isVisible()
|
||||||
|
@ -177,7 +177,7 @@ export class TauriIntegrationService implements IntegrationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
closePrompt() {
|
closePrompt() {
|
||||||
Window.getByLabel("prompt")?.close();
|
Window.getByLabel("prompt").then(window => { window?.close();});
|
||||||
}
|
}
|
||||||
|
|
||||||
openPrompt() {
|
openPrompt() {
|
||||||
|
@ -185,7 +185,8 @@ export class TauriIntegrationService implements IntegrationService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Window.getByLabel("prompt")) {
|
Window.getByLabel("prompt").then(prompt => {
|
||||||
|
if (prompt) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,5 +213,6 @@ export class TauriIntegrationService implements IntegrationService {
|
||||||
promptWindow.once("tauri://error", (err) => {
|
promptWindow.once("tauri://error", (err) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { CommonModule } from "@angular/common";
|
import { CommonModule } from "@angular/common";
|
||||||
import { Component, OnInit, TrackByFunction, inject } from "@angular/core";
|
import { Component, OnInit, TrackByFunction, inject } from "@angular/core";
|
||||||
import { AppProfile, AppProfileService, PortapiService } from "@safing/portmaster-api";
|
import { AppProfile, AppProfileService, PortapiService } from "@safing/portmaster-api";
|
||||||
import { combineLatest, combineLatestAll, forkJoin, map, merge, mergeAll, of, switchMap } from "rxjs";
|
import { combineLatest, forkJoin, map, of, switchMap } from "rxjs";
|
||||||
import { ConnectionPrompt, NotificationType, NotificationsService } from "../services";
|
import { ConnectionPrompt, NotificationType, NotificationsService } from "../services";
|
||||||
import { SfngAppIconModule } from "../shared/app-icon";
|
import { SfngAppIconModule } from "../shared/app-icon";
|
||||||
import { getCurrent } from '@tauri-apps/api/window';
|
import { getCurrentWindow } from '@tauri-apps/api/window';
|
||||||
import { CountryFlagModule } from "../shared/country-flag";
|
import { CountryFlagModule } from "../shared/country-flag";
|
||||||
|
|
||||||
interface Prompt {
|
interface Prompt {
|
||||||
|
@ -64,7 +64,7 @@ export class PromptEntryPointComponent implements OnInit {
|
||||||
|
|
||||||
// show the prompt now since we're ready
|
// show the prompt now since we're ready
|
||||||
if (this.prompts.length) {
|
if (this.prompts.length) {
|
||||||
getCurrent()!.show();
|
getCurrentWindow()!.show();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
606
desktop/tauri/src-tauri/Cargo.lock
generated
606
desktop/tauri/src-tauri/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -12,11 +12,11 @@ rust-version = "1.60"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-build = { version = "2.0.0-rc.3", features = [] }
|
tauri-build = { version = "2.0.0-rc.7", features = [] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Tauri
|
# Tauri
|
||||||
tauri = { version = "2.0.0-rc.3", features = ["tray-icon", "image-png", "config-json5", "devtools"] }
|
tauri = { version = "2.0.0-rc.8", features = ["tray-icon", "image-png", "config-json5", "devtools"] }
|
||||||
tauri-plugin-shell = "2.0.0-rc"
|
tauri-plugin-shell = "2.0.0-rc"
|
||||||
tauri-plugin-dialog = "2.0.0-rc"
|
tauri-plugin-dialog = "2.0.0-rc"
|
||||||
tauri-plugin-clipboard-manager = "2.0.0-rc"
|
tauri-plugin-clipboard-manager = "2.0.0-rc"
|
||||||
|
@ -26,7 +26,7 @@ tauri-plugin-notification = "2.0.0-rc"
|
||||||
tauri-plugin-log = "2.0.0-rc"
|
tauri-plugin-log = "2.0.0-rc"
|
||||||
tauri-plugin-window-state = "2.0.0-rc"
|
tauri-plugin-window-state = "2.0.0-rc"
|
||||||
|
|
||||||
tauri-cli = "2.0.0-rc.4"
|
tauri-cli = "2.0.0-rc.8"
|
||||||
clap = { version = "4" }
|
clap = { version = "4" }
|
||||||
|
|
||||||
# General
|
# General
|
||||||
|
@ -53,7 +53,7 @@ reqwest = { version = "0.12" }
|
||||||
rfd = { version = "*", default-features = false, features = [ "tokio", "gtk3", "common-controls-v6" ] }
|
rfd = { version = "*", default-features = false, features = [ "tokio", "gtk3", "common-controls-v6" ] }
|
||||||
open = "5.1.3"
|
open = "5.1.3"
|
||||||
|
|
||||||
dark-light = "1.1.1"
|
dark-light = { git = "https://github.com/vlabo/rust-dark-light", rev = "1f955c84d0ea05729bb5ecab29fb1b315b9897de" }
|
||||||
|
|
||||||
# Linux only
|
# Linux only
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
"core:window:allow-is-visible",
|
"core:window:allow-is-visible",
|
||||||
"core:window:allow-set-focus",
|
"core:window:allow-set-focus",
|
||||||
"core:window:allow-close",
|
"core:window:allow-close",
|
||||||
|
"core:window:allow-get-all-windows",
|
||||||
"core:app:default",
|
"core:app:default",
|
||||||
"core:image:default",
|
"core:image:default",
|
||||||
"core:resources:default",
|
"core:resources:default",
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"default":{"identifier":"default","description":"Capability for the main window","remote":{"urls":["http://localhost:817"]},"local":true,"windows":["main","splash"],"permissions":["core:path:default","core:event:allow-listen","core:event:allow-unlisten","core:event:allow-emit","core:event:allow-emit-to","core:window:allow-hide","core:window:allow-show","core:window:allow-is-visible","core:window:allow-set-focus","core:window:allow-close","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default","shell:allow-open","notification:default","window-state:allow-save-window-state","window-state:allow-restore-state","clipboard-manager:allow-read-text","clipboard-manager:allow-write-text"]}}
|
{"default":{"identifier":"default","description":"Capability for the main window","remote":{"urls":["http://localhost:817"]},"local":true,"windows":["main","splash"],"permissions":["core:path:default","core:event:allow-listen","core:event:allow-unlisten","core:event:allow-emit","core:event:allow-emit-to","core:window:allow-hide","core:window:allow-show","core:window:allow-is-visible","core:window:allow-set-focus","core:window:allow-close","core:window:allow-get-all-windows","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default","shell:allow-open","notification:default","window-state:allow-save-window-state","window-state:allow-restore-state","clipboard-manager:allow-read-text","clipboard-manager:allow-write-text"]}}
|
45
desktop/tauri/src-tauri/src/config.rs
Normal file
45
desktop/tauri/src-tauri/src/config.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use log::{debug, error};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tauri::{AppHandle, Manager};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub enum Theme {
|
||||||
|
Light,
|
||||||
|
Dark,
|
||||||
|
System,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct Config {
|
||||||
|
pub theme: Theme,
|
||||||
|
}
|
||||||
|
|
||||||
|
const CONFIG_FILE_NAME: &'static str = "config.json";
|
||||||
|
|
||||||
|
pub fn save(app: &AppHandle, config: Config) -> tauri::Result<()> {
|
||||||
|
let config_dir = app.path().app_config_dir()?;
|
||||||
|
|
||||||
|
let config_path = config_dir.join(CONFIG_FILE_NAME);
|
||||||
|
debug!("saving config file: {:?}", config_path);
|
||||||
|
let json = serde_json::to_string_pretty(&config)?;
|
||||||
|
fs::write(config_path, json)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load(app: &AppHandle) -> tauri::Result<Config> {
|
||||||
|
let config_dir = app.path().app_config_dir()?;
|
||||||
|
|
||||||
|
let config_path = config_dir.join(CONFIG_FILE_NAME);
|
||||||
|
if let Ok(json) = fs::read_to_string(config_path) {
|
||||||
|
if let Ok(config) = serde_json::from_str(&json) {
|
||||||
|
return Ok(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error!("failed to load config file returning default config");
|
||||||
|
Ok(Config {
|
||||||
|
theme: Theme::System,
|
||||||
|
})
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ mod service;
|
||||||
mod xdg;
|
mod xdg;
|
||||||
|
|
||||||
// App modules
|
// App modules
|
||||||
|
mod config;
|
||||||
mod portmaster;
|
mod portmaster;
|
||||||
mod traymenu;
|
mod traymenu;
|
||||||
mod window;
|
mod window;
|
||||||
|
@ -22,7 +23,7 @@ use log::{debug, error, info, LevelFilter};
|
||||||
use portmaster::PortmasterExt;
|
use portmaster::PortmasterExt;
|
||||||
use tauri_plugin_log::RotationStrategy;
|
use tauri_plugin_log::RotationStrategy;
|
||||||
use traymenu::setup_tray_menu;
|
use traymenu::setup_tray_menu;
|
||||||
use window::{close_splash_window, create_main_window};
|
use window::{close_splash_window, create_main_window, hide_splash_window};
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
@ -77,7 +78,11 @@ impl portmaster::Handler for WsHandler {
|
||||||
// so we don't show the splash-screen when we loose connection.
|
// so we don't show the splash-screen when we loose connection.
|
||||||
self.is_first_connect = false;
|
self.is_first_connect = false;
|
||||||
|
|
||||||
if let Err(err) = close_splash_window(&self.handle) {
|
// The order is important. If all current windows are destroyed tauri will exit.
|
||||||
|
// First create the main ui window then destroy the splash screen.
|
||||||
|
|
||||||
|
// Hide splash screen. Will be closed after main window is created.
|
||||||
|
if let Err(err) = hide_splash_window(&self.handle) {
|
||||||
error!("failed to close splash window: {}", err.to_string());
|
error!("failed to close splash window: {}", err.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +95,11 @@ impl portmaster::Handler for WsHandler {
|
||||||
debug!("created main window")
|
debug!("created main window")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now it is safe to destroy the splash window.
|
||||||
|
if let Err(err) = close_splash_window(&self.handle) {
|
||||||
|
error!("failed to close splash window: {}", err.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
let handle = self.handle.clone();
|
let handle = self.handle.clone();
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
traymenu::tray_handler(cli, handle).await;
|
traymenu::tray_handler(cli, handle).await;
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
use std::ops::Deref;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::sync::Mutex;
|
use std::sync::{Mutex, RwLock};
|
||||||
use std::{collections::HashMap, sync::atomic::Ordering};
|
use std::{collections::HashMap, sync::atomic::Ordering};
|
||||||
|
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
use tauri::tray::{MouseButton, MouseButtonState};
|
use tauri::tray::{MouseButton, MouseButtonState};
|
||||||
|
use tauri::Manager;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
image::Image,
|
image::Image,
|
||||||
menu::{MenuBuilder, MenuItem, MenuItemBuilder, PredefinedMenuItem, SubmenuBuilder},
|
menu::{MenuBuilder, MenuItem, MenuItemBuilder, PredefinedMenuItem, SubmenuBuilder},
|
||||||
|
@ -12,6 +14,7 @@ use tauri::{
|
||||||
};
|
};
|
||||||
use tauri_plugin_window_state::{AppHandleExt, StateFlags};
|
use tauri_plugin_window_state::{AppHandleExt, StateFlags};
|
||||||
|
|
||||||
|
use crate::config;
|
||||||
use crate::{
|
use crate::{
|
||||||
portapi::{
|
portapi::{
|
||||||
client::PortAPI,
|
client::PortAPI,
|
||||||
|
@ -32,6 +35,17 @@ pub type AppIcon = TrayIcon<Wry>;
|
||||||
|
|
||||||
static SPN_STATE: AtomicBool = AtomicBool::new(false);
|
static SPN_STATE: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
enum IconColor {
|
||||||
|
Red,
|
||||||
|
Green,
|
||||||
|
Blue,
|
||||||
|
Yellow,
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURRENT_ICON_COLOR: RwLock<IconColor> = RwLock::new(IconColor::Red);
|
||||||
|
pub static USER_THEME: RwLock<dark_light::Mode> = RwLock::new(dark_light::Mode::Default);
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref SPN_STATUS: Mutex<Option<MenuItem<Wry>>> = Mutex::new(None);
|
static ref SPN_STATUS: Mutex<Option<MenuItem<Wry>>> = Mutex::new(None);
|
||||||
static ref SPN_BUTTON: Mutex<Option<MenuItem<Wry>>> = Mutex::new(None);
|
static ref SPN_BUTTON: Mutex<Option<MenuItem<Wry>>> = Mutex::new(None);
|
||||||
|
@ -42,14 +56,20 @@ const PM_TRAY_ICON_ID: &'static str = "pm_icon";
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
|
|
||||||
|
fn get_theme_mode() -> dark_light::Mode {
|
||||||
|
if let Ok(value) = USER_THEME.read() {
|
||||||
|
return *value.deref();
|
||||||
|
}
|
||||||
|
return dark_light::detect();
|
||||||
|
}
|
||||||
|
|
||||||
fn get_green_icon() -> &'static [u8] {
|
fn get_green_icon() -> &'static [u8] {
|
||||||
const LIGHT_GREEN_ICON: &'static [u8] =
|
const LIGHT_GREEN_ICON: &'static [u8] =
|
||||||
include_bytes!("../../../../assets/data/icons/pm_light_green_64.png");
|
include_bytes!("../../../../assets/data/icons/pm_light_green_64.png");
|
||||||
const DARK_GREEN_ICON: &'static [u8] =
|
const DARK_GREEN_ICON: &'static [u8] =
|
||||||
include_bytes!("../../../../assets/data/icons/pm_dark_green_64.png");
|
include_bytes!("../../../../assets/data/icons/pm_dark_green_64.png");
|
||||||
|
|
||||||
let mode = dark_light::detect();
|
match get_theme_mode() {
|
||||||
match mode {
|
|
||||||
dark_light::Mode::Light => DARK_GREEN_ICON,
|
dark_light::Mode::Light => DARK_GREEN_ICON,
|
||||||
_ => LIGHT_GREEN_ICON,
|
_ => LIGHT_GREEN_ICON,
|
||||||
}
|
}
|
||||||
|
@ -60,8 +80,7 @@ fn get_blue_icon() -> &'static [u8] {
|
||||||
include_bytes!("../../../../assets/data/icons/pm_light_blue_64.png");
|
include_bytes!("../../../../assets/data/icons/pm_light_blue_64.png");
|
||||||
const DARK_BLUE_ICON: &'static [u8] =
|
const DARK_BLUE_ICON: &'static [u8] =
|
||||||
include_bytes!("../../../../assets/data/icons/pm_dark_blue_64.png");
|
include_bytes!("../../../../assets/data/icons/pm_dark_blue_64.png");
|
||||||
let mode = dark_light::detect();
|
match get_theme_mode() {
|
||||||
match mode {
|
|
||||||
dark_light::Mode::Light => DARK_BLUE_ICON,
|
dark_light::Mode::Light => DARK_BLUE_ICON,
|
||||||
_ => LIGHT_BLUE_ICON,
|
_ => LIGHT_BLUE_ICON,
|
||||||
}
|
}
|
||||||
|
@ -72,8 +91,7 @@ fn get_red_icon() -> &'static [u8] {
|
||||||
include_bytes!("../../../../assets/data/icons/pm_light_red_64.png");
|
include_bytes!("../../../../assets/data/icons/pm_light_red_64.png");
|
||||||
const DARK_RED_ICON: &'static [u8] =
|
const DARK_RED_ICON: &'static [u8] =
|
||||||
include_bytes!("../../../../assets/data/icons/pm_dark_red_64.png");
|
include_bytes!("../../../../assets/data/icons/pm_dark_red_64.png");
|
||||||
let mode = dark_light::detect();
|
match get_theme_mode() {
|
||||||
match mode {
|
|
||||||
dark_light::Mode::Light => DARK_RED_ICON,
|
dark_light::Mode::Light => DARK_RED_ICON,
|
||||||
_ => LIGHT_RED_ICON,
|
_ => LIGHT_RED_ICON,
|
||||||
}
|
}
|
||||||
|
@ -82,20 +100,28 @@ fn get_red_icon() -> &'static [u8] {
|
||||||
fn get_yellow_icon() -> &'static [u8] {
|
fn get_yellow_icon() -> &'static [u8] {
|
||||||
const LIGHT_YELLOW_ICON: &'static [u8] =
|
const LIGHT_YELLOW_ICON: &'static [u8] =
|
||||||
include_bytes!("../../../../assets/data/icons/pm_light_yellow_64.png");
|
include_bytes!("../../../../assets/data/icons/pm_light_yellow_64.png");
|
||||||
|
|
||||||
const DARK_YELLOW_ICON: &'static [u8] =
|
const DARK_YELLOW_ICON: &'static [u8] =
|
||||||
include_bytes!("../../../../assets/data/icons/pm_dark_yellow_64.png");
|
include_bytes!("../../../../assets/data/icons/pm_dark_yellow_64.png");
|
||||||
let mode = dark_light::detect();
|
match get_theme_mode() {
|
||||||
match mode {
|
|
||||||
dark_light::Mode::Light => DARK_YELLOW_ICON,
|
dark_light::Mode::Light => DARK_YELLOW_ICON,
|
||||||
_ => LIGHT_YELLOW_ICON,
|
_ => LIGHT_YELLOW_ICON,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_icon(icon: IconColor) -> &'static [u8] {
|
||||||
|
match icon {
|
||||||
|
IconColor::Red => get_red_icon(),
|
||||||
|
IconColor::Green => get_green_icon(),
|
||||||
|
IconColor::Blue => get_blue_icon(),
|
||||||
|
IconColor::Yellow => get_yellow_icon(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn setup_tray_menu(
|
pub fn setup_tray_menu(
|
||||||
app: &mut tauri::App,
|
app: &mut tauri::App,
|
||||||
) -> core::result::Result<AppIcon, Box<dyn std::error::Error>> {
|
) -> core::result::Result<AppIcon, Box<dyn std::error::Error>> {
|
||||||
// Tray menu
|
// Tray menu
|
||||||
|
load_theme(app.handle());
|
||||||
let open_btn = MenuItemBuilder::with_id("open", "Open App").build(app)?;
|
let open_btn = MenuItemBuilder::with_id("open", "Open App").build(app)?;
|
||||||
let exit_ui_btn = MenuItemBuilder::with_id("exit_ui", "Exit UI").build(app)?;
|
let exit_ui_btn = MenuItemBuilder::with_id("exit_ui", "Exit UI").build(app)?;
|
||||||
let shutdown_btn = MenuItemBuilder::with_id("shutdown", "Shut Down Portmaster").build(app)?;
|
let shutdown_btn = MenuItemBuilder::with_id("shutdown", "Shut Down Portmaster").build(app)?;
|
||||||
|
@ -118,6 +144,7 @@ pub fn setup_tray_menu(
|
||||||
let mut button_ref = SPN_STATUS.lock()?;
|
let mut button_ref = SPN_STATUS.lock()?;
|
||||||
*button_ref = Some(spn_status.clone());
|
*button_ref = Some(spn_status.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup SPN button
|
// Setup SPN button
|
||||||
let spn = MenuItemBuilder::with_id("spn_toggle", "Enable SPN")
|
let spn = MenuItemBuilder::with_id("spn_toggle", "Enable SPN")
|
||||||
.build(app)
|
.build(app)
|
||||||
|
@ -127,6 +154,19 @@ pub fn setup_tray_menu(
|
||||||
*button_ref = Some(spn.clone());
|
*button_ref = Some(spn.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let system_theme = MenuItemBuilder::with_id("system_theme", "System")
|
||||||
|
.build(app)
|
||||||
|
.unwrap();
|
||||||
|
let light_theme = MenuItemBuilder::with_id("light_theme", "Light")
|
||||||
|
.build(app)
|
||||||
|
.unwrap();
|
||||||
|
let dark_theme = MenuItemBuilder::with_id("dark_theme", "Dark")
|
||||||
|
.build(app)
|
||||||
|
.unwrap();
|
||||||
|
let theme_menu = SubmenuBuilder::new(app, "Icon Theme")
|
||||||
|
.items(&[&system_theme, &light_theme, &dark_theme])
|
||||||
|
.build()?;
|
||||||
|
|
||||||
let force_show_window = MenuItemBuilder::with_id("force-show", "Force Show UI").build(app)?;
|
let force_show_window = MenuItemBuilder::with_id("force-show", "Force Show UI").build(app)?;
|
||||||
let reload_btn = MenuItemBuilder::with_id("reload", "Reload User Interface").build(app)?;
|
let reload_btn = MenuItemBuilder::with_id("reload", "Reload User Interface").build(app)?;
|
||||||
let developer_menu = SubmenuBuilder::new(app, "Developer")
|
let developer_menu = SubmenuBuilder::new(app, "Developer")
|
||||||
|
@ -142,6 +182,8 @@ pub fn setup_tray_menu(
|
||||||
&spn_status,
|
&spn_status,
|
||||||
&spn,
|
&spn,
|
||||||
&PredefinedMenuItem::separator(app)?,
|
&PredefinedMenuItem::separator(app)?,
|
||||||
|
&theme_menu,
|
||||||
|
&PredefinedMenuItem::separator(app)?,
|
||||||
&exit_ui_btn,
|
&exit_ui_btn,
|
||||||
&shutdown_btn,
|
&shutdown_btn,
|
||||||
&developer_menu,
|
&developer_menu,
|
||||||
|
@ -197,6 +239,9 @@ pub fn setup_tray_menu(
|
||||||
"shutdown" => {
|
"shutdown" => {
|
||||||
app.portmaster().trigger_shutdown();
|
app.portmaster().trigger_shutdown();
|
||||||
}
|
}
|
||||||
|
"system_theme" => update_icon_theme(app, dark_light::Mode::Default),
|
||||||
|
"dark_theme" => update_icon_theme(app, dark_light::Mode::Dark),
|
||||||
|
"light_theme" => update_icon_theme(app, dark_light::Mode::Light),
|
||||||
other => {
|
other => {
|
||||||
error!("unknown menu event id: {}", other);
|
error!("unknown menu event id: {}", other);
|
||||||
}
|
}
|
||||||
|
@ -248,16 +293,15 @@ pub fn update_icon(icon: AppIcon, subsystems: HashMap<String, Subsystem>, spn_st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let next_icon = match failure.0 {
|
let icon_color = match failure.0 {
|
||||||
subsystem::FAILURE_WARNING => get_yellow_icon(),
|
subsystem::FAILURE_WARNING => IconColor::Yellow,
|
||||||
subsystem::FAILURE_ERROR => get_red_icon(),
|
subsystem::FAILURE_ERROR => IconColor::Red,
|
||||||
_ => match spn_status.as_str() {
|
_ => match spn_status.as_str() {
|
||||||
"connected" | "connecting" => get_blue_icon(),
|
"connected" | "connecting" => IconColor::Blue,
|
||||||
_ => get_green_icon(),
|
_ => IconColor::Green,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
update_icon_color(&icon, icon_color);
|
||||||
_ = icon.set_icon(Some(Image::from_bytes(next_icon).unwrap()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn tray_handler(cli: PortAPI, app: tauri::AppHandle) {
|
pub async fn tray_handler(cli: PortAPI, app: tauri::AppHandle) {
|
||||||
|
@ -333,7 +377,7 @@ pub async fn tray_handler(cli: PortAPI, app: tauri::AppHandle) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_ = icon.set_icon(Some(Image::from_bytes(get_blue_icon()).unwrap()));
|
update_icon_color(&icon, IconColor::Blue);
|
||||||
|
|
||||||
let mut subsystems: HashMap<String, Subsystem> = HashMap::new();
|
let mut subsystems: HashMap<String, Subsystem> = HashMap::new();
|
||||||
let mut spn_status: String = "".to_string();
|
let mut spn_status: String = "".to_string();
|
||||||
|
@ -439,19 +483,83 @@ pub async fn tray_handler(cli: PortAPI, app: tauri::AppHandle) {
|
||||||
};
|
};
|
||||||
debug!("Shutdown request received: {:?}", msg);
|
debug!("Shutdown request received: {:?}", msg);
|
||||||
match msg {
|
match msg {
|
||||||
Response::Ok(_, _) | Response::New(_, _) | Response::Update(_, _) => {
|
Response::Ok(msg, _) | Response::New(msg, _) | Response::Update(msg, _) => {
|
||||||
if let Err(err) = app.save_window_state(StateFlags::SIZE | StateFlags::POSITION) {
|
if let Err(err) = app.save_window_state(StateFlags::SIZE | StateFlags::POSITION) {
|
||||||
error!("failed to save window state: {}", err);
|
error!("failed to save window state: {}", err);
|
||||||
}
|
}
|
||||||
app.exit(0)},
|
debug!("shutting down: {}", msg);
|
||||||
|
app.exit(0)
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update_spn_ui_state(false);
|
update_spn_ui_state(false);
|
||||||
_ = icon.set_icon(Some(Image::from_bytes(get_red_icon()).unwrap()));
|
update_icon_color(&icon, IconColor::Red);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_icon_color(icon: &AppIcon, new_color: IconColor) {
|
||||||
|
if let Ok(mut value) = CURRENT_ICON_COLOR.write() {
|
||||||
|
*value = new_color;
|
||||||
|
}
|
||||||
|
_ = icon.set_icon(Some(Image::from_bytes(get_icon(new_color)).unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_icon_theme(app: &tauri::AppHandle, theme: dark_light::Mode) {
|
||||||
|
if let Ok(mut value) = USER_THEME.write() {
|
||||||
|
*value = theme;
|
||||||
|
}
|
||||||
|
let icon = match app.tray_by_id(PM_TRAY_ICON_ID) {
|
||||||
|
Some(icon) => icon,
|
||||||
|
None => {
|
||||||
|
error!("cancel theme update: missing try icon");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Ok(value) = CURRENT_ICON_COLOR.read() {
|
||||||
|
_ = icon.set_icon(Some(Image::from_bytes(get_icon(*value)).unwrap()));
|
||||||
|
}
|
||||||
|
for (_, v) in app.webview_windows() {
|
||||||
|
super::window::set_window_icon(&v);
|
||||||
|
}
|
||||||
|
save_theme(app, theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_theme(app: &tauri::AppHandle) {
|
||||||
|
match config::load(app) {
|
||||||
|
Ok(config) => {
|
||||||
|
let theme = match config.theme {
|
||||||
|
config::Theme::Light => dark_light::Mode::Light,
|
||||||
|
config::Theme::Dark => dark_light::Mode::Dark,
|
||||||
|
config::Theme::System => dark_light::Mode::Default,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(mut value) = USER_THEME.write() {
|
||||||
|
*value = theme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => error!("failed to load config file: {}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_theme(app: &tauri::AppHandle, mode: dark_light::Mode) {
|
||||||
|
match config::load(app) {
|
||||||
|
Ok(mut config) => {
|
||||||
|
let theme = match mode {
|
||||||
|
dark_light::Mode::Dark => config::Theme::Dark,
|
||||||
|
dark_light::Mode::Light => config::Theme::Light,
|
||||||
|
dark_light::Mode::Default => config::Theme::System,
|
||||||
|
};
|
||||||
|
config.theme = theme;
|
||||||
|
if let Err(err) = config::save(app, config) {
|
||||||
|
error!("failed to save config file: {}", err)
|
||||||
|
} else {
|
||||||
|
debug!("config updated");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => error!("failed to load config file: {}", err),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_spn_ui_state(enabled: bool) {
|
fn update_spn_ui_state(enabled: bool) {
|
||||||
|
|
|
@ -4,7 +4,7 @@ use tauri::{
|
||||||
WebviewWindow, WebviewWindowBuilder,
|
WebviewWindow, WebviewWindowBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::portmaster::PortmasterExt;
|
use crate::{portmaster::PortmasterExt, traymenu};
|
||||||
|
|
||||||
const LIGHT_PM_ICON: &'static [u8] =
|
const LIGHT_PM_ICON: &'static [u8] =
|
||||||
include_bytes!("../../../../assets/data/icons/pm_light_512.png");
|
include_bytes!("../../../../assets/data/icons/pm_light_512.png");
|
||||||
|
@ -51,11 +51,7 @@ pub fn create_main_window(app: &AppHandle) -> Result<WebviewWindow> {
|
||||||
|
|
||||||
// If the window is not yet navigated to the Portmaster UI, do it now.
|
// If the window is not yet navigated to the Portmaster UI, do it now.
|
||||||
may_navigate_to_ui(&mut window, false);
|
may_navigate_to_ui(&mut window, false);
|
||||||
|
set_window_icon(&window);
|
||||||
let _ = match dark_light::detect() {
|
|
||||||
dark_light::Mode::Light => window.set_icon(Image::from_bytes(DARK_PM_ICON).unwrap()),
|
|
||||||
_ => window.set_icon(Image::from_bytes(LIGHT_PM_ICON).unwrap()),
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
if let Ok(_) = std::env::var("TAURI_SHOW_IMMEDIATELY") {
|
if let Ok(_) = std::env::var("TAURI_SHOW_IMMEDIATELY") {
|
||||||
|
@ -83,6 +79,7 @@ pub fn create_splash_window(app: &AppHandle) -> Result<WebviewWindow> {
|
||||||
.title("Portmaster")
|
.title("Portmaster")
|
||||||
.inner_size(600.0, 250.0)
|
.inner_size(600.0, 250.0)
|
||||||
.build()?;
|
.build()?;
|
||||||
|
set_window_icon(&window);
|
||||||
|
|
||||||
let _ = window.request_user_attention(Some(UserAttentionType::Informational));
|
let _ = window.request_user_attention(Some(UserAttentionType::Informational));
|
||||||
|
|
||||||
|
@ -98,6 +95,30 @@ pub fn close_splash_window(app: &AppHandle) -> Result<()> {
|
||||||
return Err(tauri::Error::WindowNotFound);
|
return Err(tauri::Error::WindowNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hide_splash_window(app: &AppHandle) -> Result<()> {
|
||||||
|
if let Some(window) = app.get_webview_window("splash") {
|
||||||
|
return window.hide();
|
||||||
|
}
|
||||||
|
return Err(tauri::Error::WindowNotFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_window_icon(window: &WebviewWindow) {
|
||||||
|
let mut mode = if let Ok(value) = traymenu::USER_THEME.read() {
|
||||||
|
*value
|
||||||
|
} else {
|
||||||
|
dark_light::Mode::Default
|
||||||
|
};
|
||||||
|
|
||||||
|
if mode == dark_light::Mode::Default {
|
||||||
|
mode = dark_light::detect();
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = match mode {
|
||||||
|
dark_light::Mode::Light => window.set_icon(Image::from_bytes(DARK_PM_ICON).unwrap()),
|
||||||
|
_ => window.set_icon(Image::from_bytes(LIGHT_PM_ICON).unwrap()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Opens a window for the tauri application.
|
/// Opens a window for the tauri application.
|
||||||
///
|
///
|
||||||
/// If the main window has already been created, it is instructed to
|
/// If the main window has already been created, it is instructed to
|
||||||
|
@ -117,6 +138,7 @@ pub fn open_window(app: &AppHandle) -> Result<WebviewWindow> {
|
||||||
app.portmaster().show_window();
|
app.portmaster().show_window();
|
||||||
let _ = win.show();
|
let _ = win.show();
|
||||||
let _ = win.set_focus();
|
let _ = win.set_focus();
|
||||||
|
set_window_icon(&win);
|
||||||
Ok(win)
|
Ok(win)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue