dsh-offwork 1.1.2 → 1.2.2
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/CHANGELOG.md +27 -0
- package/README.md +16 -9
- package/ROADMAP.md +70 -0
- package/client.js +2468 -237
- package/client.source.js +514 -227
- package/companion-app.js +1431 -0
- package/companion-image.js +59 -0
- package/companion-state.js +424 -0
- package/docs/RELEASE-1.2.2.md +20 -0
- package/icon.svg +28 -1
- package/index.js +57 -6
- package/package.json +8 -2
- package/pet-interactions.js +41 -8
- package/pet-surfaces.js +1 -1
- package/pet-view.js +2 -0
- package/settings-api.js +126 -0
- package/tests/companion-state.test.mjs +267 -0
- package/tests/host.test.mjs +21 -14
- package/tests/pet-interactions.test.mjs +19 -0
- package/tests/settings-api.test.mjs +130 -0
- package/tests/ui.test.mjs +4 -1
- package/tools/build.mjs +7 -1
- package/tools/check-package.mjs +4 -0
package/client.source.js
CHANGED
|
@@ -83,7 +83,7 @@ window.__ModuleLoader__.load({
|
|
|
83
83
|
error: '操作失败,请重试。',
|
|
84
84
|
saved: '设置已保存',
|
|
85
85
|
days: '日一二三四五六',
|
|
86
|
-
privacy: '配置保存在 Harness
|
|
86
|
+
privacy: '配置保存在 Harness 所在机器;界面直接保存,不写入会话。代理访问默认关闭。',
|
|
87
87
|
drag: '按住可拖动;方向键微调,Home 复位',
|
|
88
88
|
setup: '先设好你的作息',
|
|
89
89
|
setupHint: '示例数值不是你的收入,保存后才开始计时。',
|
|
@@ -240,7 +240,8 @@ window.__ModuleLoader__.load({
|
|
|
240
240
|
error: 'Operation failed. Please retry.',
|
|
241
241
|
saved: 'Settings saved',
|
|
242
242
|
days: 'SMTWTFS',
|
|
243
|
-
privacy:
|
|
243
|
+
privacy:
|
|
244
|
+
'Settings stay on the Harness host. UI saves directly without conversation logs; agent access is off by default.',
|
|
244
245
|
drag: 'Drag to move; arrow keys to adjust; Home resets',
|
|
245
246
|
setup: 'Set up your schedule',
|
|
246
247
|
setupHint: 'These are example values, not your income. Save to start.',
|
|
@@ -330,7 +331,7 @@ window.__ModuleLoader__.load({
|
|
|
330
331
|
};
|
|
331
332
|
const STYLE =
|
|
332
333
|
`
|
|
333
|
-
.owc-v2{--owc-accent:color-mix(in srgb,var(--dsw-alias-brand-primary) 65%,#2563eb);pointer-events:auto;position:fixed;top:96px;right:24px;z-index:40;max-width:calc(100vw - 24px);max-height:calc(100dvh - 24px);border-radius:20px;color:var(--dsw-alias-label-primary);font:13px/1.45 -apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC',sans-serif;cursor:grab;touch-action:manipulation;user-select:none;-webkit-user-select:none}
|
|
334
|
+
.owc-v2{--owc-accent:color-mix(in srgb,var(--dsw-alias-brand-primary) 65%,#2563eb);pointer-events:auto;position:fixed;top:96px;right:24px;z-index:40;max-width:calc(100vw - 24px);max-height:calc(100dvh - 24px);border-radius:20px;color:var(--dsw-alias-label-primary);font:var(--owc-font-size,13px)/1.45 -apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC',sans-serif;cursor:grab;touch-action:manipulation;user-select:none;-webkit-user-select:none}
|
|
334
335
|
.owc-v2:active{cursor:grabbing}
|
|
335
336
|
.owc-v2.owc-compact{touch-action:none;border-radius:18px}
|
|
336
337
|
.owc-v2.owc-compact.owc-quick{width:296px;touch-action:manipulation}
|
|
@@ -492,7 +493,19 @@ window.__ModuleLoader__.load({
|
|
|
492
493
|
['path', { d: 'M13.1 3v3.2H9.9' }],
|
|
493
494
|
],
|
|
494
495
|
};
|
|
495
|
-
const LOCAL_SCREENS = [
|
|
496
|
+
const LOCAL_SCREENS = [
|
|
497
|
+
null,
|
|
498
|
+
'appearance',
|
|
499
|
+
'smoking',
|
|
500
|
+
'water-countdown',
|
|
501
|
+
'water',
|
|
502
|
+
'home',
|
|
503
|
+
'income',
|
|
504
|
+
'wrap',
|
|
505
|
+
'preferences',
|
|
506
|
+
'data',
|
|
507
|
+
'reminders',
|
|
508
|
+
];
|
|
496
509
|
const iconSvg = (name, size = 15) =>
|
|
497
510
|
h(
|
|
498
511
|
'svg',
|
|
@@ -658,6 +671,7 @@ window.__ModuleLoader__.load({
|
|
|
658
671
|
} catch {
|
|
659
672
|
/* Polling also synchronizes. */
|
|
660
673
|
}
|
|
674
|
+
return changedElsewhere ? null : next;
|
|
661
675
|
} catch {
|
|
662
676
|
if (alive) setSmokingError('timerStorageError');
|
|
663
677
|
} finally {
|
|
@@ -724,28 +738,83 @@ window.__ModuleLoader__.load({
|
|
|
724
738
|
const state = settings ? safeCalculate(settings) : null;
|
|
725
739
|
const preview = workingDraft ? safeCalculate(workingDraft) : null;
|
|
726
740
|
const safeState = state && !state.error ? state : null;
|
|
741
|
+
const features = useCompanionFeatures(React, {
|
|
742
|
+
language: locale.active,
|
|
743
|
+
screen: ui.screen,
|
|
744
|
+
menuOpen: !!ui.menu,
|
|
745
|
+
navigate: (screen, event) => navigateScreen(screen, event),
|
|
746
|
+
enableCharacter: () => updateAppearance({ companion: true }),
|
|
747
|
+
configured: !!data?.configured,
|
|
748
|
+
shift: data?.configured ? safeState : null,
|
|
749
|
+
timezone: settings?.timezone,
|
|
750
|
+
smoking,
|
|
751
|
+
smokingReady: smokingReady && !smokingError,
|
|
752
|
+
water,
|
|
753
|
+
waterReady: waterReady && !waterError,
|
|
754
|
+
waterOwner: waterOwner.current,
|
|
755
|
+
smokingLabel: t('smokingCountdown'),
|
|
756
|
+
waterLabel: t('waterDue'),
|
|
757
|
+
wrapLabel: t('companionDone'),
|
|
758
|
+
editing: editing || waterEditing || ui.screen === 'wrap' || !!ui.pending,
|
|
759
|
+
sessionIds,
|
|
760
|
+
sessionTitles: Object.fromEntries(
|
|
761
|
+
sessionIds.map((id) => [id, sessions?.byId?.[id]?.title]),
|
|
762
|
+
),
|
|
763
|
+
runningSessions: sessionIds.filter((id) => sessions?.byId?.[id]?.running === true),
|
|
764
|
+
view: savedView,
|
|
765
|
+
setView: (patch) => setPreference(patch),
|
|
766
|
+
openLegacy: (screen) => navigateScreen(screen),
|
|
767
|
+
reload,
|
|
768
|
+
refreshLegacy: () => {
|
|
769
|
+
waterRuntime.current?.tick();
|
|
770
|
+
smokingRuntime.current?.run({ type: 'retry' });
|
|
771
|
+
},
|
|
772
|
+
restartSmoking: () => smokingAction({ type: 'restart' }),
|
|
773
|
+
drink: () => waterAction({ type: 'manual-drink', actionId: crypto.randomUUID() }),
|
|
774
|
+
react: () => petMotion.current?.play('greet'),
|
|
775
|
+
});
|
|
776
|
+
const displayPreferences =
|
|
777
|
+
appearanceOnly && features.previewPreferences
|
|
778
|
+
? features.previewPreferences
|
|
779
|
+
: features.state.preferences;
|
|
780
|
+
const featureStyle = {
|
|
781
|
+
...(COMPANION_THEMES[displayPreferences.theme]
|
|
782
|
+
? { '--owc-accent': COMPANION_THEMES[displayPreferences.theme] }
|
|
783
|
+
: {}),
|
|
784
|
+
'--owc-font-size': 13 * displayPreferences.cardScale + 'px',
|
|
785
|
+
};
|
|
727
786
|
const petMode = ready && (appearanceOnly ? appearanceWasPet.current : view.companion);
|
|
728
|
-
const petClockStatus =
|
|
729
|
-
|
|
730
|
-
: error || state?.error
|
|
787
|
+
const petClockStatus =
|
|
788
|
+
error || state?.error
|
|
731
789
|
? 'petLoadFailed'
|
|
732
790
|
: !data
|
|
733
791
|
? 'loading'
|
|
734
792
|
: !data.configured
|
|
735
793
|
? 'petNeedsSetup'
|
|
736
794
|
: safeState?.status || 'loading';
|
|
737
|
-
const stageModel =
|
|
795
|
+
const stageModel = features.customImage
|
|
796
|
+
? 'custom-image'
|
|
797
|
+
: appearanceOnly
|
|
798
|
+
? savedView.petModel
|
|
799
|
+
: view.petModel;
|
|
738
800
|
const petGeometry = petLayout(
|
|
739
801
|
dragPosition ?? view.petPosition,
|
|
740
802
|
viewport,
|
|
741
803
|
appearanceOnly ? savedView.petSize : view.petSize,
|
|
742
804
|
420,
|
|
743
805
|
stageModel,
|
|
744
|
-
|
|
806
|
+
(window.matchMedia?.('(pointer:coarse)').matches ? 144 : 108) +
|
|
807
|
+
(features.activeTimer ? 30 : 0),
|
|
745
808
|
196,
|
|
746
809
|
);
|
|
747
810
|
const surfaceScreen = ui.screen || 'reminder';
|
|
748
|
-
const surfaceWidth =
|
|
811
|
+
const surfaceWidth = Math.max(
|
|
812
|
+
1,
|
|
813
|
+
Math.min(
|
|
814
|
+
petSurfaceWidth(surfaceScreen, viewport) * displayPreferences.cardScale,
|
|
815
|
+
viewport.width - 24,
|
|
816
|
+
),
|
|
817
|
+
);
|
|
749
818
|
const measureKey = [surfaceScreen, surfaceWidth, locale.active].join(':');
|
|
750
819
|
const measured = cardMeasure.key === measureKey;
|
|
751
820
|
const naturalHeight = measured ? cardMeasure.height : 320;
|
|
@@ -797,7 +866,7 @@ window.__ModuleLoader__.load({
|
|
|
797
866
|
});
|
|
798
867
|
const collapsed = !petMode && ui.screen === null && view.mini;
|
|
799
868
|
const classicClock = classicClockPresentation({
|
|
800
|
-
hasSession:
|
|
869
|
+
hasSession: true,
|
|
801
870
|
loaded: !!data,
|
|
802
871
|
configured: !!data?.configured,
|
|
803
872
|
failed: !!error || !!state?.error,
|
|
@@ -831,9 +900,16 @@ window.__ModuleLoader__.load({
|
|
|
831
900
|
classicSize,
|
|
832
901
|
);
|
|
833
902
|
const cardStyle = {
|
|
903
|
+
...featureStyle,
|
|
834
904
|
width: ui.screen
|
|
835
|
-
?
|
|
836
|
-
|
|
905
|
+
? Math.min(
|
|
906
|
+
petSurfaceWidth(ui.screen, viewport) * displayPreferences.cardScale,
|
|
907
|
+
viewport.width - 24,
|
|
908
|
+
)
|
|
909
|
+
: Math.min(
|
|
910
|
+
(collapsed ? 224 : 320) * displayPreferences.cardScale,
|
|
911
|
+
Math.max(1, viewport.width - 24),
|
|
912
|
+
),
|
|
837
913
|
'--owc-alpha': String(view.opacity),
|
|
838
914
|
'--owc-viewport-height': Math.max(1, viewport.height - 24) + 'px',
|
|
839
915
|
left: classicPosition.x,
|
|
@@ -1102,6 +1178,13 @@ window.__ModuleLoader__.load({
|
|
|
1102
1178
|
const outcome = await waterRuntime.current?.update(action);
|
|
1103
1179
|
const result = outcome?.state;
|
|
1104
1180
|
if (result) {
|
|
1181
|
+
if (outcome.recorded)
|
|
1182
|
+
void features.record({
|
|
1183
|
+
id: 'water-record:' + result.revision,
|
|
1184
|
+
type: 'water',
|
|
1185
|
+
at: Date.now(),
|
|
1186
|
+
label: 'Water',
|
|
1187
|
+
});
|
|
1105
1188
|
setWaterConfirm(null);
|
|
1106
1189
|
setNow(Date.now());
|
|
1107
1190
|
if (action.type === 'preferences')
|
|
@@ -1166,12 +1249,11 @@ window.__ModuleLoader__.load({
|
|
|
1166
1249
|
}
|
|
1167
1250
|
|
|
1168
1251
|
React.useEffect(() => {
|
|
1169
|
-
|
|
1170
|
-
else setError(t('noSession'));
|
|
1252
|
+
reload();
|
|
1171
1253
|
return () => {
|
|
1172
1254
|
generation.current++;
|
|
1173
1255
|
};
|
|
1174
|
-
}, [
|
|
1256
|
+
}, []);
|
|
1175
1257
|
|
|
1176
1258
|
React.useEffect(() => {
|
|
1177
1259
|
let timer;
|
|
@@ -1257,13 +1339,19 @@ window.__ModuleLoader__.load({
|
|
|
1257
1339
|
);
|
|
1258
1340
|
|
|
1259
1341
|
async function request(action, patch) {
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1342
|
+
const response = await fetch(new URL('offwork-clock/settings', document.baseURI), {
|
|
1343
|
+
method: action === 'get' ? 'GET' : 'POST',
|
|
1344
|
+
credentials: 'same-origin',
|
|
1345
|
+
cache: 'no-store',
|
|
1346
|
+
headers: {
|
|
1347
|
+
'X-Offwork-Client': '1',
|
|
1348
|
+
...(action === 'get' ? {} : { 'Content-Type': 'application/json' }),
|
|
1349
|
+
},
|
|
1350
|
+
...(action === 'get' ? {} : { body: JSON.stringify({ action, settings: patch }) }),
|
|
1351
|
+
});
|
|
1352
|
+
const result = await response.json();
|
|
1353
|
+
if (!response.ok || !result.ok) throw new Error(result.error || t('error'));
|
|
1354
|
+
return result;
|
|
1267
1355
|
}
|
|
1268
1356
|
|
|
1269
1357
|
async function reload(explicit = false) {
|
|
@@ -1435,6 +1523,7 @@ window.__ModuleLoader__.load({
|
|
|
1435
1523
|
function performNavigation(screen, root = false) {
|
|
1436
1524
|
if (root) panelPlacement.current = null;
|
|
1437
1525
|
if (screen !== ui.screen) {
|
|
1526
|
+
features.discardDrafts();
|
|
1438
1527
|
if (screen === 'water') {
|
|
1439
1528
|
waterPreferencesBase.current = { enabled: water.enabled, interval: water.interval };
|
|
1440
1529
|
setWaterInterval(String(water.interval));
|
|
@@ -1448,6 +1537,7 @@ window.__ModuleLoader__.load({
|
|
|
1448
1537
|
setError('');
|
|
1449
1538
|
}
|
|
1450
1539
|
if (screen === 'appearance') {
|
|
1540
|
+
features.beginAppearance();
|
|
1451
1541
|
appearanceBase.current = appearanceValues(savedView);
|
|
1452
1542
|
appearanceWasPet.current = !!petMode;
|
|
1453
1543
|
setAppearanceDraft(appearanceValues(savedView));
|
|
@@ -1462,6 +1552,7 @@ window.__ModuleLoader__.load({
|
|
|
1462
1552
|
setWaterConfirm(null);
|
|
1463
1553
|
}
|
|
1464
1554
|
function navigateScreen(screen, event) {
|
|
1555
|
+
if (screen === 'water-countdown') screen = 'home';
|
|
1465
1556
|
if (
|
|
1466
1557
|
screen !== null &&
|
|
1467
1558
|
!LOCAL_SCREENS.includes(screen) &&
|
|
@@ -1470,6 +1561,7 @@ window.__ModuleLoader__.load({
|
|
|
1470
1561
|
return;
|
|
1471
1562
|
if (
|
|
1472
1563
|
ui.pending ||
|
|
1564
|
+
features.busy ||
|
|
1473
1565
|
waterBusy ||
|
|
1474
1566
|
requestBusy.current ||
|
|
1475
1567
|
waterPending.current ||
|
|
@@ -1485,6 +1577,7 @@ window.__ModuleLoader__.load({
|
|
|
1485
1577
|
performNavigation(screen, root);
|
|
1486
1578
|
}
|
|
1487
1579
|
function draftChanged() {
|
|
1580
|
+
if (features.dirty) return true;
|
|
1488
1581
|
if (waterEditing && waterPreferencesBase.current)
|
|
1489
1582
|
return (
|
|
1490
1583
|
waterEnabledDraft !== waterPreferencesBase.current.enabled ||
|
|
@@ -1498,7 +1591,8 @@ window.__ModuleLoader__.load({
|
|
|
1498
1591
|
);
|
|
1499
1592
|
return false;
|
|
1500
1593
|
}
|
|
1501
|
-
function applyAppearance() {
|
|
1594
|
+
async function applyAppearance() {
|
|
1595
|
+
if (!(await features.applyAppearance())) return false;
|
|
1502
1596
|
panelPlacement.current = null;
|
|
1503
1597
|
if (appearanceDraft)
|
|
1504
1598
|
setPreference(changedSettings(appearanceBase.current, appearanceDraft));
|
|
@@ -1510,13 +1604,16 @@ window.__ModuleLoader__.load({
|
|
|
1510
1604
|
const destination = ui.pending.screen;
|
|
1511
1605
|
const result = waterEditing
|
|
1512
1606
|
? await saveWaterSettings({ preventDefault() {} })
|
|
1513
|
-
:
|
|
1514
|
-
?
|
|
1515
|
-
:
|
|
1607
|
+
: ui.screen === 'wrap'
|
|
1608
|
+
? await features.saveNotes(false)
|
|
1609
|
+
: appearanceOnly
|
|
1610
|
+
? await applyAppearance()
|
|
1611
|
+
: await save({ preventDefault() {} });
|
|
1516
1612
|
if (result) performNavigation(destination, ui.pending.root);
|
|
1517
1613
|
else dispatchUI({ type: 'stay' });
|
|
1518
1614
|
}
|
|
1519
1615
|
function updateAppearance(patch) {
|
|
1616
|
+
if (patch.petModel) features.useBuiltin();
|
|
1520
1617
|
setAppearanceDraft((current) => ({ ...current, ...patch }));
|
|
1521
1618
|
}
|
|
1522
1619
|
function openAppearance(event) {
|
|
@@ -1607,6 +1704,7 @@ window.__ModuleLoader__.load({
|
|
|
1607
1704
|
const waterState = hydrationView(water, now);
|
|
1608
1705
|
const waterClaim = water.claim;
|
|
1609
1706
|
const waterPrompt =
|
|
1707
|
+
!features.ready &&
|
|
1610
1708
|
waterReady &&
|
|
1611
1709
|
!waterError &&
|
|
1612
1710
|
!editing &&
|
|
@@ -1835,7 +1933,7 @@ window.__ModuleLoader__.load({
|
|
|
1835
1933
|
break: 'waterBreak',
|
|
1836
1934
|
paused: 'waterPaused',
|
|
1837
1935
|
finished: 'waterFinished',
|
|
1838
|
-
due:
|
|
1936
|
+
due: 'waterDue',
|
|
1839
1937
|
};
|
|
1840
1938
|
if (waterState.phase === 'quiet')
|
|
1841
1939
|
return t('waterQuiet') + ' · ' + formatDuration(waterState.quietRemaining / 1000);
|
|
@@ -1846,6 +1944,8 @@ window.__ModuleLoader__.load({
|
|
|
1846
1944
|
const waterCountdownText = () => {
|
|
1847
1945
|
if (waterError) return t('timerUnavailable');
|
|
1848
1946
|
if (!waterReady) return t('timerLoading');
|
|
1947
|
+
if (waterState.phase === 'due' && features.waterSnoozedUntil > now)
|
|
1948
|
+
return formatDuration(Math.ceil((features.waterSnoozedUntil - now) / 1000));
|
|
1849
1949
|
if (['countdown', 'due', 'break'].includes(waterState.phase))
|
|
1850
1950
|
return formatDuration(Math.ceil(waterState.remaining / 1000));
|
|
1851
1951
|
if (waterState.phase === 'quiet')
|
|
@@ -1864,25 +1964,34 @@ window.__ModuleLoader__.load({
|
|
|
1864
1964
|
? t(smokingError ? 'timerUnavailable' : 'timerLoading')
|
|
1865
1965
|
: smokingState.phase === 'idle'
|
|
1866
1966
|
? t('timerIdle')
|
|
1867
|
-
:
|
|
1967
|
+
: smokingState.phase === 'due' && features.smokingSnoozedUntil > now
|
|
1968
|
+
? formatDuration(Math.ceil((features.smokingSnoozedUntil - now) / 1000))
|
|
1969
|
+
: formatDuration(Math.ceil(smokingState.remaining / 1000));
|
|
1868
1970
|
const timerRow = (kind, value, due, title) => {
|
|
1869
|
-
|
|
1971
|
+
let phase = kind === 'water' ? waterState.phase : smokingState.phase;
|
|
1972
|
+
if (
|
|
1973
|
+
phase === 'due' &&
|
|
1974
|
+
(kind === 'water' ? features.waterSnoozedUntil : features.smokingSnoozedUntil) > now
|
|
1975
|
+
)
|
|
1976
|
+
phase = 'snoozed';
|
|
1870
1977
|
const extra = {
|
|
1978
|
+
snoozed: 'timerSnoozed',
|
|
1871
1979
|
paused: 'timerPaused',
|
|
1872
1980
|
break: 'timerBreak',
|
|
1873
1981
|
quiet: 'timerQuiet',
|
|
1874
1982
|
due: 'timerDue',
|
|
1875
1983
|
}[phase];
|
|
1876
1984
|
return h(
|
|
1877
|
-
'
|
|
1985
|
+
'button',
|
|
1878
1986
|
{
|
|
1987
|
+
type: 'button',
|
|
1988
|
+
onClick: (event) => navigateScreen(kind === 'water' ? 'home' : 'smoking', event),
|
|
1879
1989
|
className: 'owc-pet-timer-row',
|
|
1880
1990
|
'data-countdown': kind,
|
|
1881
|
-
'data-countdown-due': due,
|
|
1991
|
+
'data-countdown-due': due && phase !== 'snoozed',
|
|
1882
1992
|
'data-countdown-phase': phase,
|
|
1883
|
-
role: 'timer',
|
|
1884
1993
|
'aria-label': t(kind === 'water' ? 'waterCountdown' : 'smokingCountdown'),
|
|
1885
|
-
title,
|
|
1994
|
+
title: phase === 'snoozed' ? t('timerSnoozed') + ' · ' + value : title,
|
|
1886
1995
|
},
|
|
1887
1996
|
h(
|
|
1888
1997
|
'span',
|
|
@@ -1913,11 +2022,13 @@ window.__ModuleLoader__.load({
|
|
|
1913
2022
|
{ className: 'owc-detail-kicker', 'data-water-status': true },
|
|
1914
2023
|
t(
|
|
1915
2024
|
ticking
|
|
1916
|
-
?
|
|
1917
|
-
? '
|
|
1918
|
-
: waterState.phase === '
|
|
1919
|
-
? '
|
|
1920
|
-
: '
|
|
2025
|
+
? features.waterSnoozedUntil > now
|
|
2026
|
+
? 'timerSnoozed'
|
|
2027
|
+
: waterState.phase === 'quiet'
|
|
2028
|
+
? 'waterQuiet'
|
|
2029
|
+
: waterState.phase === 'due'
|
|
2030
|
+
? 'waterDue'
|
|
2031
|
+
: 'waterNext'
|
|
1921
2032
|
: 'waterTitle',
|
|
1922
2033
|
),
|
|
1923
2034
|
),
|
|
@@ -1995,14 +2106,16 @@ window.__ModuleLoader__.load({
|
|
|
1995
2106
|
{ role: 'status' },
|
|
1996
2107
|
smokingUnavailable
|
|
1997
2108
|
? t(smokingError ? 'timerUnavailable' : 'timerLoading')
|
|
1998
|
-
:
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2109
|
+
: smokingState.phase === 'due' && features.smokingSnoozedUntil > now
|
|
2110
|
+
? t('timerSnoozed')
|
|
2111
|
+
: t(
|
|
2112
|
+
{
|
|
2113
|
+
idle: 'timerIdle',
|
|
2114
|
+
running: 'timerRunning',
|
|
2115
|
+
paused: 'timerPaused',
|
|
2116
|
+
due: 'timerDue',
|
|
2117
|
+
}[smokingState.phase],
|
|
2118
|
+
),
|
|
2006
2119
|
),
|
|
2007
2120
|
h(
|
|
2008
2121
|
'label',
|
|
@@ -2069,7 +2182,8 @@ window.__ModuleLoader__.load({
|
|
|
2069
2182
|
t('timerStop'),
|
|
2070
2183
|
),
|
|
2071
2184
|
),
|
|
2072
|
-
|
|
2185
|
+
smokingState.phase !== 'idle' &&
|
|
2186
|
+
h('p', { className: 'owc-hint' }, t('detailNextInterval')),
|
|
2073
2187
|
h(
|
|
2074
2188
|
'details',
|
|
2075
2189
|
{ className: 'owc-detail-more' },
|
|
@@ -2525,11 +2639,12 @@ window.__ModuleLoader__.load({
|
|
|
2525
2639
|
h('span', { className: 'owc-classic-mini-label' }, t(caption)),
|
|
2526
2640
|
countdown
|
|
2527
2641
|
? h(
|
|
2528
|
-
'
|
|
2642
|
+
'button',
|
|
2529
2643
|
{
|
|
2644
|
+
type: 'button',
|
|
2645
|
+
onClick: (event) => navigateScreen('income', event),
|
|
2530
2646
|
className: 'owc-classic-mini-time',
|
|
2531
|
-
|
|
2532
|
-
'aria-label': t(classicClock.title),
|
|
2647
|
+
'aria-label': t('petCountdownCard'),
|
|
2533
2648
|
},
|
|
2534
2649
|
formatDuration(classicClock.seconds),
|
|
2535
2650
|
)
|
|
@@ -2662,7 +2777,7 @@ window.__ModuleLoader__.load({
|
|
|
2662
2777
|
h(
|
|
2663
2778
|
'strong',
|
|
2664
2779
|
{ className: 'owc-title', tabIndex: 0, title: t('drag'), onKeyDown: gripKeys },
|
|
2665
|
-
t(ui.screen ?
|
|
2780
|
+
t(ui.screen ? pageTitle(ui.screen) : 'classicOverview'),
|
|
2666
2781
|
),
|
|
2667
2782
|
['home', 'water-countdown'].includes(ui.screen) &&
|
|
2668
2783
|
h(
|
|
@@ -2691,6 +2806,18 @@ window.__ModuleLoader__.load({
|
|
|
2691
2806
|
},
|
|
2692
2807
|
iconSvg('water'),
|
|
2693
2808
|
),
|
|
2809
|
+
ui.screen &&
|
|
2810
|
+
h(
|
|
2811
|
+
'button',
|
|
2812
|
+
{
|
|
2813
|
+
type: 'button',
|
|
2814
|
+
className: 'owc-icon',
|
|
2815
|
+
'data-panel-more': true,
|
|
2816
|
+
'aria-label': t('quickMore'),
|
|
2817
|
+
onClick: openQuickMenu,
|
|
2818
|
+
},
|
|
2819
|
+
'⋯',
|
|
2820
|
+
),
|
|
2694
2821
|
!ui.screen &&
|
|
2695
2822
|
h(
|
|
2696
2823
|
React.Fragment,
|
|
@@ -2792,7 +2919,7 @@ window.__ModuleLoader__.load({
|
|
|
2792
2919
|
'button',
|
|
2793
2920
|
{
|
|
2794
2921
|
type: 'button',
|
|
2795
|
-
disabled: hostBusy
|
|
2922
|
+
disabled: hostBusy,
|
|
2796
2923
|
onClick: () => reload(true),
|
|
2797
2924
|
},
|
|
2798
2925
|
iconSvg('refresh', 12),
|
|
@@ -3128,7 +3255,6 @@ window.__ModuleLoader__.load({
|
|
|
3128
3255
|
h('span', { className: 'owc-dot' }),
|
|
3129
3256
|
t('loading'),
|
|
3130
3257
|
),
|
|
3131
|
-
!sessionId && h('p', { className: 'owc-hint' }, t('noSession')),
|
|
3132
3258
|
h(
|
|
3133
3259
|
'div',
|
|
3134
3260
|
{ className: 'owc-row-actions' },
|
|
@@ -3138,7 +3264,7 @@ window.__ModuleLoader__.load({
|
|
|
3138
3264
|
type: 'button',
|
|
3139
3265
|
className: 'owc-text',
|
|
3140
3266
|
onClick: () => reload(true),
|
|
3141
|
-
disabled: hostBusy
|
|
3267
|
+
disabled: hostBusy,
|
|
3142
3268
|
},
|
|
3143
3269
|
iconSvg('refresh', 12),
|
|
3144
3270
|
t('retry'),
|
|
@@ -3244,38 +3370,6 @@ window.__ModuleLoader__.load({
|
|
|
3244
3370
|
),
|
|
3245
3371
|
),
|
|
3246
3372
|
),
|
|
3247
|
-
h(
|
|
3248
|
-
'div',
|
|
3249
|
-
{ className: 'owc-row-actions' },
|
|
3250
|
-
h(
|
|
3251
|
-
'button',
|
|
3252
|
-
{
|
|
3253
|
-
type: 'button',
|
|
3254
|
-
className: 'owc-text',
|
|
3255
|
-
onClick: () => reload(true),
|
|
3256
|
-
disabled: hostBusy,
|
|
3257
|
-
},
|
|
3258
|
-
iconSvg('refresh', 12),
|
|
3259
|
-
t('refresh'),
|
|
3260
|
-
),
|
|
3261
|
-
petMode &&
|
|
3262
|
-
h(
|
|
3263
|
-
'button',
|
|
3264
|
-
{ type: 'button', className: 'owc-text', onClick: openEditor },
|
|
3265
|
-
t('petWorkSettings'),
|
|
3266
|
-
),
|
|
3267
|
-
!petMode &&
|
|
3268
|
-
h(
|
|
3269
|
-
'button',
|
|
3270
|
-
{
|
|
3271
|
-
type: 'button',
|
|
3272
|
-
className: 'owc-text',
|
|
3273
|
-
onClick: () =>
|
|
3274
|
-
setPreference(petMode ? { petPosition: null } : { position: null }),
|
|
3275
|
-
},
|
|
3276
|
-
t('reset'),
|
|
3277
|
-
),
|
|
3278
|
-
),
|
|
3279
3373
|
);
|
|
3280
3374
|
};
|
|
3281
3375
|
|
|
@@ -3295,66 +3389,85 @@ window.__ModuleLoader__.load({
|
|
|
3295
3389
|
}),
|
|
3296
3390
|
t('petMode'),
|
|
3297
3391
|
),
|
|
3298
|
-
h(
|
|
3299
|
-
'label',
|
|
3300
|
-
{ className: 'owc-check' },
|
|
3301
|
-
h('input', {
|
|
3302
|
-
type: 'checkbox',
|
|
3303
|
-
checked: view.companionMotion,
|
|
3304
|
-
disabled: !view.companion,
|
|
3305
|
-
onChange: (event) => updateAppearance({ companionMotion: event.target.checked }),
|
|
3306
|
-
}),
|
|
3307
|
-
t('companionMotion'),
|
|
3308
|
-
),
|
|
3309
3392
|
label(
|
|
3310
3393
|
t('petCharacter'),
|
|
3311
3394
|
h(
|
|
3312
3395
|
'select',
|
|
3313
3396
|
{
|
|
3314
3397
|
'aria-label': t('petCharacter'),
|
|
3315
|
-
value: view.petModel,
|
|
3398
|
+
value: features.previewImage ? 'custom-image' : view.petModel,
|
|
3316
3399
|
disabled: !view.companion,
|
|
3317
|
-
onChange: (event) =>
|
|
3400
|
+
onChange: (event) =>
|
|
3401
|
+
event.target.value === 'custom-image'
|
|
3402
|
+
? features.selectCustom()
|
|
3403
|
+
: updateAppearance({ petModel: event.target.value }),
|
|
3318
3404
|
},
|
|
3405
|
+
features.hasCustom &&
|
|
3406
|
+
h(
|
|
3407
|
+
'option',
|
|
3408
|
+
{ value: 'custom-image' },
|
|
3409
|
+
locale.active.startsWith('en') ? 'Custom image' : '自定义图片',
|
|
3410
|
+
),
|
|
3319
3411
|
...Object.values(PET_MODELS).map((model) =>
|
|
3320
3412
|
h('option', { key: model.id, value: model.id }, t(model.label)),
|
|
3321
3413
|
),
|
|
3322
3414
|
),
|
|
3323
3415
|
),
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
type: 'range',
|
|
3328
|
-
min: '80',
|
|
3329
|
-
max: '180',
|
|
3330
|
-
step: '4',
|
|
3331
|
-
value: view.petSize,
|
|
3332
|
-
'aria-label': t('petSize'),
|
|
3333
|
-
disabled: !view.companion,
|
|
3334
|
-
onChange: (event) => updateAppearance({ petSize: event.target.valueAsNumber }),
|
|
3335
|
-
}),
|
|
3336
|
-
),
|
|
3337
|
-
label(
|
|
3338
|
-
t('opacity'),
|
|
3416
|
+
h(
|
|
3417
|
+
'details',
|
|
3418
|
+
{ className: 'owc-appearance-display' },
|
|
3339
3419
|
h(
|
|
3340
|
-
|
|
3420
|
+
'summary',
|
|
3341
3421
|
null,
|
|
3422
|
+
locale.active.startsWith('en') ? 'Display and motion' : '显示与动作',
|
|
3423
|
+
),
|
|
3424
|
+
h(
|
|
3425
|
+
'label',
|
|
3426
|
+
{ className: 'owc-check' },
|
|
3342
3427
|
h('input', {
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
max: '100',
|
|
3347
|
-
step: '1',
|
|
3348
|
-
value: String(Math.round(view.opacity * 100)),
|
|
3349
|
-
disabled: busy,
|
|
3350
|
-
'aria-label': t('opacity'),
|
|
3428
|
+
type: 'checkbox',
|
|
3429
|
+
checked: view.companionMotion,
|
|
3430
|
+
disabled: !view.companion,
|
|
3351
3431
|
onChange: (event) =>
|
|
3352
|
-
updateAppearance({
|
|
3432
|
+
updateAppearance({ companionMotion: event.target.checked }),
|
|
3353
3433
|
}),
|
|
3434
|
+
t('companionMotion'),
|
|
3435
|
+
),
|
|
3436
|
+
label(
|
|
3437
|
+
t('petSize'),
|
|
3438
|
+
h('input', {
|
|
3439
|
+
type: 'range',
|
|
3440
|
+
min: '80',
|
|
3441
|
+
max: '180',
|
|
3442
|
+
step: '4',
|
|
3443
|
+
value: view.petSize,
|
|
3444
|
+
'aria-label': t('petSize'),
|
|
3445
|
+
disabled: !view.companion,
|
|
3446
|
+
onChange: (event) => updateAppearance({ petSize: event.target.valueAsNumber }),
|
|
3447
|
+
}),
|
|
3448
|
+
),
|
|
3449
|
+
label(
|
|
3450
|
+
t('opacity'),
|
|
3354
3451
|
h(
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3452
|
+
React.Fragment,
|
|
3453
|
+
null,
|
|
3454
|
+
h('input', {
|
|
3455
|
+
className: 'owc-range',
|
|
3456
|
+
type: 'range',
|
|
3457
|
+
min: '30',
|
|
3458
|
+
max: '100',
|
|
3459
|
+
step: '1',
|
|
3460
|
+
value: String(Math.round(view.opacity * 100)),
|
|
3461
|
+
disabled: busy,
|
|
3462
|
+
'aria-label': t('opacity'),
|
|
3463
|
+
onChange: (event) =>
|
|
3464
|
+
updateAppearance({ opacity: event.target.valueAsNumber / 100 }),
|
|
3465
|
+
}),
|
|
3466
|
+
h(
|
|
3467
|
+
'span',
|
|
3468
|
+
{ className: 'owc-range-value', title: t('opacityHint') },
|
|
3469
|
+
Math.round(view.opacity * 100) + '%',
|
|
3470
|
+
),
|
|
3358
3471
|
),
|
|
3359
3472
|
),
|
|
3360
3473
|
),
|
|
@@ -3440,6 +3553,7 @@ window.__ModuleLoader__.load({
|
|
|
3440
3553
|
{
|
|
3441
3554
|
ref: previewBox,
|
|
3442
3555
|
'data-appearance-preview': true,
|
|
3556
|
+
style: features.cropping ? { display: 'none' } : undefined,
|
|
3443
3557
|
className: 'owc-appearance-preview',
|
|
3444
3558
|
},
|
|
3445
3559
|
view.companion
|
|
@@ -3448,14 +3562,15 @@ window.__ModuleLoader__.load({
|
|
|
3448
3562
|
{ pose: 'calm', animate: false },
|
|
3449
3563
|
view.petSize * (petModel(view.petModel).renderer === 'svg' ? 1 : 0.65),
|
|
3450
3564
|
'',
|
|
3451
|
-
view.petModel,
|
|
3452
|
-
PET_SPRITES,
|
|
3453
|
-
petModel(view.petModel).renderer === 'video',
|
|
3565
|
+
features.previewImage ? 'custom-image' : view.petModel,
|
|
3566
|
+
{ ...PET_SPRITES, 'custom-image': features.previewImage },
|
|
3567
|
+
!features.previewImage && petModel(view.petModel).renderer === 'video',
|
|
3454
3568
|
)
|
|
3455
3569
|
: h('p', null, t('petClassicPreview')),
|
|
3456
3570
|
),
|
|
3457
|
-
previewActions(),
|
|
3571
|
+
!features.previewImage && previewActions(),
|
|
3458
3572
|
appearanceFields(),
|
|
3573
|
+
features.render('appearance'),
|
|
3459
3574
|
h(
|
|
3460
3575
|
'div',
|
|
3461
3576
|
{ className: 'owc-save' },
|
|
@@ -3668,8 +3783,6 @@ window.__ModuleLoader__.load({
|
|
|
3668
3783
|
{ className: 'owc-advanced' },
|
|
3669
3784
|
h('summary', null, t('advanced')),
|
|
3670
3785
|
timezoneField(),
|
|
3671
|
-
h('p', { className: 'owc-hint' }, t('sessionHint')),
|
|
3672
|
-
label(t('session'), sessionSelect()),
|
|
3673
3786
|
),
|
|
3674
3787
|
h('p', { className: 'owc-hint' }, t('privacy')),
|
|
3675
3788
|
h(
|
|
@@ -3747,7 +3860,7 @@ window.__ModuleLoader__.load({
|
|
|
3747
3860
|
if (scroll) scroll.scrollTop = 0;
|
|
3748
3861
|
}, [ready, petMode, ui.screen]);
|
|
3749
3862
|
const petShowing = petOpen;
|
|
3750
|
-
const petFloating = petShowing || autoWaterPrompt;
|
|
3863
|
+
const petFloating = petShowing || autoWaterPrompt || features.alert;
|
|
3751
3864
|
React.useLayoutEffect(() => {
|
|
3752
3865
|
if (!petMode || !petFloating || !cardContent.current) return;
|
|
3753
3866
|
const content = cardContent.current,
|
|
@@ -3836,20 +3949,38 @@ window.__ModuleLoader__.load({
|
|
|
3836
3949
|
return () => window.removeEventListener('blur', blur);
|
|
3837
3950
|
}, [ui.menu]);
|
|
3838
3951
|
React.useEffect(() => {
|
|
3839
|
-
if (!
|
|
3952
|
+
if (!petShowing && !ui.menu) return;
|
|
3840
3953
|
const outside = (event) => {
|
|
3954
|
+
if (ui.menu && event.target.closest?.('[data-quick-more],[data-panel-more]')) return;
|
|
3841
3955
|
if (ui.menu && !menuBox.current?.contains(event.target)) {
|
|
3842
3956
|
dispatchUI({ type: 'dismiss-menu' });
|
|
3843
3957
|
return;
|
|
3844
3958
|
}
|
|
3845
3959
|
if (box.current?.contains(event.target)) return;
|
|
3846
3960
|
if (ui.menu) dispatchUI({ type: 'dismiss-menu' });
|
|
3847
|
-
else if (
|
|
3848
|
-
|
|
3961
|
+
else if (
|
|
3962
|
+
petMode &&
|
|
3963
|
+
!editing &&
|
|
3964
|
+
!waterEditing &&
|
|
3965
|
+
!waterBusy &&
|
|
3966
|
+
!features.dirty &&
|
|
3967
|
+
!features.busy
|
|
3968
|
+
)
|
|
3969
|
+
navigateScreen(null);
|
|
3849
3970
|
};
|
|
3850
3971
|
document.addEventListener('pointerdown', outside);
|
|
3851
3972
|
return () => document.removeEventListener('pointerdown', outside);
|
|
3852
|
-
}, [
|
|
3973
|
+
}, [
|
|
3974
|
+
petMode,
|
|
3975
|
+
petShowing,
|
|
3976
|
+
ui.menu,
|
|
3977
|
+
ui.screen,
|
|
3978
|
+
editing,
|
|
3979
|
+
waterEditing,
|
|
3980
|
+
waterBusy,
|
|
3981
|
+
features.dirty,
|
|
3982
|
+
features.busy,
|
|
3983
|
+
]);
|
|
3853
3984
|
React.useEffect(() => {
|
|
3854
3985
|
if (!ui.menu) return;
|
|
3855
3986
|
const waterEntry = menuTrigger.current?.classList.contains('owc-pet-water-alert')
|
|
@@ -3967,7 +4098,21 @@ window.__ModuleLoader__.load({
|
|
|
3967
4098
|
water: 'petWaterSettings',
|
|
3968
4099
|
appearance: 'petAppearance',
|
|
3969
4100
|
schedule: 'petWorkSettings',
|
|
4101
|
+
wrap: 'companionWrapTitle',
|
|
4102
|
+
preferences: 'companionPreferencesTitle',
|
|
4103
|
+
data: 'companionDataTitle',
|
|
4104
|
+
reminders: 'companionRemindersTitle',
|
|
3970
4105
|
};
|
|
4106
|
+
const pageTitle = (screen) =>
|
|
4107
|
+
screen === 'income' && safeState
|
|
4108
|
+
? safeState.status === 'before'
|
|
4109
|
+
? t('petCountdownBefore')
|
|
4110
|
+
: safeState.status === 'done'
|
|
4111
|
+
? t('classicMiniFinished')
|
|
4112
|
+
: safeState.status === 'rest'
|
|
4113
|
+
? t('classicMiniRest')
|
|
4114
|
+
: t('petCountdownCard')
|
|
4115
|
+
: t(petPageTitle[screen] || 'waterTitle');
|
|
3971
4116
|
const petHeader = () =>
|
|
3972
4117
|
h(
|
|
3973
4118
|
'div',
|
|
@@ -3989,8 +4134,22 @@ window.__ModuleLoader__.load({
|
|
|
3989
4134
|
h(
|
|
3990
4135
|
'strong',
|
|
3991
4136
|
{ 'data-pet-page-title': true, tabIndex: -1, style: { flex: 1 } },
|
|
3992
|
-
|
|
4137
|
+
pageTitle(ui.screen),
|
|
3993
4138
|
),
|
|
4139
|
+
ui.screen === 'income' &&
|
|
4140
|
+
data?.configured &&
|
|
4141
|
+
h(
|
|
4142
|
+
'button',
|
|
4143
|
+
{
|
|
4144
|
+
type: 'button',
|
|
4145
|
+
className: 'owc-icon',
|
|
4146
|
+
'aria-label': t('petWorkSettings'),
|
|
4147
|
+
title: t('petWorkSettings'),
|
|
4148
|
+
disabled: busy || !!ui.pending,
|
|
4149
|
+
onClick: openEditor,
|
|
4150
|
+
},
|
|
4151
|
+
iconSvg('sliders', 14),
|
|
4152
|
+
),
|
|
3994
4153
|
['home', 'water-countdown'].includes(ui.screen) &&
|
|
3995
4154
|
h(
|
|
3996
4155
|
'button',
|
|
@@ -4004,6 +4163,17 @@ window.__ModuleLoader__.load({
|
|
|
4004
4163
|
},
|
|
4005
4164
|
iconSvg('sliders', 14),
|
|
4006
4165
|
),
|
|
4166
|
+
h(
|
|
4167
|
+
'button',
|
|
4168
|
+
{
|
|
4169
|
+
type: 'button',
|
|
4170
|
+
className: 'owc-icon',
|
|
4171
|
+
'data-panel-more': true,
|
|
4172
|
+
'aria-label': t('quickMore'),
|
|
4173
|
+
onClick: openQuickMenu,
|
|
4174
|
+
},
|
|
4175
|
+
'⋯',
|
|
4176
|
+
),
|
|
4007
4177
|
h(
|
|
4008
4178
|
'button',
|
|
4009
4179
|
{
|
|
@@ -4025,6 +4195,23 @@ window.__ModuleLoader__.load({
|
|
|
4025
4195
|
'data-water-event': waterPrompt ? waterState.eventId : undefined,
|
|
4026
4196
|
},
|
|
4027
4197
|
waterHero(),
|
|
4198
|
+
waterState.phase === 'due' &&
|
|
4199
|
+
features.waterSnoozedUntil > now &&
|
|
4200
|
+
h(
|
|
4201
|
+
'p',
|
|
4202
|
+
{ className: 'owc-hint' },
|
|
4203
|
+
t('waterSnooze') +
|
|
4204
|
+
' · ' +
|
|
4205
|
+
formatDuration(Math.ceil((features.waterSnoozedUntil - now) / 1000)),
|
|
4206
|
+
),
|
|
4207
|
+
features.quiet &&
|
|
4208
|
+
h(
|
|
4209
|
+
'p',
|
|
4210
|
+
{ className: 'owc-hint' },
|
|
4211
|
+
t('waterQuiet') +
|
|
4212
|
+
' · ' +
|
|
4213
|
+
formatDuration(Math.ceil((features.state.preferences.quietUntil - now) / 1000)),
|
|
4214
|
+
),
|
|
4028
4215
|
h(
|
|
4029
4216
|
'div',
|
|
4030
4217
|
{ className: 'owc-detail-primary-actions' },
|
|
@@ -4038,14 +4225,15 @@ window.__ModuleLoader__.load({
|
|
|
4038
4225
|
},
|
|
4039
4226
|
t('petRecord'),
|
|
4040
4227
|
),
|
|
4041
|
-
|
|
4228
|
+
waterState.phase === 'due' &&
|
|
4229
|
+
features.waterSnoozedUntil <= now &&
|
|
4042
4230
|
h(
|
|
4043
4231
|
'button',
|
|
4044
4232
|
{
|
|
4045
4233
|
type: 'button',
|
|
4046
4234
|
className: 'owc-text',
|
|
4047
|
-
disabled: waterBusy,
|
|
4048
|
-
onClick: () =>
|
|
4235
|
+
disabled: waterBusy || features.busy || !features.waterCanSnooze,
|
|
4236
|
+
onClick: () => features.snoozeWater(),
|
|
4049
4237
|
},
|
|
4050
4238
|
t('waterSnooze'),
|
|
4051
4239
|
),
|
|
@@ -4057,11 +4245,16 @@ window.__ModuleLoader__.load({
|
|
|
4057
4245
|
'button',
|
|
4058
4246
|
{
|
|
4059
4247
|
type: 'button',
|
|
4060
|
-
className: 'owc-text',
|
|
4061
|
-
disabled:
|
|
4062
|
-
onClick: () =>
|
|
4248
|
+
className: 'owc-text owc-secondary',
|
|
4249
|
+
disabled: busy || waterBusy || waterError || !waterReady,
|
|
4250
|
+
onClick: () =>
|
|
4251
|
+
waterAction(
|
|
4252
|
+
water.enabled
|
|
4253
|
+
? { type: water.paused ? 'resume' : 'pause' }
|
|
4254
|
+
: { type: 'preferences', enabled: true },
|
|
4255
|
+
),
|
|
4063
4256
|
},
|
|
4064
|
-
t(water.paused ? 'waterResume' : 'waterPause'),
|
|
4257
|
+
t(!water.enabled ? 'waterEnable' : water.paused ? 'waterResume' : 'waterPause'),
|
|
4065
4258
|
),
|
|
4066
4259
|
waterState.phase === 'quiet' &&
|
|
4067
4260
|
h(
|
|
@@ -4075,33 +4268,34 @@ window.__ModuleLoader__.load({
|
|
|
4075
4268
|
t('waterQuietEnd'),
|
|
4076
4269
|
),
|
|
4077
4270
|
),
|
|
4078
|
-
|
|
4079
|
-
'details',
|
|
4080
|
-
{ className: 'owc-detail-more' },
|
|
4081
|
-
h('summary', null, t('waterQuiet')),
|
|
4271
|
+
water.enabled &&
|
|
4082
4272
|
h(
|
|
4083
|
-
'
|
|
4084
|
-
{ className: 'owc-detail-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4273
|
+
'details',
|
|
4274
|
+
{ className: 'owc-detail-more' },
|
|
4275
|
+
h('summary', null, t('waterQuiet')),
|
|
4276
|
+
h(
|
|
4277
|
+
'div',
|
|
4278
|
+
{ className: 'owc-detail-options' },
|
|
4279
|
+
[30, 60].map((minutes) =>
|
|
4280
|
+
h(
|
|
4281
|
+
'button',
|
|
4282
|
+
{
|
|
4283
|
+
type: 'button',
|
|
4284
|
+
key: minutes,
|
|
4285
|
+
disabled: !waterCanQuiet || waterBusy,
|
|
4286
|
+
onClick: (event) => {
|
|
4287
|
+
const menu = event.currentTarget.closest('details');
|
|
4288
|
+
menu.open = false;
|
|
4289
|
+
menu.querySelector('summary')?.focus();
|
|
4290
|
+
void waterAction({ type: 'quiet', minutes });
|
|
4291
|
+
},
|
|
4097
4292
|
},
|
|
4098
|
-
|
|
4099
|
-
|
|
4293
|
+
t(minutes === 30 ? 'petQuiet30' : 'petQuiet60'),
|
|
4294
|
+
),
|
|
4100
4295
|
),
|
|
4101
4296
|
),
|
|
4297
|
+
h('p', { className: 'owc-hint' }, t('petQuietHint')),
|
|
4102
4298
|
),
|
|
4103
|
-
h('p', { className: 'owc-hint' }, t('petQuietHint')),
|
|
4104
|
-
),
|
|
4105
4299
|
waterError &&
|
|
4106
4300
|
h('p', { className: 'owc-error', role: 'alert' }, t('waterUnavailable')),
|
|
4107
4301
|
waterError &&
|
|
@@ -4115,6 +4309,115 @@ window.__ModuleLoader__.load({
|
|
|
4115
4309
|
t('waterRetry'),
|
|
4116
4310
|
),
|
|
4117
4311
|
);
|
|
4312
|
+
function openQuickMenu(event) {
|
|
4313
|
+
if (ui.pending || busy || waterBusy || features.busy) return;
|
|
4314
|
+
if (ui.menu) {
|
|
4315
|
+
closePetMenu();
|
|
4316
|
+
return;
|
|
4317
|
+
}
|
|
4318
|
+
menuTrigger.current = event.currentTarget;
|
|
4319
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
4320
|
+
dispatchUI({ type: 'menu', position: { x: rect.right, y: rect.top } });
|
|
4321
|
+
}
|
|
4322
|
+
const activeCustomTimer = () =>
|
|
4323
|
+
features.activeTimer &&
|
|
4324
|
+
h(
|
|
4325
|
+
'button',
|
|
4326
|
+
{
|
|
4327
|
+
type: 'button',
|
|
4328
|
+
className: 'owc-inline-timer',
|
|
4329
|
+
'data-active-custom-timer': true,
|
|
4330
|
+
onClick: (event) => navigateScreen('smoking', event),
|
|
4331
|
+
title: features.activeTimer.name,
|
|
4332
|
+
},
|
|
4333
|
+
iconSvg('alarm', 12),
|
|
4334
|
+
h('span', null, features.activeTimer.name),
|
|
4335
|
+
h(
|
|
4336
|
+
'strong',
|
|
4337
|
+
null,
|
|
4338
|
+
(features.activeTimer.phase === 'paused' ? 'Ⅱ ' : '') +
|
|
4339
|
+
formatDuration(Math.ceil(features.activeTimer.remaining / 1000)).replace(
|
|
4340
|
+
/^00:/,
|
|
4341
|
+
'',
|
|
4342
|
+
),
|
|
4343
|
+
),
|
|
4344
|
+
features.activeTimer.count > 1 ? ' +' + (features.activeTimer.count - 1) : null,
|
|
4345
|
+
);
|
|
4346
|
+
const quickActions = () =>
|
|
4347
|
+
h(
|
|
4348
|
+
'div',
|
|
4349
|
+
{ className: 'owc-quick-actions' },
|
|
4350
|
+
waterState.phase === 'due' &&
|
|
4351
|
+
h(
|
|
4352
|
+
'button',
|
|
4353
|
+
{
|
|
4354
|
+
type: 'button',
|
|
4355
|
+
'data-quick-drink': true,
|
|
4356
|
+
disabled: !waterCanRecord || waterBusy,
|
|
4357
|
+
onClick: recordWater,
|
|
4358
|
+
},
|
|
4359
|
+
iconSvg('water', 13),
|
|
4360
|
+
waterNotice?.kind === 'drink' ? t('waterRecorded') : t('petRecord'),
|
|
4361
|
+
),
|
|
4362
|
+
features.pendingCount > 0 &&
|
|
4363
|
+
h(
|
|
4364
|
+
'button',
|
|
4365
|
+
{
|
|
4366
|
+
type: 'button',
|
|
4367
|
+
'aria-label': t('companionRemindersTitle'),
|
|
4368
|
+
onClick: (event) => navigateScreen('reminders', event),
|
|
4369
|
+
},
|
|
4370
|
+
iconSvg('alarm', 13),
|
|
4371
|
+
String(features.pendingCount),
|
|
4372
|
+
),
|
|
4373
|
+
h(
|
|
4374
|
+
'button',
|
|
4375
|
+
{
|
|
4376
|
+
type: 'button',
|
|
4377
|
+
className: 'owc-quick-more',
|
|
4378
|
+
'data-quick-more': true,
|
|
4379
|
+
'aria-label': t('quickMore'),
|
|
4380
|
+
'aria-expanded': !!ui.menu,
|
|
4381
|
+
onClick: openQuickMenu,
|
|
4382
|
+
},
|
|
4383
|
+
'⋯',
|
|
4384
|
+
),
|
|
4385
|
+
);
|
|
4386
|
+
const contentForScreen = () => {
|
|
4387
|
+
if (ui.pending) return draftGuard();
|
|
4388
|
+
if (waterEditing) return waterSettings();
|
|
4389
|
+
if (editing) return editor();
|
|
4390
|
+
if (ui.screen === 'income')
|
|
4391
|
+
return h(
|
|
4392
|
+
React.Fragment,
|
|
4393
|
+
null,
|
|
4394
|
+
panelBody('clock'),
|
|
4395
|
+
features.render('wrap-entry'),
|
|
4396
|
+
h(
|
|
4397
|
+
'div',
|
|
4398
|
+
{ className: 'owc-extra' },
|
|
4399
|
+
h(
|
|
4400
|
+
'button',
|
|
4401
|
+
{
|
|
4402
|
+
type: 'button',
|
|
4403
|
+
className: 'owc-link-row',
|
|
4404
|
+
onClick: (event) => navigateScreen('earnings', event),
|
|
4405
|
+
disabled: !data?.configured,
|
|
4406
|
+
},
|
|
4407
|
+
t('petEarningsCard'),
|
|
4408
|
+
),
|
|
4409
|
+
),
|
|
4410
|
+
);
|
|
4411
|
+
if (ui.screen === 'smoking')
|
|
4412
|
+
return h(React.Fragment, null, smokingCountdownCard(), features.render('timers'));
|
|
4413
|
+
if (ui.screen === 'water-countdown' || ui.screen === 'home') return petHome();
|
|
4414
|
+
if (ui.screen === 'earnings') return panelBody('earnings');
|
|
4415
|
+
if (ui.screen === 'wrap') return features.render('wrap');
|
|
4416
|
+
if (ui.screen === 'preferences') return features.render('settings');
|
|
4417
|
+
if (ui.screen === 'data') return features.render('data');
|
|
4418
|
+
if (ui.screen === 'reminders') return features.render('reminders');
|
|
4419
|
+
return collapsed ? classicMini() : classicOverview();
|
|
4420
|
+
};
|
|
4118
4421
|
const contextMenu = () =>
|
|
4119
4422
|
ui.menu &&
|
|
4120
4423
|
h(
|
|
@@ -4168,11 +4471,9 @@ window.__ModuleLoader__.load({
|
|
|
4168
4471
|
[
|
|
4169
4472
|
['income', 'petCountdownCard'],
|
|
4170
4473
|
['home', 'petWaterCard'],
|
|
4171
|
-
['water-countdown', 'waterCountdown'],
|
|
4172
4474
|
['smoking', 'smokingCountdown'],
|
|
4173
|
-
['earnings', 'petEarningsCard'],
|
|
4174
4475
|
['appearance', 'petAppearance'],
|
|
4175
|
-
['
|
|
4476
|
+
['preferences', 'companionPreferencesTitle'],
|
|
4176
4477
|
].map(([screen, label]) =>
|
|
4177
4478
|
h(
|
|
4178
4479
|
'button',
|
|
@@ -4200,7 +4501,7 @@ window.__ModuleLoader__.load({
|
|
|
4200
4501
|
type: 'button',
|
|
4201
4502
|
role: 'menuitem',
|
|
4202
4503
|
tabIndex: -1,
|
|
4203
|
-
disabled: hostBusy
|
|
4504
|
+
disabled: hostBusy,
|
|
4204
4505
|
onClick: () => {
|
|
4205
4506
|
closePetMenu();
|
|
4206
4507
|
void reload(true);
|
|
@@ -4232,7 +4533,7 @@ window.__ModuleLoader__.load({
|
|
|
4232
4533
|
{
|
|
4233
4534
|
ref: box,
|
|
4234
4535
|
className: 'owc-v2 owc-pet-shell',
|
|
4235
|
-
'data-version': '1.
|
|
4536
|
+
'data-version': '1.2.2',
|
|
4236
4537
|
'data-pet-model': stageModel,
|
|
4237
4538
|
'data-status':
|
|
4238
4539
|
error || state?.error
|
|
@@ -4244,6 +4545,7 @@ window.__ModuleLoader__.load({
|
|
|
4244
4545
|
: 'loading',
|
|
4245
4546
|
'aria-label': t('companionLabel'),
|
|
4246
4547
|
style: {
|
|
4548
|
+
...featureStyle,
|
|
4247
4549
|
'--owc-alpha': String(view.opacity),
|
|
4248
4550
|
left: petGeometry.x,
|
|
4249
4551
|
top: petGeometry.y,
|
|
@@ -4267,10 +4569,11 @@ window.__ModuleLoader__.load({
|
|
|
4267
4569
|
else if (ui.pending) dispatchUI({ type: 'stay' });
|
|
4268
4570
|
else if (editing || waterEditing) navigateScreen(ui.back);
|
|
4269
4571
|
else if (petShowing) closePetPanel();
|
|
4572
|
+
else if (features.alert) features.dismissAlert();
|
|
4270
4573
|
else if (autoWaterPrompt) dismissWaterPopup();
|
|
4271
4574
|
},
|
|
4272
4575
|
},
|
|
4273
|
-
h('style', null, STYLE),
|
|
4576
|
+
h('style', null, STYLE + COMPANION_APP_STYLE),
|
|
4274
4577
|
liveFeedback(),
|
|
4275
4578
|
h(
|
|
4276
4579
|
'div',
|
|
@@ -4295,7 +4598,7 @@ window.__ModuleLoader__.load({
|
|
|
4295
4598
|
petGeometry.artworkSize,
|
|
4296
4599
|
waterNotice?.token,
|
|
4297
4600
|
stageModel,
|
|
4298
|
-
PET_SPRITES,
|
|
4601
|
+
{ ...PET_SPRITES, 'custom-image': features.customImage },
|
|
4299
4602
|
true,
|
|
4300
4603
|
),
|
|
4301
4604
|
),
|
|
@@ -4307,17 +4610,14 @@ window.__ModuleLoader__.load({
|
|
|
4307
4610
|
'aria-label': t('petCountdownGroup'),
|
|
4308
4611
|
},
|
|
4309
4612
|
h(
|
|
4310
|
-
'
|
|
4613
|
+
'button',
|
|
4311
4614
|
{
|
|
4615
|
+
type: 'button',
|
|
4616
|
+
onClick: (event) =>
|
|
4617
|
+
navigateScreen(data?.configured ? 'income' : 'schedule', event),
|
|
4312
4618
|
className: 'owc-pet-clock',
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
title:
|
|
4316
|
-
error || state?.error
|
|
4317
|
-
? t('petRetryHint')
|
|
4318
|
-
: !sessionId
|
|
4319
|
-
? t('noSession')
|
|
4320
|
-
: undefined,
|
|
4619
|
+
'aria-label': t('petCountdownCard'),
|
|
4620
|
+
title: error || state?.error ? t('petRetryHint') : undefined,
|
|
4321
4621
|
},
|
|
4322
4622
|
iconSvg('alarm', 12),
|
|
4323
4623
|
h(
|
|
@@ -4328,7 +4628,6 @@ window.__ModuleLoader__.load({
|
|
|
4328
4628
|
data?.configured &&
|
|
4329
4629
|
safeState &&
|
|
4330
4630
|
!error &&
|
|
4331
|
-
sessionId &&
|
|
4332
4631
|
!['done', 'rest'].includes(safeState.status)
|
|
4333
4632
|
? h('strong', null, duration)
|
|
4334
4633
|
: null,
|
|
@@ -4360,6 +4659,8 @@ window.__ModuleLoader__.load({
|
|
|
4360
4659
|
)),
|
|
4361
4660
|
),
|
|
4362
4661
|
),
|
|
4662
|
+
activeCustomTimer(),
|
|
4663
|
+
quickActions(),
|
|
4363
4664
|
),
|
|
4364
4665
|
),
|
|
4365
4666
|
waterPrompt &&
|
|
@@ -4414,7 +4715,10 @@ window.__ModuleLoader__.load({
|
|
|
4414
4715
|
'data-pet-screen': ui.screen || 'reminder',
|
|
4415
4716
|
'data-side': floatingPanel.side,
|
|
4416
4717
|
role: 'region',
|
|
4417
|
-
'aria-label':
|
|
4718
|
+
'aria-label':
|
|
4719
|
+
features.alert && !petShowing
|
|
4720
|
+
? features.alertTitle
|
|
4721
|
+
: t(petPageTitle[ui.screen] || 'waterTitle'),
|
|
4418
4722
|
style: {
|
|
4419
4723
|
left: floatingPanel.left,
|
|
4420
4724
|
top: floatingPanel.top,
|
|
@@ -4429,7 +4733,11 @@ window.__ModuleLoader__.load({
|
|
|
4429
4733
|
: h(
|
|
4430
4734
|
'div',
|
|
4431
4735
|
{ className: 'owc-head' },
|
|
4432
|
-
h(
|
|
4736
|
+
h(
|
|
4737
|
+
'strong',
|
|
4738
|
+
{ style: { flex: 1, fontSize: 12 } },
|
|
4739
|
+
features.alert ? features.alertTitle : t('waterTitle'),
|
|
4740
|
+
),
|
|
4433
4741
|
h(
|
|
4434
4742
|
'button',
|
|
4435
4743
|
{
|
|
@@ -4438,7 +4746,8 @@ window.__ModuleLoader__.load({
|
|
|
4438
4746
|
'aria-label': t('petDismissReminder'),
|
|
4439
4747
|
title: t('petDismissReminder'),
|
|
4440
4748
|
disabled: waterBusy,
|
|
4441
|
-
onClick:
|
|
4749
|
+
onClick: () =>
|
|
4750
|
+
features.alert ? features.dismissAlert() : dismissWaterPopup(),
|
|
4442
4751
|
},
|
|
4443
4752
|
iconSvg('close', 14),
|
|
4444
4753
|
),
|
|
@@ -4453,24 +4762,16 @@ window.__ModuleLoader__.load({
|
|
|
4453
4762
|
? h(
|
|
4454
4763
|
React.Fragment,
|
|
4455
4764
|
null,
|
|
4456
|
-
|
|
4457
|
-
? draftGuard()
|
|
4458
|
-
: waterEditing
|
|
4459
|
-
? waterSettings()
|
|
4460
|
-
: editing
|
|
4461
|
-
? editor()
|
|
4462
|
-
: petDetails
|
|
4463
|
-
? panelBody('clock')
|
|
4464
|
-
: ui.screen === 'water-countdown'
|
|
4465
|
-
? waterCountdownCard()
|
|
4466
|
-
: ui.screen === 'smoking'
|
|
4467
|
-
? smokingCountdownCard()
|
|
4468
|
-
: ui.screen === 'earnings'
|
|
4469
|
-
? panelBody('earnings')
|
|
4470
|
-
: petHome(),
|
|
4765
|
+
contentForScreen(),
|
|
4471
4766
|
notices(),
|
|
4767
|
+
features.feedback(),
|
|
4472
4768
|
)
|
|
4473
|
-
:
|
|
4769
|
+
: h(
|
|
4770
|
+
React.Fragment,
|
|
4771
|
+
null,
|
|
4772
|
+
features.alert ? features.render('alert') : waterReminder(),
|
|
4773
|
+
features.feedback(),
|
|
4774
|
+
),
|
|
4474
4775
|
),
|
|
4475
4776
|
),
|
|
4476
4777
|
),
|
|
@@ -4487,7 +4788,7 @@ window.__ModuleLoader__.load({
|
|
|
4487
4788
|
(collapsed && waterQuickOpen ? ' owc-quick' : '') +
|
|
4488
4789
|
(editing || waterEditing ? ' owc-editing' : ''),
|
|
4489
4790
|
'aria-label': t('title'),
|
|
4490
|
-
'data-version': '1.
|
|
4791
|
+
'data-version': '1.2.2',
|
|
4491
4792
|
'data-status': classicClock.phase,
|
|
4492
4793
|
style: cardStyle,
|
|
4493
4794
|
onPointerDown: dragDown,
|
|
@@ -4512,7 +4813,7 @@ window.__ModuleLoader__.load({
|
|
|
4512
4813
|
else setPreference({ mini: true });
|
|
4513
4814
|
},
|
|
4514
4815
|
},
|
|
4515
|
-
h('style', null, STYLE),
|
|
4816
|
+
h('style', null, STYLE + COMPANION_APP_STYLE),
|
|
4516
4817
|
h('div', { className: 'owc-glass', 'aria-hidden': 'true' }),
|
|
4517
4818
|
h(
|
|
4518
4819
|
'div',
|
|
@@ -4531,27 +4832,13 @@ window.__ModuleLoader__.load({
|
|
|
4531
4832
|
),
|
|
4532
4833
|
),
|
|
4533
4834
|
!collapsed && classicHeader(),
|
|
4534
|
-
|
|
4535
|
-
? draftGuard()
|
|
4536
|
-
: waterEditing
|
|
4537
|
-
? waterSettings()
|
|
4538
|
-
: editing
|
|
4539
|
-
? editor()
|
|
4540
|
-
: ui.screen === 'water-countdown'
|
|
4541
|
-
? waterCountdownCard()
|
|
4542
|
-
: ui.screen === 'smoking'
|
|
4543
|
-
? smokingCountdownCard()
|
|
4544
|
-
: ui.screen === 'home'
|
|
4545
|
-
? petHome()
|
|
4546
|
-
: ui.screen === 'earnings'
|
|
4547
|
-
? panelBody('earnings')
|
|
4548
|
-
: ui.screen === 'income'
|
|
4549
|
-
? panelBody('clock')
|
|
4550
|
-
: collapsed
|
|
4551
|
-
? classicMini()
|
|
4552
|
-
: classicOverview(),
|
|
4835
|
+
contentForScreen(),
|
|
4553
4836
|
notices(ui.screen !== null),
|
|
4554
|
-
|
|
4837
|
+
features.feedback(),
|
|
4838
|
+
ui.screen === null && (features.alert ? features.render('alert') : waterReminder()),
|
|
4839
|
+
ui.screen === null && activeCustomTimer(),
|
|
4840
|
+
ui.screen === null && quickActions(),
|
|
4841
|
+
contextMenu(),
|
|
4555
4842
|
),
|
|
4556
4843
|
);
|
|
4557
4844
|
}
|