diff --git a/docs/releases/v1.1.18/PLAY_STORE_METADATA.md b/docs/releases/v1.1.18/PLAY_STORE_METADATA.md index b1cb839..b0ea05f 100644 --- a/docs/releases/v1.1.18/PLAY_STORE_METADATA.md +++ b/docs/releases/v1.1.18/PLAY_STORE_METADATA.md @@ -39,5 +39,17 @@ task lines, theme colors); no note bodies and nothing off the device. within seconds; `npm test` 50/50; `npm run typecheck` clean at the pin; `testDebugUnitTest`, `lintDebug` and `assembleDebug` pass. Not verified on a device or below API 31. -- Matching ports: iOS ZenNotes/zennotesios `release/1.9.9` (build 20); +- Comment sidecar fix (2026-09-09, after the merge): between the 1.1.16 + pin and a3e638fc, desktop `vault.ts` dropped its private comment + normalizer for the shared `@shared/note-comments`, which keeps the 2.46 + `author` and `parentId` fields. `MobileVault.writeNoteComments` still + rebuilt each record from a fixed field list, and app-core hands over the + whole list on every comment action, so one reply, resolve, or delete on + the phone would have flattened every thread and dropped every name the + desktop or an assistant wrote. `src/bridge/vault-fs.ts` now reads and + writes the sidecar through the shared normalizer, as desktop does. + Verified by `npm run typecheck`, `npm run build`, and `npm test`; + `MobileVault` cannot run under `node --test` (path aliases), and the + fix was not re-run on the AVD. Same fix as iPhone 1.9.8. +- Matching ports: iOS ZenNotes/zennotesios `release/1.9.8` (build 19); desktop ZenNotes/zennotes 2.46.0. diff --git a/docs/releases/v1.1.18/RELEASE_NOTES.md b/docs/releases/v1.1.18/RELEASE_NOTES.md index c04a777..4088b4e 100644 --- a/docs/releases/v1.1.18/RELEASE_NOTES.md +++ b/docs/releases/v1.1.18/RELEASE_NOTES.md @@ -1,6 +1,6 @@ # ZenNotes for Android 1.1.18: widgets -Home Screen widgets, in step with iPhone 1.9.9. Three of them, zero +Home Screen widgets, in step with iPhone 1.9.8. Three of them, zero configuration, wearing whatever theme the app wears. ## What changes on the phone @@ -44,4 +44,4 @@ configuration, wearing whatever theme the app wears. No new permissions, services, or data collection. On-device and folder vaults continue to work without an account; self-hosted and ZenNotes Cloud vaults remain optional. The same widgets ship on iPhone and iPad as -ZenNotes 1.9.9. +ZenNotes 1.9.8. diff --git a/src/bridge/vault-fs.ts b/src/bridge/vault-fs.ts index f12366c..3c028ff 100644 --- a/src/bridge/vault-fs.ts +++ b/src/bridge/vault-fs.ts @@ -25,6 +25,7 @@ import type { CustomTemplateFile, WriteTemplateInput } from '@bridge-contract/te import type { VaultTask } from '@shared/tasks' import { parseTaskFile, parseTasksFromBody } from '@shared/tasks' import { normalizeHarperVaultState } from '@shared/harper-settings' +import { normalizeNoteComments } from '@shared/note-comments' import { isFormDirName, isDatabaseInternalPath } from '@shared/databases' import { emptyExcalidrawDocument } from '@shared/excalidraw' import { DEMO_TOUR_ASSETS, DEMO_TOUR_NOTES } from '@desktop-main/demo-tour-data' @@ -937,14 +938,11 @@ export class MobileVault { } async readNoteComments(relPath: string): Promise { - const raw = await this.fs.readTextOrNull(this.commentsPathFor(resolveSafeRel(relPath))) + const rel = resolveSafeRel(relPath) + const raw = await this.fs.readTextOrNull(this.commentsPathFor(rel)) if (!raw) return [] try { - const parsed = JSON.parse(raw) as { comments?: NoteComment[] } | NoteComment[] - const list = Array.isArray(parsed) ? parsed : (parsed.comments ?? []) - return list - .filter((c) => c && typeof c === 'object') - .sort((a, b) => a.createdAt - b.createdAt || a.id.localeCompare(b.id)) + return normalizeNoteComments(JSON.parse(raw), rel) } catch { return [] } @@ -961,18 +959,11 @@ export class MobileVault { async writeNoteComments(relPath: string, inputs: NoteCommentInput[]): Promise { const rel = resolveSafeRel(relPath) - const now = Date.now() - const comments: NoteComment[] = inputs.map((input) => ({ - id: input.id ?? uuid(), - notePath: rel, - anchorStart: Math.max(0, Math.min(input.anchorStart, input.anchorEnd)), - anchorEnd: Math.max(0, Math.max(input.anchorStart, input.anchorEnd)), - anchorText: (input.anchorText ?? '').slice(0, 500), - body: input.body ?? '', - createdAt: input.createdAt ?? now, - updatedAt: input.updatedAt ?? now, - resolvedAt: input.resolvedAt ?? null - })) + // Desktop's own normalizer (shared since app core 2.46). App-core always + // hands over the whole list, so the writer must keep the optional `author` + // and `parentId` a desktop or an assistant wrote, or one comment action on + // the phone flattens every thread and drops every name in the sidecar. + const comments = normalizeNoteComments(inputs, rel) await this.writeCommentsFile(rel, comments) emitVaultChange({ kind: 'change',