@opengeni/desktop 6.5.2-canary.41607687019001 → 6.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +242 -21
- package/dist/index.js.map +1 -1
- package/dist/main/app.d.ts +8 -0
- package/dist/main/inbox-actions.d.ts +2 -1
- package/dist/main/meeting-detection/index.d.ts +36 -3
- package/dist/main/meeting-detection/ipc.d.ts +1 -1
- package/dist/main/meeting-detection/public.js +77 -9
- package/dist/main/meeting-detection/public.js.map +1 -1
- package/dist/main/tray-icons.d.ts +1 -1
- package/dist/main/tray.d.ts +38 -6
- package/dist/preload/content.js +1 -1
- package/dist/preload/content.js.map +1 -1
- package/dist/preload/meeting-detection.js +1 -1
- package/dist/preload/meeting-detection.js.map +1 -1
- package/package.json +4 -5
- package/src/main/app.ts +60 -5
- package/src/main/inbox-actions.ts +11 -5
- package/src/main/meeting-detection/index.ts +103 -6
- package/src/main/meeting-detection/ipc.ts +6 -6
- package/src/main/tray-icons.ts +29 -2
- package/src/main/tray.ts +132 -10
- package/src/preload/meeting-detection.ts +2 -1
package/dist/index.js
CHANGED
|
@@ -3327,10 +3327,15 @@ import { Notification, powerMonitor } from "electron";
|
|
|
3327
3327
|
async function actOnInboxItem(client, item, action) {
|
|
3328
3328
|
if (action.kind === "approve" || action.kind === "deny") {
|
|
3329
3329
|
if (item.kind !== "approval") return false;
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3330
|
+
try {
|
|
3331
|
+
await client.sendApprovalDecision(item.workspaceId, item.sessionId, {
|
|
3332
|
+
approvalId: item.sourceKey,
|
|
3333
|
+
decision: action.kind === "approve" ? "approve" : "reject"
|
|
3334
|
+
});
|
|
3335
|
+
} catch (error) {
|
|
3336
|
+
if (error.status === 403) return false;
|
|
3337
|
+
throw error;
|
|
3338
|
+
}
|
|
3334
3339
|
return true;
|
|
3335
3340
|
}
|
|
3336
3341
|
if (item.kind !== "question") return false;
|
|
@@ -4317,6 +4322,16 @@ var MeetingDetectionStore = class {
|
|
|
4317
4322
|
var PROBLEMS = {
|
|
4318
4323
|
sound_server_unavailable: "Calls can't be noticed because no sound server (PulseAudio or PipeWire) is running."
|
|
4319
4324
|
};
|
|
4325
|
+
function recordingMeeting(value) {
|
|
4326
|
+
if (!value || typeof value !== "object") return null;
|
|
4327
|
+
const { title, elapsedMilliseconds, paused } = value;
|
|
4328
|
+
if (typeof elapsedMilliseconds !== "number" || !Number.isFinite(elapsedMilliseconds)) return null;
|
|
4329
|
+
return {
|
|
4330
|
+
title: typeof title === "string" && title.trim() ? title.trim().slice(0, 200) : null,
|
|
4331
|
+
elapsedMilliseconds: Math.max(0, elapsedMilliseconds),
|
|
4332
|
+
paused: paused === true
|
|
4333
|
+
};
|
|
4334
|
+
}
|
|
4320
4335
|
var RESTART_MIN_MS = 1e3;
|
|
4321
4336
|
var RESTART_MAX_MS = 6e4;
|
|
4322
4337
|
var REQUEST_WAIT_MS = 6e4;
|
|
@@ -4345,8 +4360,10 @@ var MeetingDetection = class {
|
|
|
4345
4360
|
running = false;
|
|
4346
4361
|
/** Pages that take choices, oldest first. */
|
|
4347
4362
|
pages = [];
|
|
4348
|
-
|
|
4363
|
+
/** The pages that record, oldest first, with what they said about it. */
|
|
4364
|
+
recordingPages = /* @__PURE__ */ new Map();
|
|
4349
4365
|
listeners = /* @__PURE__ */ new Set();
|
|
4366
|
+
recordingListeners = /* @__PURE__ */ new Set();
|
|
4350
4367
|
pending = null;
|
|
4351
4368
|
cannotRecord = null;
|
|
4352
4369
|
status() {
|
|
@@ -4400,11 +4417,67 @@ var MeetingDetection = class {
|
|
|
4400
4417
|
if (!listening || !pending) return;
|
|
4401
4418
|
if (this.send(pending.request)) this.clearPending();
|
|
4402
4419
|
}
|
|
4403
|
-
/**
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4420
|
+
/**
|
|
4421
|
+
* A page started or stopped recording a meeting, and what it said about
|
|
4422
|
+
* the meeting. A page built before it described its meetings says nothing:
|
|
4423
|
+
* the recording counts from when the app heard of it.
|
|
4424
|
+
*/
|
|
4425
|
+
setRecording(page, recording, meeting = null) {
|
|
4426
|
+
const now = this.now();
|
|
4427
|
+
const before = this.recordingPages.get(page);
|
|
4428
|
+
if (!recording) {
|
|
4429
|
+
if (!this.recordingPages.delete(page)) return;
|
|
4430
|
+
} else if (meeting) {
|
|
4431
|
+
this.recordingPages.set(page, { page, ...meeting, at: now, canOpen: true });
|
|
4432
|
+
} else if (!before) {
|
|
4433
|
+
this.recordingPages.set(page, {
|
|
4434
|
+
page,
|
|
4435
|
+
title: null,
|
|
4436
|
+
paused: false,
|
|
4437
|
+
elapsedMilliseconds: 0,
|
|
4438
|
+
at: now,
|
|
4439
|
+
canOpen: false
|
|
4440
|
+
});
|
|
4441
|
+
}
|
|
4442
|
+
this.prompter.setRecording(this.recordingPages.size > 0, now);
|
|
4443
|
+
for (const listener of this.recordingListeners) listener();
|
|
4444
|
+
}
|
|
4445
|
+
/** The meeting being recorded here, the newest when pages record several; null for none. */
|
|
4446
|
+
recording() {
|
|
4447
|
+
let newest = null;
|
|
4448
|
+
for (const [page, recording] of this.recordingPages) {
|
|
4449
|
+
if (!page.isDestroyed()) newest = recording;
|
|
4450
|
+
}
|
|
4451
|
+
return newest;
|
|
4452
|
+
}
|
|
4453
|
+
/** Runs `listener` when a recording starts, stops, or its title or pause changes. */
|
|
4454
|
+
onRecording(listener) {
|
|
4455
|
+
this.recordingListeners.add(listener);
|
|
4456
|
+
return () => {
|
|
4457
|
+
this.recordingListeners.delete(listener);
|
|
4458
|
+
};
|
|
4459
|
+
}
|
|
4460
|
+
/** Stop the recordings going on, from the app's menu; false when none is. */
|
|
4461
|
+
stopRecording() {
|
|
4462
|
+
const pages = [...this.recordingPages.keys()].filter((page) => !page.isDestroyed());
|
|
4463
|
+
if (pages.length === 0) return false;
|
|
4464
|
+
this.options.log("Meeting detection: stopping the recording from the menu.");
|
|
4465
|
+
for (const page of pages) {
|
|
4466
|
+
page.send(contract_exports.DESKTOP_IPC.meetingDetectionRequest, { kind: "stop", app: "" });
|
|
4467
|
+
}
|
|
4468
|
+
return true;
|
|
4469
|
+
}
|
|
4470
|
+
/**
|
|
4471
|
+
* Ask the page recording `recording` to show it; false when that page
|
|
4472
|
+
* can't (it didn't describe its recording) or is gone.
|
|
4473
|
+
*/
|
|
4474
|
+
openRecording(recording) {
|
|
4475
|
+
const page = recording.page;
|
|
4476
|
+
if (!recording.canOpen || page.isDestroyed() || !this.recordingPages.has(page)) return false;
|
|
4477
|
+
page.send(contract_exports.DESKTOP_IPC.meetingDetectionRequest, {
|
|
4478
|
+
kind: "open"
|
|
4479
|
+
});
|
|
4480
|
+
return true;
|
|
4408
4481
|
}
|
|
4409
4482
|
/** A page closed or went to another address: it neither records nor listens. */
|
|
4410
4483
|
pageGone(page) {
|
|
@@ -5039,21 +5112,21 @@ function handleMeetingDetectionIpc(input) {
|
|
|
5039
5112
|
});
|
|
5040
5113
|
};
|
|
5041
5114
|
const on = (channel, run2) => {
|
|
5042
|
-
ipcMain2.on(channel, (event, arg) => {
|
|
5115
|
+
ipcMain2.on(channel, (event, arg, more) => {
|
|
5043
5116
|
try {
|
|
5044
5117
|
allow(event);
|
|
5045
5118
|
} catch {
|
|
5046
5119
|
return;
|
|
5047
5120
|
}
|
|
5048
5121
|
watch(event.sender);
|
|
5049
|
-
run2(event.sender, arg);
|
|
5122
|
+
run2(event.sender, arg, more);
|
|
5050
5123
|
});
|
|
5051
5124
|
};
|
|
5052
5125
|
handle(contract_exports.DESKTOP_IPC.meetingDetectionStatus, () => detection.status());
|
|
5053
5126
|
handle(contract_exports.DESKTOP_IPC.meetingDetectionUpdate, (change) => detection.update(change));
|
|
5054
5127
|
on(
|
|
5055
5128
|
contract_exports.DESKTOP_IPC.meetingDetectionRecording,
|
|
5056
|
-
(page, recording) => detection.setRecording(page, recording === true)
|
|
5129
|
+
(page, recording, meeting) => detection.setRecording(page, recording === true, recordingMeeting(meeting))
|
|
5057
5130
|
);
|
|
5058
5131
|
on(
|
|
5059
5132
|
contract_exports.DESKTOP_IPC.meetingDetectionListen,
|
|
@@ -5510,6 +5583,14 @@ function stroke(ax, ay, bx, by, width) {
|
|
|
5510
5583
|
function capsule(cx, top, bottom, width) {
|
|
5511
5584
|
return stroke(cx, top + width / 2, cx, bottom - width / 2, width);
|
|
5512
5585
|
}
|
|
5586
|
+
function roundedBox(left, top, right, bottom, r) {
|
|
5587
|
+
return (x, y) => {
|
|
5588
|
+
if (x < left || x > right || y < top || y > bottom) return false;
|
|
5589
|
+
const dx = Math.max(left + r - x, 0, x - (right - r));
|
|
5590
|
+
const dy = Math.max(top + r - y, 0, y - (bottom - r));
|
|
5591
|
+
return dx * dx + dy * dy <= r * r;
|
|
5592
|
+
};
|
|
5593
|
+
}
|
|
5513
5594
|
function ink(...parts) {
|
|
5514
5595
|
return (x, y) => parts.some((part) => part(x, y)) ? "ink" : "none";
|
|
5515
5596
|
}
|
|
@@ -5539,6 +5620,22 @@ var SHAPES = {
|
|
|
5539
5620
|
});
|
|
5540
5621
|
return ink(...bars);
|
|
5541
5622
|
},
|
|
5623
|
+
// A recording badge: a dot and a sound wave in a pill, a meeting being recorded.
|
|
5624
|
+
meeting: () => {
|
|
5625
|
+
const outer = roundedBox(0.03, 0.25, 0.97, 0.75, 0.25);
|
|
5626
|
+
const inner = roundedBox(0.105, 0.325, 0.895, 0.675, 0.175);
|
|
5627
|
+
const dot = circle(0.3, 0.5, 0.105);
|
|
5628
|
+
const wave = ink(
|
|
5629
|
+
capsule(0.53, 0.43, 0.57, 0.07),
|
|
5630
|
+
capsule(0.645, 0.37, 0.63, 0.07),
|
|
5631
|
+
capsule(0.76, 0.43, 0.57, 0.07)
|
|
5632
|
+
);
|
|
5633
|
+
return (x, y) => {
|
|
5634
|
+
if (dot(x, y)) return "accent";
|
|
5635
|
+
if (outer(x, y) && !inner(x, y)) return "ink";
|
|
5636
|
+
return wave(x, y);
|
|
5637
|
+
};
|
|
5638
|
+
},
|
|
5542
5639
|
// A check: the text is where it was going.
|
|
5543
5640
|
done: () => ink(stroke(0.2, 0.52, 0.41, 0.73, 0.11), stroke(0.41, 0.73, 0.8, 0.29, 0.11)),
|
|
5544
5641
|
// A warning sign with the exclamation mark cut out.
|
|
@@ -5555,6 +5652,7 @@ var SHAPES = {
|
|
|
5555
5652
|
|
|
5556
5653
|
// src/main/tray.ts
|
|
5557
5654
|
var DICTATION_DONE_MS = 800;
|
|
5655
|
+
var MEETING_TICK_MS = 3e4;
|
|
5558
5656
|
var PERMISSION_LABELS = {
|
|
5559
5657
|
screenRecording: "Allow Screen Recording\u2026",
|
|
5560
5658
|
accessibility: "Allow Accessibility\u2026",
|
|
@@ -5576,6 +5674,11 @@ var AppTray = class {
|
|
|
5576
5674
|
idle;
|
|
5577
5675
|
summary = null;
|
|
5578
5676
|
dictationMenu = null;
|
|
5677
|
+
meeting = null;
|
|
5678
|
+
meetingTimer = null;
|
|
5679
|
+
/** The menu is open: rebuilding it then could close it, so wait. */
|
|
5680
|
+
menuOpen = false;
|
|
5681
|
+
stale = false;
|
|
5579
5682
|
/** The glyph showing; null for the app's icon. */
|
|
5580
5683
|
glyph = null;
|
|
5581
5684
|
images = /* @__PURE__ */ new Map();
|
|
@@ -5591,6 +5694,17 @@ var AppTray = class {
|
|
|
5591
5694
|
if (menu && menu.activity.phase !== "idle") this.clearDone();
|
|
5592
5695
|
this.render();
|
|
5593
5696
|
}
|
|
5697
|
+
/** The meeting being recorded; null when none is. */
|
|
5698
|
+
setMeeting(meeting) {
|
|
5699
|
+
this.meeting = meeting;
|
|
5700
|
+
if (meeting && !this.meetingTimer) {
|
|
5701
|
+
this.meetingTimer = setInterval(() => this.render(), MEETING_TICK_MS);
|
|
5702
|
+
this.meetingTimer.unref?.();
|
|
5703
|
+
} else if (!meeting) {
|
|
5704
|
+
this.stopMeetingTimer();
|
|
5705
|
+
}
|
|
5706
|
+
this.render();
|
|
5707
|
+
}
|
|
5594
5708
|
/** A dictation's text was delivered: a check, briefly. */
|
|
5595
5709
|
dictationDone() {
|
|
5596
5710
|
this.clearDone();
|
|
@@ -5603,6 +5717,7 @@ var AppTray = class {
|
|
|
5603
5717
|
destroy() {
|
|
5604
5718
|
this.clearDone();
|
|
5605
5719
|
this.stopAnimation();
|
|
5720
|
+
this.stopMeetingTimer();
|
|
5606
5721
|
this.tray.destroy();
|
|
5607
5722
|
}
|
|
5608
5723
|
render() {
|
|
@@ -5612,15 +5727,30 @@ var AppTray = class {
|
|
|
5612
5727
|
this.config.productName,
|
|
5613
5728
|
this.actions,
|
|
5614
5729
|
this.dictationMenu,
|
|
5615
|
-
this.platform
|
|
5730
|
+
this.platform,
|
|
5731
|
+
this.meeting
|
|
5616
5732
|
);
|
|
5617
5733
|
this.tray.setToolTip(toolTip);
|
|
5618
|
-
this.
|
|
5734
|
+
if (this.menuOpen) {
|
|
5735
|
+
this.stale = true;
|
|
5736
|
+
} else {
|
|
5737
|
+
const menu = Menu2.buildFromTemplate(template);
|
|
5738
|
+
menu.on("menu-will-show", () => {
|
|
5739
|
+
this.menuOpen = true;
|
|
5740
|
+
});
|
|
5741
|
+
menu.on("menu-will-close", () => {
|
|
5742
|
+
this.menuOpen = false;
|
|
5743
|
+
if (!this.stale) return;
|
|
5744
|
+
this.stale = false;
|
|
5745
|
+
setTimeout(() => this.render(), 0);
|
|
5746
|
+
});
|
|
5747
|
+
this.tray.setContextMenu(menu);
|
|
5748
|
+
}
|
|
5619
5749
|
this.showIcon();
|
|
5620
5750
|
}
|
|
5621
5751
|
showIcon() {
|
|
5622
5752
|
const phase = this.dictationMenu?.activity.phase ?? "idle";
|
|
5623
|
-
const glyph = phase !== "idle" ? phase : this.doneTimer ? "done" : null;
|
|
5753
|
+
const glyph = phase !== "idle" ? phase : this.doneTimer ? "done" : this.meeting ? "meeting" : null;
|
|
5624
5754
|
if (glyph === this.glyph) return;
|
|
5625
5755
|
this.glyph = glyph;
|
|
5626
5756
|
this.stopAnimation();
|
|
@@ -5652,6 +5782,10 @@ var AppTray = class {
|
|
|
5652
5782
|
if (this.animation) clearInterval(this.animation);
|
|
5653
5783
|
this.animation = null;
|
|
5654
5784
|
}
|
|
5785
|
+
stopMeetingTimer() {
|
|
5786
|
+
if (this.meetingTimer) clearInterval(this.meetingTimer);
|
|
5787
|
+
this.meetingTimer = null;
|
|
5788
|
+
}
|
|
5655
5789
|
clearDone() {
|
|
5656
5790
|
if (this.doneTimer) clearTimeout(this.doneTimer);
|
|
5657
5791
|
this.doneTimer = null;
|
|
@@ -5739,6 +5873,43 @@ function dictationSection(menu, actions, platform) {
|
|
|
5739
5873
|
};
|
|
5740
5874
|
}
|
|
5741
5875
|
}
|
|
5876
|
+
function recordedWords(milliseconds) {
|
|
5877
|
+
const minutes = Math.floor(milliseconds / 6e4);
|
|
5878
|
+
if (minutes < 1) return "just started";
|
|
5879
|
+
if (minutes < 60) return `${minutes} min`;
|
|
5880
|
+
const hours = Math.floor(minutes / 60);
|
|
5881
|
+
const rest = minutes % 60;
|
|
5882
|
+
return rest === 0 ? `${hours} h` : `${hours} h ${rest} min`;
|
|
5883
|
+
}
|
|
5884
|
+
function clockTime(at) {
|
|
5885
|
+
return new Date(at).toLocaleTimeString(void 0, { hour: "2-digit", minute: "2-digit" });
|
|
5886
|
+
}
|
|
5887
|
+
function meetingSection(meeting, actions, now) {
|
|
5888
|
+
const recorded = meeting.elapsedMilliseconds + (meeting.paused ? 0 : Math.max(0, now - meeting.at));
|
|
5889
|
+
const started = meeting.at - meeting.elapsedMilliseconds;
|
|
5890
|
+
const what = meeting.title ? shorten(meeting.title) : `Started ${clockTime(started)}`;
|
|
5891
|
+
return [
|
|
5892
|
+
{
|
|
5893
|
+
label: `Meeting: ${meeting.paused ? "paused" : "recording"} \xB7 ${recordedWords(recorded)}`,
|
|
5894
|
+
enabled: false
|
|
5895
|
+
},
|
|
5896
|
+
{
|
|
5897
|
+
label: meeting.otherAccount ? `${what} \xB7 ${shorten(meeting.otherAccount)}` : what,
|
|
5898
|
+
enabled: false
|
|
5899
|
+
},
|
|
5900
|
+
{
|
|
5901
|
+
label: meeting.canOpen ? "Open Live Transcript" : "Show Recording",
|
|
5902
|
+
click: () => actions.meeting?.("open")
|
|
5903
|
+
},
|
|
5904
|
+
{ label: "Stop Recording", click: () => actions.meeting?.("stop") },
|
|
5905
|
+
{ type: "separator" }
|
|
5906
|
+
];
|
|
5907
|
+
}
|
|
5908
|
+
function meetingTip(meeting, now) {
|
|
5909
|
+
if (!meeting) return null;
|
|
5910
|
+
const recorded = meeting.elapsedMilliseconds + (meeting.paused ? 0 : Math.max(0, now - meeting.at));
|
|
5911
|
+
return meeting.paused ? `meeting recording paused (${recordedWords(recorded)})` : `recording a meeting (${recordedWords(recorded)})`;
|
|
5912
|
+
}
|
|
5742
5913
|
function dictationTip(menu) {
|
|
5743
5914
|
const activity = menu?.activity;
|
|
5744
5915
|
switch (activity?.phase) {
|
|
@@ -5754,11 +5925,11 @@ function dictationTip(menu) {
|
|
|
5754
5925
|
return null;
|
|
5755
5926
|
}
|
|
5756
5927
|
}
|
|
5757
|
-
function trayMenu(summary, productName, actions, dictation = null, platform = process.platform) {
|
|
5928
|
+
function trayMenu(summary, productName, actions, dictation = null, platform = process.platform, meeting = null, now = Date.now()) {
|
|
5758
5929
|
const missing = summary.running ? summary.missingPermissions ?? [] : [];
|
|
5759
5930
|
const status = !summary.running ? "paused" : summary.needsReconnect ? "needs reconnecting" : missing.length > 0 ? "screen control needs permission" : summary.reconnecting ? "connecting\u2026" : "available to agents";
|
|
5760
|
-
const
|
|
5761
|
-
const toolTip =
|
|
5931
|
+
const busy = dictationTip(dictation) ?? meetingTip(meeting, now);
|
|
5932
|
+
const toolTip = busy ? `${productName}: ${busy}` : !summary.connected ? productName : `${productName}: ${!summary.running ? "this computer is paused" : summary.needsReconnect ? "this computer needs reconnecting" : summary.reconnecting ? "connecting this computer\u2026" : "this computer is available to agents"}`;
|
|
5762
5933
|
const computer = !summary.connected ? [] : [
|
|
5763
5934
|
{ label: `This computer: ${status}`, enabled: false },
|
|
5764
5935
|
// Reconnecting needs the account and workspace, which the window has.
|
|
@@ -5778,6 +5949,7 @@ function trayMenu(summary, productName, actions, dictation = null, platform = pr
|
|
|
5778
5949
|
return {
|
|
5779
5950
|
toolTip,
|
|
5780
5951
|
template: [
|
|
5952
|
+
...meeting ? meetingSection(meeting, actions, now) : [],
|
|
5781
5953
|
...dictationItems,
|
|
5782
5954
|
...computer,
|
|
5783
5955
|
{ label: `Open ${productName}`, click: () => actions.open() },
|
|
@@ -6928,6 +7100,16 @@ var DesktopShell = class _DesktopShell {
|
|
|
6928
7100
|
if (activity.phase === "done") this.tray?.dictationDone();
|
|
6929
7101
|
else this.tray?.setDictation(this.dictation.menu());
|
|
6930
7102
|
});
|
|
7103
|
+
let recordingMeeting2 = false;
|
|
7104
|
+
this.meetings.onRecording(() => {
|
|
7105
|
+
const recording = this.meetings.recording() !== null;
|
|
7106
|
+
if (recording !== recordingMeeting2) {
|
|
7107
|
+
recordingMeeting2 = recording;
|
|
7108
|
+
void this.refreshTray();
|
|
7109
|
+
} else {
|
|
7110
|
+
this.tray?.setMeeting(this.trayMeeting());
|
|
7111
|
+
}
|
|
7112
|
+
});
|
|
6931
7113
|
const hidden = (openedAtLogin() || this.reopenedWithoutWindow()) && this.store.active() !== null;
|
|
6932
7114
|
if (!hidden) this.openWindow();
|
|
6933
7115
|
if (process.platform === "darwin" && app3.isPackaged && this.config.thisComputer) {
|
|
@@ -7778,7 +7960,7 @@ var DesktopShell = class _DesktopShell {
|
|
|
7778
7960
|
);
|
|
7779
7961
|
if (change) setOpenAtLogin(this.config, change === "open");
|
|
7780
7962
|
}
|
|
7781
|
-
const wanted = (process.platform === "darwin" ? summary.connected : hasAccounts) || this.dictation.enabled;
|
|
7963
|
+
const wanted = (process.platform === "darwin" ? summary.connected : hasAccounts) || this.dictation.enabled || this.meetings.recording() !== null;
|
|
7782
7964
|
if (!wanted) {
|
|
7783
7965
|
this.tray?.destroy();
|
|
7784
7966
|
this.tray = null;
|
|
@@ -7790,11 +7972,50 @@ var DesktopShell = class _DesktopShell {
|
|
|
7790
7972
|
resume: () => void this.computer.resume().catch(() => void 0),
|
|
7791
7973
|
allow: (permission) => void this.computer.requestPermission(permission).catch(() => void 0),
|
|
7792
7974
|
quit: () => app3.quit(),
|
|
7793
|
-
dictation: (action) => this.dictation.menuAction(action)
|
|
7975
|
+
dictation: (action) => this.dictation.menuAction(action),
|
|
7976
|
+
meeting: (action) => this.meetingAction(action)
|
|
7794
7977
|
});
|
|
7795
7978
|
this.tray.setDictation(this.dictation.menu());
|
|
7979
|
+
this.tray.setMeeting(this.trayMeeting());
|
|
7796
7980
|
this.tray.update(summary);
|
|
7797
7981
|
}
|
|
7982
|
+
/** The meeting being recorded, for the menu: the newest, in whichever account records it. */
|
|
7983
|
+
trayMeeting() {
|
|
7984
|
+
const recording = this.meetings.recording();
|
|
7985
|
+
if (!recording) return null;
|
|
7986
|
+
const accountId = this.recordingAccount(recording);
|
|
7987
|
+
const shown = this.window?.accountId ?? this.store.snapshot().activeId;
|
|
7988
|
+
const other = accountId && accountId !== shown ? this.store.get(accountId) : null;
|
|
7989
|
+
return {
|
|
7990
|
+
title: recording.title,
|
|
7991
|
+
paused: recording.paused,
|
|
7992
|
+
elapsedMilliseconds: recording.elapsedMilliseconds,
|
|
7993
|
+
at: recording.at,
|
|
7994
|
+
canOpen: recording.canOpen,
|
|
7995
|
+
otherAccount: other ? other.email : null
|
|
7996
|
+
};
|
|
7997
|
+
}
|
|
7998
|
+
recordingAccount(recording) {
|
|
7999
|
+
const page = recording.page;
|
|
8000
|
+
return this.window?.accountFor(page) ?? null;
|
|
8001
|
+
}
|
|
8002
|
+
/**
|
|
8003
|
+
* The menu's meeting items. Opening shows the account that records, switching
|
|
8004
|
+
* to it first, then asks its page to show the meeting's live transcript.
|
|
8005
|
+
*/
|
|
8006
|
+
meetingAction(action) {
|
|
8007
|
+
const recording = this.meetings.recording();
|
|
8008
|
+
if (!recording) return;
|
|
8009
|
+
if (action === "stop") {
|
|
8010
|
+
this.meetings.stopRecording();
|
|
8011
|
+
return;
|
|
8012
|
+
}
|
|
8013
|
+
const accountId = this.recordingAccount(recording);
|
|
8014
|
+
if (accountId && accountId !== this.window?.accountId) this.showAccount(accountId);
|
|
8015
|
+
else this.reveal();
|
|
8016
|
+
app3.focus({ steal: true });
|
|
8017
|
+
this.meetings.openRecording(recording);
|
|
8018
|
+
}
|
|
7798
8019
|
};
|
|
7799
8020
|
function setOpenAtLogin(config, open) {
|
|
7800
8021
|
if (process.platform === "linux") {
|