Skip to content

Commit

Permalink
feat(annotation): export reader annotations list to the readium annot…
Browse files Browse the repository at this point in the history
…ations json format (PR #2551)
  • Loading branch information
panaC committed Sep 18, 2024
1 parent 3f572ce commit f7b410e
Show file tree
Hide file tree
Showing 38 changed files with 175 additions and 274 deletions.
29 changes: 0 additions & 29 deletions src/common/redux/actions/annotation/exportW3CAnnotationSet.ts

This file was deleted.

12 changes: 0 additions & 12 deletions src/common/redux/actions/annotation/index.ts

This file was deleted.

2 changes: 0 additions & 2 deletions src/common/redux/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import * as publicationActions from "./publication";
import * as themeActions from "./theme";
import * as wizardActions from "./wizard";
import * as versionUpdateActions from "./version-update";
import * as annotationActions from "./annotation";

export {
historyActions,
Expand All @@ -46,5 +45,4 @@ export {
themeActions,
wizardActions,
versionUpdateActions,
annotationActions,
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ export interface IW3CAnnotationModel {
body: {
type: string;
value: string;
format: string;
color: string;
tag?: string;
highlight?: "solid" | "underline" | "strikethrough" | "outline";
format?: string;
color?: string;
textDirection?: string;
language?: string;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// that can be found in the LICENSE file exposed on Github (readium) in the project repository.
// ==LICENSE-END==

import { IW3CAnnotationModel, IW3CAnnotationModelSet, IW3CAnnotationSetAboutView } from "./annotationModel.type";
import { IW3CAnnotationModel, IW3CAnnotationModelSet } from "./annotationModel.type";
import { v4 as uuidv4 } from "uuid";
import { _APP_NAME, _APP_VERSION } from "readium-desktop/preprocessor-directives";
import { PublicationView } from "readium-desktop/common/views/publication";
Expand All @@ -16,11 +16,13 @@ export function convertAnnotationToW3CAnnotationModel(annotation: IAnnotationSta

const currentDate = new Date();
const dateString: string = currentDate.toISOString();
const { uuid, color, locatorExtended: def } = annotation;
const { uuid, color, locatorExtended: def, tags, drawType } = annotation;
const { selectionInfo, locator, headings, epubPage } = def;
const { cleanText, rawText, rawBefore, rawAfter } = selectionInfo;
const { href } = locator;

const highlight: IW3CAnnotationModel["body"]["highlight"] = drawType === "solid_background" ? "solid" : drawType;

return {
"@context": "http://www.w3.org/ns/anno.jsonld",
id: uuid ? "urn:uuid:" + uuid : "",
Expand All @@ -33,6 +35,8 @@ export function convertAnnotationToW3CAnnotationModel(annotation: IAnnotationSta
value: cleanText || "",
format: "text/plain",
color: rgbToHex(color),
tag: (tags || [])[0] || "",
highlight,
// textDirection: "ltr",
// language: "fr",
},
Expand Down Expand Up @@ -72,11 +76,8 @@ export function convertAnnotationToW3CAnnotationModel(annotation: IAnnotationSta
};
}

export function convertAnnotationListToW3CAnnotationModelSet(annotationArray: IAnnotationState[],
publicationMetadata: IW3CAnnotationSetAboutView,
): IW3CAnnotationModelSet {
export function convertAnnotationListToW3CAnnotationSet(annotationArray: IAnnotationState[], publicationView: PublicationView): IW3CAnnotationModelSet {

const { identiferArrayString, mimeType, title, publisher, creator, publishedAt, source } = publicationMetadata;
const currentDate = new Date();
const dateString: string = currentDate.toISOString();

Expand All @@ -93,28 +94,15 @@ export function convertAnnotationListToW3CAnnotationModelSet(annotationArray: IA
generated: dateString,
label: "Annotations set",
about: {
"dc:identifier": identiferArrayString || [],
"dc:format": mimeType || "",
"dc:title": title || "",
"dc:publisher": publisher || [],
"dc:creator": creator || [],
"dc:date": publishedAt || "",
"dc:source": source || "",
"dc:identifier": [publicationView.workIdentifier ? ((publicationView.workIdentifier.startsWith("urn:") ? "" : "urn:isbn:") + publicationView.workIdentifier) : ""],
"dc:format": "application/epub+zip",
"dc:title": publicationView.documentTitle || "",
"dc:publisher": publicationView.publishers || [],
"dc:creator": publicationView.authors || [],
"dc:date": publicationView.publishedAt || "",
"dc:source": "urn:uuid:" + publicationView.identifier,
},
total: annotationArray.length,
items: (annotationArray || []).map((v) => convertAnnotationToW3CAnnotationModel(v)),
};
}

export function convertPublicationToAnnotationStateAbout(publicationView: PublicationView, publicationIdentifier: string): IW3CAnnotationSetAboutView {

return {
identiferArrayString: ["urn:isbn:" + publicationView.workIdentifier || ""],
mimeType: "application/epub+zip",
title: publicationView.documentTitle || "",
publisher: publicationView.publishers || [],
creator: publicationView.authors || [],
publishedAt: publicationView.publishedAt || "",
source: "urn:uuid:" + publicationIdentifier,
};
}
88 changes: 0 additions & 88 deletions src/main/redux/sagas/annotation.ts

This file was deleted.

4 changes: 0 additions & 4 deletions src/main/redux/sagas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import * as win from "./win";
import * as telemetry from "./telemetry";
import * as lcp from "./lcp";
import * as catalog from "./catalog";
import * as annotation from "./annotation";

import { IS_DEV } from "readium-desktop/preprocessor-directives";
// Logger
Expand Down Expand Up @@ -125,9 +124,6 @@ export function* rootSaga() {
// need to track the previous state version before update in initSuccess.build
yield call(telemetry.collectSaveAndSend);

// export annotations
yield annotation.saga();

// app initialized
yield put(appActions.initSuccess.build());

Expand Down
25 changes: 0 additions & 25 deletions src/main/w3c/annotation/fs.ts

This file was deleted.

11 changes: 1 addition & 10 deletions src/renderer/library/components/publication/menu/CatalogMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ import SVG from "readium-desktop/renderer/common/components/SVG";
import * as InfoIcon from "readium-desktop/renderer/assets/icons/info-icon.svg";
import * as TrashIcon from "readium-desktop/renderer/assets/icons/trash-icon.svg";
import * as DoubleCheckIcon from "readium-desktop/renderer/assets/icons/doubleCheck-icon.svg";
import { annotationActions, publicationActions } from "readium-desktop/common/redux/actions";
import { publicationActions } from "readium-desktop/common/redux/actions";
import { useDispatch } from "readium-desktop/renderer/common/hooks/useDispatch";
import { apiDispatch } from "readium-desktop/renderer/common/redux/api/api";
import * as SaveIcon from "readium-desktop/renderer/assets/icons/SaveAs-icon.svg";

const CatalogMenu: React.FC<{publicationView: PublicationView}> = (props) => {
const [__] = useTranslator();
Expand Down Expand Up @@ -72,14 +71,6 @@ const CatalogMenu: React.FC<{publicationView: PublicationView}> = (props) => {
<PublicationExportButton
publicationView={props.publicationView}
/>
<div style={{ borderBottom: "1px solid var(--color-blue)" }}></div>
<button
className="R2_CSS_CLASS__FORCE_NO_FOCUS_OUTLINE"
onClick={() => dispatch(annotationActions.exportW3CAnnotationSetFromAnnotations.build(props.publicationView.identifier))}
>
<SVG ariaHidden svg={SaveIcon} />
<p>{__("catalog.exportAnnotation")}</p>
</button>
</>
);
};
Expand Down
2 changes: 0 additions & 2 deletions src/renderer/library/redux/middleware/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import {
apiActions, authActions, catalogActions, downloadActions, i18nActions, keyboardActions, lcpActions, readerActions, sessionActions, themeActions, publicationActions, wizardActions,
annotationActions,
} from "readium-desktop/common/redux/actions";
import { syncFactory } from "readium-desktop/renderer/common/redux/middleware/syncFactory";

Expand Down Expand Up @@ -56,7 +55,6 @@ const SYNCHRONIZABLE_ACTIONS: string[] = [

sessionActions.save.ID,

annotationActions.exportW3CAnnotationSetFromAnnotations.ID,
];

export const reduxSyncMiddleware = syncFactory(SYNCHRONIZABLE_ACTIONS);
28 changes: 27 additions & 1 deletion src/renderer/reader/components/ReaderMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ import { Locator } from "r2-shared-js/dist/es8-es2017/src/models/locator";
import { TextArea } from "react-aria-components";
import { AnnotationEdit } from "./AnnotationEdit";
import { IAnnotationState, IColor, TAnnotationState, TDrawType } from "readium-desktop/common/redux/states/renderer/annotation";
import { readerActions } from "readium-desktop/common/redux/actions";
import { readerActions, toastActions } from "readium-desktop/common/redux/actions";
import { readerLocalActionLocatorHrefChanged, readerLocalActionSetConfig } from "../redux/actions";
import * as stylesGlobal from "readium-desktop/renderer/assets/styles/global.scss";
import * as CheckIcon from "readium-desktop/renderer/assets/icons/singlecheck-icon.svg";
Expand All @@ -90,6 +90,8 @@ import { ObjectKeys } from "readium-desktop/utils/object-keys-values";

import type { Selection } from "react-aria-components";
import { rgbToHex } from "readium-desktop/common/rgb";
import { ToastType } from "readium-desktop/common/models/toast";
import { convertAnnotationListToW3CAnnotationSet } from "readium-desktop/common/w3c/annotation/converter";



Expand Down Expand Up @@ -650,6 +652,7 @@ const AnnotationList: React.FC<{ annotationUUIDFocused: string, resetAnnotationU

const [__] = useTranslator();
const annotationsQueue = useSelector((state: IReaderRootState) => state.reader.annotation);
const publicationView = useSelector((state: IReaderRootState) => state.reader.info.publicationView);

const [tagArrayFilter, setTagArrayFilter] = React.useState<Selection>(new Set([]));
const [colorArrayFilter, setColorArrayFilter] = React.useState<Selection>(new Set([]));
Expand Down Expand Up @@ -814,6 +817,29 @@ const AnnotationList: React.FC<{ annotationUUIDFocused: string, resetAnnotationU
</AlertDialog.Content>
</AlertDialog.Portal>
</AlertDialog.Root>
<button className={stylesAnnotations.annotations_filter_trigger_button} disabled={!annotationList.length}
onClick={async () => {

try {
const fileHandle = await (window as any).showSaveFilePicker({ excludeAcceptAllOption: true, id: publicationView.identifier.slice(0, 32), suggestedName: "myAnnotationSet.annotation", types: [{ description: ".annotation", accept: { "application/rd-annotations+json": [".annotation"] } }] });
const writable = await fileHandle.createWritable();

const annotations = annotationList.map(([, anno]) => anno);
const contents = convertAnnotationListToW3CAnnotationSet(annotations, publicationView);
const jsonData = JSON.stringify(contents, null, 2);
await writable.write(jsonData);
await writable.close();

dispatch(toastActions.openRequest.build(ToastType.Success, __("catalog.exportAnnotationSuccess", {fileName: fileHandle.name})));

} catch (e) {
dispatch(toastActions.openRequest.build(ToastType.Error, __("catalog.exportAnnotationFailure", { errorTxt: e?.toString() })));
}

}}
title={__("catalog.exportAnnotation")}>
<SVG svg={SaveIcon} />
</button>
<Popover.Root>
<Popover.Trigger asChild>
<button aria-label="Menu" className={stylesAnnotations.annotations_filter_trigger_button}
Expand Down
2 changes: 2 additions & 0 deletions src/resources/locales/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@
},
"export": "حفظ بإسم",
"exportAnnotation": "",
"exportAnnotationFailure": "",
"exportAnnotationSuccess": "",
"format": "التنسيق",
"lang": "اللغة",
"lastRead": "آخر منشور مقروء",
Expand Down
Loading

0 comments on commit f7b410e

Please sign in to comment.