diff --git a/README.md b/README.md
index f883d8f0..f06a0a57 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,15 @@ Andrew Ng
## Sneak Peek
-
+
+
+
+## Advanced AI functionalities
+
+[makesense.ai][1] strives to significantly reduce the time we have to spend on labeling photos. To achieve this, we are going to use many different AI models that will be able to give you recommendations as well as automate repetitive and tedious activities. The first step on this journey is to use a [SSD model][8] pretrained on the [COCO dataset][9], which will do some of the work for you in drawing bboxes on photos and - in future versions of the application - will also suggest a label. We also plan to add, among other things, models that classify photos, detect characteristic features of faces, whole faces, and also human pose. The engine that drives our AI functionalities is [TensorFlow.js][10] - JS version of the most popular framework for training neural networks. This choice allows us not only to speed up your work but also to care about the privacy of your data, because unlike with other commercial and open source tools, your photos do not have to be transferred to the server. This time AI comes to your device!
+
+
{selectRoute()}
@@ -43,8 +45,9 @@ const App: React.FC = ({projectType, windowSize}) => {
};
const mapStateToProps = (state: AppState) => ({
- projectType: state.editor.projectType,
- windowSize: state.general.windowSize
+ projectType: state.general.projectData.type,
+ windowSize: state.general.windowSize,
+ AIMode: state.ai.isObjectDetectorLoaded
});
export default connect(
diff --git a/src/__test__/custom-test-env.js b/src/__test__/custom-test-env.js
new file mode 100644
index 00000000..771878f8
--- /dev/null
+++ b/src/__test__/custom-test-env.js
@@ -0,0 +1,12 @@
+const Environment = require('jest-environment-jsdom');
+
+/**
+ * A custom environment to set the TextEncoder that is required by TensorFlow.js.
+ */
+module.exports = class CustomTestEnvironment extends Environment {
+ async setup() {
+ await super.setup();
+ const { TextEncoder } = require('util');
+ this.global.TextEncoder = TextEncoder;
+ }
+}
\ No newline at end of file
diff --git a/src/ai/ObjectDetector.ts b/src/ai/ObjectDetector.ts
new file mode 100644
index 00000000..2a16c483
--- /dev/null
+++ b/src/ai/ObjectDetector.ts
@@ -0,0 +1,39 @@
+import * as cocoSsd from '@tensorflow-models/coco-ssd';
+import {ObjectDetection} from "@tensorflow-models/coco-ssd";
+import {DetectedObject} from "@tensorflow-models/coco-ssd";
+import {store} from "../index";
+import {updateObjectDetectorStatus} from "../store/ai/actionCreators";
+import {AIActions} from "../logic/actions/AIActions";
+
+export class ObjectDetector {
+ private static model: ObjectDetection;
+
+ public static loadModel(callback?: () => any) {
+ cocoSsd
+ .load()
+ .then((model: ObjectDetection) => {
+ ObjectDetector.model = model;
+ store.dispatch(updateObjectDetectorStatus(true));
+ AIActions.detectRectsForActiveImage();
+ callback && callback();
+ })
+ .catch((error) => {
+ // TODO
+ throw new Error(error);
+ })
+ }
+
+ public static predict(image: HTMLImageElement, callback?: (predictions: DetectedObject[]) => any) {
+ if (!ObjectDetector.model) return;
+
+ ObjectDetector.model
+ .detect(image)
+ .then((predictions: DetectedObject[]) => {
+ callback && callback(predictions)
+ })
+ .catch((error) => {
+ // TODO
+ throw new Error(error);
+ })
+ }
+}
\ No newline at end of file
diff --git a/src/data/enums/LabelStatus.ts b/src/data/enums/LabelStatus.ts
new file mode 100644
index 00000000..de06ee29
--- /dev/null
+++ b/src/data/enums/LabelStatus.ts
@@ -0,0 +1,5 @@
+export enum LabelStatus {
+ ACCEPTED = "ACCEPTED",
+ REJECTED = "REJECTED",
+ UNDECIDED = "UNDECIDED"
+}
\ No newline at end of file
diff --git a/src/data/enums/PopupWindowType.ts b/src/data/enums/PopupWindowType.ts
index 2265b875..af9c8822 100644
--- a/src/data/enums/PopupWindowType.ts
+++ b/src/data/enums/PopupWindowType.ts
@@ -1,6 +1,7 @@
export enum PopupWindowType {
LOAD_LABEL_NAMES = "LOAD_LABEL_NAMES",
LOAD_IMAGES = "LOAD_IMAGES",
+ LOAD_AI_MODEL = "LOAD_AI_MODEL",
EXPORT_LABELS = "EXPORT_LABELS",
INSERT_LABEL_NAMES = 'INSERT_LABEL_NAMES',
EXIT_PROJECT = 'EXIT_PROJECT'
diff --git a/src/data/info/EditorFeatureData.ts b/src/data/info/EditorFeatureData.ts
index d840c388..9894ab88 100644
--- a/src/data/info/EditorFeatureData.ts
+++ b/src/data/info/EditorFeatureData.ts
@@ -31,8 +31,8 @@ export const EditorFeatureData: IEditorFeature[] = [
imageAlt: "file",
},
{
- displayText: "Support basic image operations like crop and resize",
- imageSrc: "img/crop.png",
- imageAlt: "crop",
+ displayText: "Use AI to make your work more productive",
+ imageSrc: "img/robot.png",
+ imageAlt: "robot",
},
];
\ No newline at end of file
diff --git a/src/logic/actions/AIActions.ts b/src/logic/actions/AIActions.ts
new file mode 100644
index 00000000..f72ceea4
--- /dev/null
+++ b/src/logic/actions/AIActions.ts
@@ -0,0 +1,53 @@
+import {DetectedObject} from "@tensorflow-models/coco-ssd";
+import {ImageData, LabelRect} from "../../store/labels/types";
+import {LabelsSelector} from "../../store/selectors/LabelsSelector";
+import uuidv1 from 'uuid/v1';
+import {store} from "../../index";
+import {updateImageDataById} from "../../store/labels/actionCreators";
+import {ObjectDetector} from "../../ai/ObjectDetector";
+import {ImageRepository} from "../imageRepository/ImageRepository";
+import {LabelStatus} from "../../data/enums/LabelStatus";
+
+export class AIActions {
+ public static detectRectsForActiveImage(): void {
+ const activeImageData: ImageData = LabelsSelector.getActiveImageData();
+ AIActions.detectRects(activeImageData.id, ImageRepository.getById(activeImageData.id))
+ }
+
+ public static detectRects(imageId: string, image: HTMLImageElement): void {
+ if (LabelsSelector.getImageDataById(imageId).isVisitedByObjectDetector)
+ return;
+
+ ObjectDetector.predict(image, (predictions: DetectedObject[]) => {
+ AIActions.savePredictions(imageId, predictions);
+ })
+ }
+
+ public static savePredictions(imageId: string, predictions: DetectedObject[]) {
+ const imageData: ImageData = LabelsSelector.getImageDataById(imageId);
+ const predictedLabels: LabelRect[] = AIActions.mapPredictionsToRectLabels(predictions);
+ const nextImageData: ImageData = {
+ ...imageData,
+ labelRects: imageData.labelRects.concat(predictedLabels),
+ isVisitedByObjectDetector: true
+ };
+ store.dispatch(updateImageDataById(imageData.id, nextImageData));
+ }
+
+ public static mapPredictionsToRectLabels(predictions: DetectedObject[]): LabelRect[] {
+ return predictions.map((prediction: DetectedObject) => {
+ return {
+ id: uuidv1(),
+ labelIndex: null,
+ rect: {
+ x: prediction.bbox[0],
+ y: prediction.bbox[1],
+ width: prediction.bbox[2],
+ height: prediction.bbox[3],
+ },
+ isCreatedByAI: true,
+ status: LabelStatus.UNDECIDED
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/src/logic/actions/EditorActions.ts b/src/logic/actions/EditorActions.ts
index 681ef438..bbcff600 100644
--- a/src/logic/actions/EditorActions.ts
+++ b/src/logic/actions/EditorActions.ts
@@ -88,7 +88,7 @@ export class EditorActions {
viewPortContentSize: CanvasUtil.getSize(EditorModel.canvas),
activeKeyCombo: ContextManager.getActiveCombo(),
event: event,
- zoom: EditorModel.zoom,
+ zoom: GeneralSelector.getZoom(),
viewPortSize: EditorModel.viewPortSize,
defaultRenderImageRect: EditorModel.defaultRenderImageRect,
viewPortContentImageRect: ViewPortActions.calculateViewPortContentImageRect(),
diff --git a/src/logic/actions/ImageActions.ts b/src/logic/actions/ImageActions.ts
index 9e883866..55b1abc4 100644
--- a/src/logic/actions/ImageActions.ts
+++ b/src/logic/actions/ImageActions.ts
@@ -1,24 +1,24 @@
-import {EditorSelector} from "../../store/selectors/EditorSelector";
+import {LabelsSelector} from "../../store/selectors/LabelsSelector";
import {store} from "../../index";
-import {updateActiveImageIndex, updateActiveLabelId} from "../../store/editor/actionCreators";
+import {updateActiveImageIndex, updateActiveLabelId} from "../../store/labels/actionCreators";
import {ViewPortActions} from "./ViewPortActions";
import {EditorModel} from "../../staticModels/EditorModel";
export class ImageActions {
public static getPreviousImage(): void {
- const currentImageIndex: number = EditorSelector.getActiveImageIndex();
+ const currentImageIndex: number = LabelsSelector.getActiveImageIndex();
ImageActions.getImageByIndex(currentImageIndex - 1);
}
public static getNextImage(): void {
- const currentImageIndex: number = EditorSelector.getActiveImageIndex();
+ const currentImageIndex: number = LabelsSelector.getActiveImageIndex();
ImageActions.getImageByIndex(currentImageIndex + 1);
}
public static getImageByIndex(index: number): void {
if (EditorModel.viewPortActionsDisabled) return;
- const imageCount: number = EditorSelector.getImagesData().length;
+ const imageCount: number = LabelsSelector.getImagesData().length;
if (index < 0 || index > imageCount - 1) {
return;
diff --git a/src/logic/actions/LabelActions.ts b/src/logic/actions/LabelActions.ts
index 86600dc8..bd9122bf 100644
--- a/src/logic/actions/LabelActions.ts
+++ b/src/logic/actions/LabelActions.ts
@@ -1,19 +1,19 @@
-import {EditorSelector} from "../../store/selectors/EditorSelector";
-import {ImageData, LabelPoint, LabelPolygon, LabelRect} from "../../store/editor/types";
+import {LabelsSelector} from "../../store/selectors/LabelsSelector";
+import {ImageData, LabelPoint, LabelPolygon, LabelRect} from "../../store/labels/types";
import * as _ from "lodash";
import {store} from "../../index";
-import {updateImageDataById} from "../../store/editor/actionCreators";
+import {updateImageDataById} from "../../store/labels/actionCreators";
import {LabelType} from "../../data/enums/LabelType";
export class LabelActions {
public static deleteActiveLabel() {
- const activeImageData: ImageData = EditorSelector.getActiveImageData();
- const activeLabelId: string = EditorSelector.getActiveLabelId();
+ const activeImageData: ImageData = LabelsSelector.getActiveImageData();
+ const activeLabelId: string = LabelsSelector.getActiveLabelId();
LabelActions.deleteImageLabelById(activeImageData.id, activeLabelId);
}
public static deleteImageLabelById(imageId: string, labelId: string) {
- switch (EditorSelector.getActiveLabelType()) {
+ switch (LabelsSelector.getActiveLabelType()) {
case LabelType.POINT:
LabelActions.deletePointLabelById(imageId, labelId);
break;
@@ -27,7 +27,7 @@ export class LabelActions {
}
public static deleteRectLabelById(imageId: string, labelRectId: string) {
- const imageData: ImageData = EditorSelector.getImageDataById(imageId);
+ const imageData: ImageData = LabelsSelector.getImageDataById(imageId);
const newImageData = {
...imageData,
labelRects: _.filter(imageData.labelRects, (currentLabel: LabelRect) => {
@@ -38,7 +38,7 @@ export class LabelActions {
}
public static deletePointLabelById(imageId: string, labelPointId: string) {
- const imageData: ImageData = EditorSelector.getImageDataById(imageId);
+ const imageData: ImageData = LabelsSelector.getImageDataById(imageId);
const newImageData = {
...imageData,
labelPoints: _.filter(imageData.labelPoints, (currentLabel: LabelPoint) => {
@@ -49,7 +49,7 @@ export class LabelActions {
}
public static deletePolygonLabelById(imageId: string, labelPolygonId: string) {
- const imageData: ImageData = EditorSelector.getImageDataById(imageId);
+ const imageData: ImageData = LabelsSelector.getImageDataById(imageId);
const newImageData = {
...imageData,
labelPolygons: _.filter(imageData.labelPolygons, (currentLabel: LabelPolygon) => {
diff --git a/src/logic/actions/ViewPortActions.ts b/src/logic/actions/ViewPortActions.ts
index 89c2c341..8ed67a9f 100644
--- a/src/logic/actions/ViewPortActions.ts
+++ b/src/logic/actions/ViewPortActions.ts
@@ -11,6 +11,9 @@ import {SizeUtil} from "../../utils/SizeUtil";
import {EditorActions} from "./EditorActions";
import {Direction} from "../../data/enums/Direction";
import {DirectionUtil} from "../../utils/DirectionUtil";
+import {GeneralSelector} from "../../store/selectors/GeneralSelector";
+import {store} from "../../index";
+import {updateZoom} from "../../store/general/actionCreators";
export class ViewPortActions {
public static updateViewPortSize() {
@@ -35,7 +38,7 @@ export class ViewPortActions {
public static calculateViewPortContentSize(): ISize {
if (!!EditorModel.viewPortSize && !!EditorModel.image) {
const defaultViewPortImageRect: IRect = EditorModel.defaultRenderImageRect;
- const scaledImageSize: ISize = SizeUtil.scale(EditorModel.defaultRenderImageRect, EditorModel.zoom);
+ const scaledImageSize: ISize = SizeUtil.scale(EditorModel.defaultRenderImageRect, GeneralSelector.getZoom());
return {
width: scaledImageSize.width + 2 * defaultViewPortImageRect.x,
height: scaledImageSize.height + 2 * defaultViewPortImageRect.y
@@ -123,7 +126,7 @@ export class ViewPortActions {
public static zoomIn() {
if (EditorModel.viewPortActionsDisabled) return;
- const currentZoom: number = EditorModel.zoom;
+ const currentZoom: number = GeneralSelector.getZoom();
const currentRelativeScrollPosition: IPoint = ViewPortActions.getRelativeScrollPosition();
const nextRelativeScrollPosition = currentZoom === 1 ? {x: 0.5, y: 0.5} : currentRelativeScrollPosition;
ViewPortActions.setZoom(currentZoom + ViewPointSettings.ZOOM_STEP);
@@ -135,7 +138,7 @@ export class ViewPortActions {
public static zoomOut() {
if (EditorModel.viewPortActionsDisabled) return;
- const currentZoom: number = EditorModel.zoom;
+ const currentZoom: number = GeneralSelector.getZoom();
const currentRelativeScrollPosition: IPoint = ViewPortActions.getRelativeScrollPosition();
ViewPortActions.setZoom(currentZoom - ViewPointSettings.ZOOM_STEP);
ViewPortActions.resizeViewPortContent();
@@ -152,7 +155,7 @@ export class ViewPortActions {
}
public static setOneForOneZoom() {
- const currentZoom: number = EditorModel.zoom;
+ const currentZoom: number = GeneralSelector.getZoom();
const currentRelativeScrollPosition: IPoint = ViewPortActions.getRelativeScrollPosition();
const nextRelativeScrollPosition = currentZoom === 1 ? {x: 0.5, y: 0.5} : currentRelativeScrollPosition;
const nextZoom: number = EditorModel.image.width / EditorModel.defaultRenderImageRect.width
@@ -163,12 +166,12 @@ export class ViewPortActions {
}
public static setZoom(value: number) {
- const currentZoom: number = EditorModel.zoom;
+ const currentZoom: number = GeneralSelector.getZoom();
const isNewValueValid: boolean = NumberUtil.isValueInRange(
value, ViewPointSettings.MIN_ZOOM, ViewPointSettings.MAX_ZOOM);
if (isNewValueValid && value !== currentZoom) {
- EditorModel.zoom = value;
+ store.dispatch(updateZoom(value));
}
}
}
\ No newline at end of file
diff --git a/src/logic/export/PointLabelsExport.ts b/src/logic/export/PointLabelsExport.ts
index 4acd4782..a5feaa37 100644
--- a/src/logic/export/PointLabelsExport.ts
+++ b/src/logic/export/PointLabelsExport.ts
@@ -1,8 +1,8 @@
import {ExportFormatType} from "../../data/enums/ExportFormatType";
-import {ImageData, LabelPoint} from "../../store/editor/types";
+import {ImageData, LabelPoint} from "../../store/labels/types";
import {saveAs} from "file-saver";
import {ImageRepository} from "../imageRepository/ImageRepository";
-import {EditorSelector} from "../../store/selectors/EditorSelector";
+import {LabelsSelector} from "../../store/selectors/LabelsSelector";
import {ExporterUtil} from "../../utils/ExporterUtil";
export class PointLabelsExporter {
@@ -17,7 +17,7 @@ export class PointLabelsExporter {
}
private static exportAsCSV(): void {
- const content: string = EditorSelector.getImagesData()
+ const content: string = LabelsSelector.getImagesData()
.map((imageData: ImageData) => {
return PointLabelsExporter.wrapRectLabelsIntoCSV(imageData)})
.filter((imageLabelData: string) => {
@@ -38,7 +38,7 @@ export class PointLabelsExporter {
return null;
const image: HTMLImageElement = ImageRepository.getById(imageData.id);
- const labelNamesList: string[] = EditorSelector.getLabelNames();
+ const labelNamesList: string[] = LabelsSelector.getLabelNames();
const labelRectsString: string[] = imageData.labelPoints.map((labelPoint: LabelPoint) => {
const labelFields = [
labelNamesList[labelPoint.labelIndex],
diff --git a/src/logic/export/PolygonLabelsExporter.ts b/src/logic/export/PolygonLabelsExporter.ts
index 23e0afe1..a38d66cd 100644
--- a/src/logic/export/PolygonLabelsExporter.ts
+++ b/src/logic/export/PolygonLabelsExporter.ts
@@ -1,8 +1,8 @@
import {ExportFormatType} from "../../data/enums/ExportFormatType";
import {IPoint} from "../../interfaces/IPoint";
import {VGGFileData, VGGObject, VGGPolygon, VGGRegionsData} from "../../data/VGG/IVGG";
-import {ImageData, LabelPolygon} from "../../store/editor/types";
-import {EditorSelector} from "../../store/selectors/EditorSelector";
+import {ImageData, LabelPolygon} from "../../store/labels/types";
+import {LabelsSelector} from "../../store/selectors/LabelsSelector";
import {saveAs} from "file-saver";
import {ExporterUtil} from "../../utils/ExporterUtil";
@@ -18,8 +18,8 @@ export class PolygonLabelsExporter {
}
private static exportAsVGGJson(): void {
- const imagesData: ImageData[] = EditorSelector.getImagesData();
- const labelNames: string[] = EditorSelector.getLabelNames();
+ const imagesData: ImageData[] = LabelsSelector.getImagesData();
+ const labelNames: string[] = LabelsSelector.getLabelNames();
const content: string = JSON.stringify(PolygonLabelsExporter.mapImagesDataToVGGObject(imagesData, labelNames));
const blob = new Blob([content], {type: "text/plain;charset=utf-8"});
try {
diff --git a/src/logic/export/RectLabelsExporter.ts b/src/logic/export/RectLabelsExporter.ts
index 1238e617..b2d7f5a7 100644
--- a/src/logic/export/RectLabelsExporter.ts
+++ b/src/logic/export/RectLabelsExporter.ts
@@ -1,11 +1,12 @@
import {ExportFormatType} from "../../data/enums/ExportFormatType";
-import {ImageData, LabelRect} from "../../store/editor/types";
+import {ImageData, LabelRect} from "../../store/labels/types";
import {ImageRepository} from "../imageRepository/ImageRepository";
import JSZip from 'jszip';
import { saveAs } from 'file-saver';
-import {EditorSelector} from "../../store/selectors/EditorSelector";
+import {LabelsSelector} from "../../store/selectors/LabelsSelector";
import {XMLSanitizerUtil} from "../../utils/XMLSanitizerUtil";
import {ExporterUtil} from "../../utils/ExporterUtil";
+import {GeneralSelector} from "../../store/selectors/GeneralSelector";
export class RectLabelsExporter {
public static export(exportFormatType: ExportFormatType): void {
@@ -26,7 +27,7 @@ export class RectLabelsExporter {
private static exportAsYOLO(): void {
let zip = new JSZip();
- EditorSelector.getImagesData()
+ LabelsSelector.getImagesData()
.forEach((imageData: ImageData) => {
const fileContent: string = RectLabelsExporter.wrapRectLabelsIntoYOLO(imageData);
if (fileContent) {
@@ -72,7 +73,7 @@ export class RectLabelsExporter {
private static exportAsVOC(): void {
let zip = new JSZip();
- EditorSelector.getImagesData().forEach((imageData: ImageData) => {
+ LabelsSelector.getImagesData().forEach((imageData: ImageData) => {
const fileContent: string = RectLabelsExporter.wrapImageIntoVOC(imageData);
if (fileContent) {
const fileName : string = imageData.fileData.name.replace(/\.[^/.]+$/, ".xml");
@@ -100,7 +101,7 @@ export class RectLabelsExporter {
if (imageData.labelRects.length === 0 || !imageData.loadStatus)
return null;
- const labelNamesList: string[] = EditorSelector.getLabelNames();
+ const labelNamesList: string[] = LabelsSelector.getLabelNames();
const labelRectsString: string[] = imageData.labelRects.map((labelRect: LabelRect) => {
const labelFields = [
`\t
)
diff --git a/src/views/EditorView/SideNavigationBar/ImagesList/ImagesList.tsx b/src/views/EditorView/SideNavigationBar/ImagesList/ImagesList.tsx
index bf421de1..59e5c6ec 100644
--- a/src/views/EditorView/SideNavigationBar/ImagesList/ImagesList.tsx
+++ b/src/views/EditorView/SideNavigationBar/ImagesList/ImagesList.tsx
@@ -3,7 +3,7 @@ import {connect} from "react-redux";
import {LabelType} from "../../../../data/enums/LabelType";
import {ISize} from "../../../../interfaces/ISize";
import {AppState} from "../../../../store";
-import {ImageData} from "../../../../store/editor/types";
+import {ImageData} from "../../../../store/labels/types";
import {VirtualList} from "../../../Common/VirtualList/VirtualList";
import ImagePreview from "../ImagePreview/ImagePreview";
import './ImagesList.scss';
@@ -99,9 +99,9 @@ class ImagesList extends React.Component {
const mapDispatchToProps = {};
const mapStateToProps = (state: AppState) => ({
- activeImageIndex: state.editor.activeImageIndex,
- imagesData: state.editor.imagesData,
- activeLabelType: state.editor.activeLabelType
+ activeImageIndex: state.labels.activeImageIndex,
+ imagesData: state.labels.imagesData,
+ activeLabelType: state.labels.activeLabelType
});
export default connect(
diff --git a/src/views/EditorView/SideNavigationBar/LabelInputField/LabelInputField.scss b/src/views/EditorView/SideNavigationBar/LabelInputField/LabelInputField.scss
index 0046032d..5c98039c 100644
--- a/src/views/EditorView/SideNavigationBar/LabelInputField/LabelInputField.scss
+++ b/src/views/EditorView/SideNavigationBar/LabelInputField/LabelInputField.scss
@@ -68,7 +68,8 @@
background-color: rgba(0, 0, 0, 0.05);
&::after {
- background-color: $secondaryColor;
+ background-color: $secondaryColor; // fallback if new css variables are not supported by browser
+ background-color: var(--leading-color);
}
}
@@ -131,7 +132,8 @@
}
&.trash:not(.disabled):hover {
- filter: brightness(35%) sepia(100%) hue-rotate(172deg) saturate(1000%);
+ filter: brightness(35%) sepia(100%) hue-rotate(172deg) saturate(2000%); // fallback if new css variables are not supported by browser
+ filter: brightness(35%) sepia(100%) hue-rotate(var(--hue-value)) saturate(2000%);
}
}
}
@@ -139,7 +141,8 @@
&:hover {
background-color: rgba(0, 0, 0, 0.05);
.Marker {
- background-color: $secondaryColor;
+ background-color: $secondaryColor; // fallback if new css variables are not supported by browser
+ background-color: var(--leading-color);
}
}
}
@@ -147,7 +150,8 @@
&.active {
background-color: rgba(0, 0, 0, 0.05);
.Marker {
- background-color: $secondaryColor;
+ background-color: $secondaryColor; // fallback if new css variables are not supported by browser
+ background-color: var(--leading-color);
}
}
@@ -160,7 +164,8 @@
&.highlighted {
background-color: rgba(0, 0, 0, 0.05);
.Marker {
- background-color: $secondaryColor;
+ background-color: $secondaryColor; // fallback if new css variables are not supported by browser
+ background-color: var(--leading-color);
}
}
}
\ No newline at end of file
diff --git a/src/views/EditorView/SideNavigationBar/LabelInputField/LabelInputField.tsx b/src/views/EditorView/SideNavigationBar/LabelInputField/LabelInputField.tsx
index 6fc12138..5970569e 100644
--- a/src/views/EditorView/SideNavigationBar/LabelInputField/LabelInputField.tsx
+++ b/src/views/EditorView/SideNavigationBar/LabelInputField/LabelInputField.tsx
@@ -8,7 +8,7 @@ import {IPoint} from "../../../../interfaces/IPoint";
import {RectUtil} from "../../../../utils/RectUtil";
import {AppState} from "../../../../store";
import {connect} from "react-redux";
-import {updateActiveLabelId, updateHighlightedLabelId} from "../../../../store/editor/actionCreators";
+import {updateActiveLabelId, updateHighlightedLabelId} from "../../../../store/labels/actionCreators";
import Scrollbars from 'react-custom-scrollbars';
import {EventType} from "../../../../data/enums/EventType";
diff --git a/src/views/EditorView/SideNavigationBar/LabelsToolkit/LabelsToolkit.scss b/src/views/EditorView/SideNavigationBar/LabelsToolkit/LabelsToolkit.scss
index 68e56a4c..5bf899da 100644
--- a/src/views/EditorView/SideNavigationBar/LabelsToolkit/LabelsToolkit.scss
+++ b/src/views/EditorView/SideNavigationBar/LabelsToolkit/LabelsToolkit.scss
@@ -16,7 +16,6 @@
position: relative;
align-self: stretch;
box-sizing: border-box;
- //border-bottom: solid 1px $darkThemeSecondColor;
padding: 0 25px;
color: white;
font-size: 14px;
@@ -74,7 +73,8 @@
background-color: rgba(0, 0, 0, 0.05);
.Marker {
transform: translate(5px);
- background-color: $secondaryColor;
+ background-color: $secondaryColor; // fallback if new css variables are not supported by browser
+ background-color: var(--leading-color);
}
.Arrow {
@@ -96,28 +96,6 @@
justify-content: center;
align-items: center;
align-content: center;
-
- //&:not(.active) {
- // animation-duration: 0.6s;
- // animation-name: cssAnimationHide;
- // animation-fill-mode: forwards;
- //}
}
}
-//@keyframes cssAnimationHide {
-// 0% {
-// opacity: 1;
-// height: 0;
-// }
-// 20% {
-// opacity: 0;
-// //width: 400px;
-// }
-// 100% {
-// opacity: 0;
-// //width: 0;
-// overflow: hidden;
-// }
-//}
-
diff --git a/src/views/EditorView/SideNavigationBar/LabelsToolkit/LabelsToolkit.tsx b/src/views/EditorView/SideNavigationBar/LabelsToolkit/LabelsToolkit.tsx
index 6b0a5f27..18bf3065 100644
--- a/src/views/EditorView/SideNavigationBar/LabelsToolkit/LabelsToolkit.tsx
+++ b/src/views/EditorView/SideNavigationBar/LabelsToolkit/LabelsToolkit.tsx
@@ -1,7 +1,7 @@
import React from "react";
import './LabelsToolkit.scss';
-import {ImageData} from "../../../../store/editor/types";
-import {updateActiveLabelId, updateActiveLabelType, updateImageDataById} from "../../../../store/editor/actionCreators";
+import {ImageData} from "../../../../store/labels/types";
+import {updateActiveLabelId, updateActiveLabelType, updateImageDataById} from "../../../../store/labels/actionCreators";
import {AppState} from "../../../../store";
import {connect} from "react-redux";
import {LabelType} from "../../../../data/enums/LabelType";
@@ -182,10 +182,10 @@ const mapDispatchToProps = {
};
const mapStateToProps = (state: AppState) => ({
- activeImageIndex: state.editor.activeImageIndex,
- activeLabelType: state.editor.activeLabelType,
- imagesData: state.editor.imagesData,
- projectType: state.editor.projectType,
+ activeImageIndex: state.labels.activeImageIndex,
+ activeLabelType: state.labels.activeLabelType,
+ imagesData: state.labels.imagesData,
+ projectType: state.general.projectData.type,
});
export default connect(
diff --git a/src/views/EditorView/SideNavigationBar/PointLabelsList/PointLabelsList.tsx b/src/views/EditorView/SideNavigationBar/PointLabelsList/PointLabelsList.tsx
index 522e8bf4..20ef510e 100644
--- a/src/views/EditorView/SideNavigationBar/PointLabelsList/PointLabelsList.tsx
+++ b/src/views/EditorView/SideNavigationBar/PointLabelsList/PointLabelsList.tsx
@@ -1,13 +1,13 @@
import React from 'react';
import {ISize} from "../../../../interfaces/ISize";
import Scrollbars from 'react-custom-scrollbars';
-import {ImageData, LabelPoint} from "../../../../store/editor/types";
+import {ImageData, LabelPoint} from "../../../../store/labels/types";
import './PointLabelsList.scss';
import {
updateActiveLabelId,
updateActiveLabelNameIndex,
updateImageDataById
-} from "../../../../store/editor/actionCreators";
+} from "../../../../store/labels/actionCreators";
import {AppState} from "../../../../store";
import {connect} from "react-redux";
import LabelInputField from "../LabelInputField/LabelInputField";
@@ -112,10 +112,10 @@ const mapDispatchToProps = {
};
const mapStateToProps = (state: AppState) => ({
- activeLabelIndex: state.editor.activeLabelNameIndex,
- activeLabelId: state.editor.activeLabelId,
- highlightedLabelId: state.editor.highlightedLabelId,
- labelNames : state.editor.labelNames
+ activeLabelIndex: state.labels.activeLabelNameIndex,
+ activeLabelId: state.labels.activeLabelId,
+ highlightedLabelId: state.labels.highlightedLabelId,
+ labelNames : state.labels.labelNames
});
export default connect(
diff --git a/src/views/EditorView/SideNavigationBar/PolygonLabelsList/PolygonLabelsList.tsx b/src/views/EditorView/SideNavigationBar/PolygonLabelsList/PolygonLabelsList.tsx
index e3fea0fc..4f08729c 100644
--- a/src/views/EditorView/SideNavigationBar/PolygonLabelsList/PolygonLabelsList.tsx
+++ b/src/views/EditorView/SideNavigationBar/PolygonLabelsList/PolygonLabelsList.tsx
@@ -1,13 +1,13 @@
import React from 'react';
import {ISize} from "../../../../interfaces/ISize";
import Scrollbars from 'react-custom-scrollbars';
-import {ImageData, LabelPolygon} from "../../../../store/editor/types";
+import {ImageData, LabelPolygon} from "../../../../store/labels/types";
import './PolygonLabelsList.scss';
import {
updateActiveLabelId,
updateActiveLabelNameIndex,
updateImageDataById
-} from "../../../../store/editor/actionCreators";
+} from "../../../../store/labels/actionCreators";
import {AppState} from "../../../../store";
import {connect} from "react-redux";
import LabelInputField from "../LabelInputField/LabelInputField";
@@ -112,10 +112,10 @@ const mapDispatchToProps = {
};
const mapStateToProps = (state: AppState) => ({
- activeLabelIndex: state.editor.activeLabelNameIndex,
- activeLabelId: state.editor.activeLabelId,
- highlightedLabelId: state.editor.highlightedLabelId,
- labelNames : state.editor.labelNames
+ activeLabelIndex: state.labels.activeLabelNameIndex,
+ activeLabelId: state.labels.activeLabelId,
+ highlightedLabelId: state.labels.highlightedLabelId,
+ labelNames : state.labels.labelNames
});
export default connect(
diff --git a/src/views/EditorView/SideNavigationBar/RectLabelsList/RectLabelsList.tsx b/src/views/EditorView/SideNavigationBar/RectLabelsList/RectLabelsList.tsx
index 1091809e..c6a83a40 100644
--- a/src/views/EditorView/SideNavigationBar/RectLabelsList/RectLabelsList.tsx
+++ b/src/views/EditorView/SideNavigationBar/RectLabelsList/RectLabelsList.tsx
@@ -1,18 +1,19 @@
import React from 'react';
import {ISize} from "../../../../interfaces/ISize";
import Scrollbars from 'react-custom-scrollbars';
-import {ImageData, LabelRect} from "../../../../store/editor/types";
+import {ImageData, LabelRect} from "../../../../store/labels/types";
import './RectLabelsList.scss';
import {
updateActiveLabelId,
updateActiveLabelNameIndex,
updateImageDataById
-} from "../../../../store/editor/actionCreators";
+} from "../../../../store/labels/actionCreators";
import {AppState} from "../../../../store";
import {connect} from "react-redux";
import LabelInputField from "../LabelInputField/LabelInputField";
import EmptyLabelList from "../EmptyLabelList/EmptyLabelList";
import {LabelActions} from "../../../../logic/actions/LabelActions";
+import {LabelStatus} from "../../../../data/enums/LabelStatus";
interface IProps {
size: ISize;
@@ -48,7 +49,8 @@ const RectLabelsList: React.FC = ({size, imageData, updateImageDataById,
if (labelRect.id === labelRectId) {
return {
...labelRect,
- labelIndex: labelNameIndex
+ labelIndex: labelNameIndex,
+ status: LabelStatus.ACCEPTED
}
} else {
return labelRect
@@ -113,10 +115,10 @@ const mapDispatchToProps = {
};
const mapStateToProps = (state: AppState) => ({
- activeLabelIndex: state.editor.activeLabelNameIndex,
- activeLabelId: state.editor.activeLabelId,
- highlightedLabelId: state.editor.highlightedLabelId,
- labelNames : state.editor.labelNames
+ activeLabelIndex: state.labels.activeLabelNameIndex,
+ activeLabelId: state.labels.activeLabelId,
+ highlightedLabelId: state.labels.highlightedLabelId,
+ labelNames : state.labels.labelNames
});
export default connect(
diff --git a/src/views/EditorView/StateBar/StateBar.scss b/src/views/EditorView/StateBar/StateBar.scss
index 72c40b52..89ea9338 100644
--- a/src/views/EditorView/StateBar/StateBar.scss
+++ b/src/views/EditorView/StateBar/StateBar.scss
@@ -14,8 +14,8 @@
.done {
align-self: stretch;
- //width: 30%;
- background-color: $secondaryColor;
+ background-color: $secondaryColor; // fallback if new css variables are not supported by browser
+ background-color: var(--leading-color);
transition: width 0.4s ease-out;
}
}
\ No newline at end of file
diff --git a/src/views/EditorView/StateBar/StateBar.tsx b/src/views/EditorView/StateBar/StateBar.tsx
index 3ab6fb31..1a13c04f 100644
--- a/src/views/EditorView/StateBar/StateBar.tsx
+++ b/src/views/EditorView/StateBar/StateBar.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import './StateBar.scss';
-import {ImageData} from "../../../store/editor/types";
+import {ImageData} from "../../../store/labels/types";
import {AppState} from "../../../store";
import {connect} from "react-redux";
import {LabelType} from "../../../data/enums/LabelType";
@@ -50,8 +50,8 @@ const StateBar: React.FC = ({imagesData, activeLabelType}) => {
const mapDispatchToProps = {};
const mapStateToProps = (state: AppState) => ({
- imagesData: state.editor.imagesData,
- activeLabelType: state.editor.activeLabelType
+ imagesData: state.labels.imagesData,
+ activeLabelType: state.labels.activeLabelType
});
export default connect(
diff --git a/src/views/EditorView/ToolBox/ToolBox.tsx b/src/views/EditorView/ToolBox/ToolBox.tsx
index f8fd8d7d..590cd903 100644
--- a/src/views/EditorView/ToolBox/ToolBox.tsx
+++ b/src/views/EditorView/ToolBox/ToolBox.tsx
@@ -10,8 +10,8 @@ import {ViewPortActions} from "../../../logic/actions/ViewPortActions";
import {ISize} from "../../../interfaces/ISize";
import {updateImageDragModeStatus} from "../../../store/general/actionCreators";
import ImageButtonDropDown from "./ImageButtonDropDown/ImageButtonDropDown";
-import {EditorModel} from "../../../staticModels/EditorModel";
import {ViewPointSettings} from "../../../settings/ViewPointSettings";
+import {GeneralSelector} from "../../../store/selectors/GeneralSelector";
interface IProps {
activeContext: ContextType;
@@ -46,7 +46,10 @@ const ToolBox: React.FC = ({activeContext, updateImageDragModeStatus, im
];
const imageDragOnClick = () => {
- if (EditorModel.zoom !== ViewPointSettings.MIN_ZOOM) {
+ if (imageDragMode) {
+ updateImageDragModeStatus(!imageDragMode);
+ }
+ else if (GeneralSelector.getZoom() !== ViewPointSettings.MIN_ZOOM) {
updateImageDragModeStatus(!imageDragMode);
}
};
diff --git a/src/views/EditorView/TopNavigationBar/TopNavigationBar.scss b/src/views/EditorView/TopNavigationBar/TopNavigationBar.scss
index e610206b..b09b0af2 100644
--- a/src/views/EditorView/TopNavigationBar/TopNavigationBar.scss
+++ b/src/views/EditorView/TopNavigationBar/TopNavigationBar.scss
@@ -55,7 +55,8 @@
}
&:not(.disabled):hover {
- filter: brightness(35%) sepia(100%) hue-rotate(172deg) saturate(1000%);
+ filter: brightness(35%) sepia(100%) hue-rotate(172deg) saturate(2000%); // fallback if new css variables are not supported by browser
+ filter: brightness(35%) sepia(100%) hue-rotate(var(--hue-value)) saturate(2000%);
}
}
@@ -72,10 +73,12 @@
&:focus {
outline: none;
- color: $secondaryColor;
+ color: $secondaryColor; // fallback if new css variables are not supported by browser
+ color: var(--leading-color);
~ .Bar {
- background-color: $secondaryColor;
+ background-color: $secondaryColor; // fallback if new css variables are not supported by browser
+ background-color: var(--leading-color);
}
}
}
diff --git a/src/views/EditorView/TopNavigationBar/TopNavigationBar.tsx b/src/views/EditorView/TopNavigationBar/TopNavigationBar.tsx
index d5aad8d1..36c79f5a 100644
--- a/src/views/EditorView/TopNavigationBar/TopNavigationBar.tsx
+++ b/src/views/EditorView/TopNavigationBar/TopNavigationBar.tsx
@@ -5,19 +5,19 @@ import {UnderlineTextButton} from "../../Common/UnderlineTextButton/UnderlineTex
import {PopupWindowType} from "../../../data/enums/PopupWindowType";
import {AppState} from "../../../store";
import {connect} from "react-redux";
-import {updateActivePopupType} from "../../../store/general/actionCreators";
+import {updateActivePopupType, updateProjectData} from "../../../store/general/actionCreators";
import TextInput from "../../Common/TextInput/TextInput";
-import {updateProjectName} from "../../../store/editor/actionCreators";
import {ImageButton} from "../../Common/ImageButton/ImageButton";
import {Settings} from "../../../settings/Settings";
+import {ProjectData} from "../../../store/general/types";
interface IProps {
updateActivePopupType: (activePopupType: PopupWindowType) => any;
- updateProjectName: (projectName: string) => any;
- projectName: string;
+ updateProjectData: (projectData: ProjectData) => any;
+ projectData: ProjectData;
}
-const TopNavigationBar: React.FC = ({updateActivePopupType, updateProjectName, projectName}) => {
+const TopNavigationBar: React.FC = ({updateActivePopupType, updateProjectData, projectData}) => {
const onFocus = (event: React.FocusEvent) => {
event.target.setSelectionRange(0, event.target.value.length);
};
@@ -26,7 +26,11 @@ const TopNavigationBar: React.FC = ({updateActivePopupType, updateProjec
const value = event.target.value
.toLowerCase()
.replace(' ', '-');
- updateProjectName(value)
+
+ updateProjectData({
+ ...projectData,
+ name: value
+ })
};
return (
@@ -51,7 +55,7 @@ const TopNavigationBar: React.FC = ({updateActivePopupType, updateProjec
@@ -81,11 +85,11 @@ const TopNavigationBar: React.FC = ({updateActivePopupType, updateProjec
const mapDispatchToProps = {
updateActivePopupType,
- updateProjectName
+ updateProjectData
};
const mapStateToProps = (state: AppState) => ({
- projectName: state.editor.projectName
+ projectData: state.general.projectData
});
export default connect(
diff --git a/src/views/EditorView/VerticalEditorButton/VerticalEditorButton.scss b/src/views/EditorView/VerticalEditorButton/VerticalEditorButton.scss
index 6d9739b8..c5811dff 100644
--- a/src/views/EditorView/VerticalEditorButton/VerticalEditorButton.scss
+++ b/src/views/EditorView/VerticalEditorButton/VerticalEditorButton.scss
@@ -30,10 +30,12 @@
}
&:hover {
- background-color: $secondaryColor;
+ background-color: $secondaryColor; // fallback if new css variables are not supported by browser
+ background-color: var(--leading-color);
}
&.active {
- background-color: $secondaryColor;
+ background-color: $secondaryColor; // fallback if new css variables are not supported by browser
+ background-color: var(--leading-color);
}
}
\ No newline at end of file
diff --git a/src/views/MainView/ImagesDropZone/ImagesDropZone.tsx b/src/views/MainView/ImagesDropZone/ImagesDropZone.tsx
index b609dd82..ff339070 100644
--- a/src/views/MainView/ImagesDropZone/ImagesDropZone.tsx
+++ b/src/views/MainView/ImagesDropZone/ImagesDropZone.tsx
@@ -2,31 +2,36 @@ import React from "react";
import './ImagesDropZone.scss';
import {useDropzone} from "react-dropzone";
import {TextButton} from "../../Common/TextButton/TextButton";
-import {ImageData} from "../../../store/editor/types";
+import {ImageData} from "../../../store/labels/types";
import {connect} from "react-redux";
-import {addImageData, updateActiveImageIndex, updateProjectType} from "../../../store/editor/actionCreators";
+import {addImageData, updateActiveImageIndex} from "../../../store/labels/actionCreators";
import {AppState} from "../../../store";
import {ProjectType} from "../../../data/enums/ProjectType";
import {FileUtil} from "../../../utils/FileUtil";
import {PopupWindowType} from "../../../data/enums/PopupWindowType";
-import {updateActivePopupType} from "../../../store/general/actionCreators";
+import {updateActivePopupType, updateProjectData} from "../../../store/general/actionCreators";
import {AcceptedFileType} from "../../../data/enums/AcceptedFileType";
+import {ProjectData} from "../../../store/general/types";
interface IProps {
updateActiveImageIndex: (activeImageIndex: number) => any;
addImageData: (imageData: ImageData[]) => any;
- updateProjectType: (projectType: ProjectType) => any;
+ updateProjectData: (projectData: ProjectData) => any;
updateActivePopupType: (activePopupType: PopupWindowType) => any;
+ projectData: ProjectData;
}
-const ImagesDropZone: React.FC = ({updateActiveImageIndex, addImageData, updateProjectType, updateActivePopupType}) => {
+const ImagesDropZone: React.FC = ({updateActiveImageIndex, addImageData, updateProjectData, updateActivePopupType, projectData}) => {
const {acceptedFiles, getRootProps, getInputProps} = useDropzone({
accept: AcceptedFileType.IMAGE
});
const startEditor = (projectType: ProjectType) => {
if (acceptedFiles.length > 0) {
- updateProjectType(projectType);
+ updateProjectData({
+ ...projectData,
+ type: projectType
+ });
updateActiveImageIndex(0);
addImageData(acceptedFiles.map((fileData:File) => FileUtil.mapFileDataToImageData(fileData)));
updateActivePopupType(PopupWindowType.INSERT_LABEL_NAMES);
@@ -92,11 +97,13 @@ const ImagesDropZone: React.FC = ({updateActiveImageIndex, addImageData,
const mapDispatchToProps = {
updateActiveImageIndex,
addImageData,
- updateProjectType,
+ updateProjectData,
updateActivePopupType
};
-const mapStateToProps = (state: AppState) => ({});
+const mapStateToProps = (state: AppState) => ({
+ projectData: state.general.projectData
+});
export default connect(
mapStateToProps,
diff --git a/src/views/PopupView/ExitProjectPopup/ExitProjectPopup.tsx b/src/views/PopupView/ExitProjectPopup/ExitProjectPopup.tsx
index 1ed620a1..b6c18ffb 100644
--- a/src/views/PopupView/ExitProjectPopup/ExitProjectPopup.tsx
+++ b/src/views/PopupView/ExitProjectPopup/ExitProjectPopup.tsx
@@ -6,32 +6,32 @@ import {
updateActiveLabelNameIndex,
updateFirstLabelCreatedFlag,
updateImageData,
- updateLabelNamesList,
- updateProjectType
-} from "../../../store/editor/actionCreators";
+ updateLabelNamesList
+} from "../../../store/labels/actionCreators";
import {AppState} from "../../../store";
import {connect} from "react-redux";
-import {ProjectType} from "../../../data/enums/ProjectType";
-import {ImageData} from "../../../store/editor/types";
+import {ImageData} from "../../../store/labels/types";
import {PopupActions} from "../../../logic/actions/PopupActions";
+import {ProjectData} from "../../../store/general/types";
+import {updateProjectData} from "../../../store/general/actionCreators";
interface IProps {
updateActiveImageIndex: (activeImageIndex: number) => any;
- updateProjectType: (projectType: ProjectType) => any;
updateActiveLabelNameIndex: (activeLabelIndex: number) => any;
updateLabelNamesList: (labelNames: string[]) => any;
updateImageData: (imageData: ImageData[]) => any;
updateFirstLabelCreatedFlag: (firstLabelCreatedFlag: boolean) => any;
+ updateProjectData: (projectData: ProjectData) => any;
}
const ExitProjectPopup: React.FC = (props) => {
const {
updateActiveLabelNameIndex,
updateLabelNamesList,
- updateProjectType,
updateActiveImageIndex,
updateImageData,
- updateFirstLabelCreatedFlag
+ updateFirstLabelCreatedFlag,
+ updateProjectData
} = props;
const renderContent = () => {
@@ -47,7 +47,7 @@ const ExitProjectPopup: React.FC = (props) => {
const onAccept = () => {
updateActiveLabelNameIndex(null);
updateLabelNamesList([]);
- updateProjectType(null);
+ updateProjectData({type: null, name: "my-project-name"});
updateActiveImageIndex(null);
updateImageData([]);
updateFirstLabelCreatedFlag(false);
@@ -72,7 +72,7 @@ const ExitProjectPopup: React.FC = (props) => {
const mapDispatchToProps = {
updateActiveLabelNameIndex,
updateLabelNamesList,
- updateProjectType,
+ updateProjectData,
updateActiveImageIndex,
updateImageData,
updateFirstLabelCreatedFlag
diff --git a/src/views/PopupView/ExportLabelsPopup/ExportLabelPopup.tsx b/src/views/PopupView/ExportLabelsPopup/ExportLabelPopup.tsx
index b36b0a94..cf2a4216 100644
--- a/src/views/PopupView/ExportLabelsPopup/ExportLabelPopup.tsx
+++ b/src/views/PopupView/ExportLabelsPopup/ExportLabelPopup.tsx
@@ -131,7 +131,7 @@ const ExportLabelPopup: React.FC = () => {
const mapDispatchToProps = {};
const mapStateToProps = (state: AppState) => ({
- imagesData: state.editor.imagesData
+ imagesData: state.labels.imagesData
});
export default connect(
diff --git a/src/views/PopupView/GenericYesNoPopup/GenericYesNoPopup.scss b/src/views/PopupView/GenericYesNoPopup/GenericYesNoPopup.scss
index 6ecd1356..4c999725 100644
--- a/src/views/PopupView/GenericYesNoPopup/GenericYesNoPopup.scss
+++ b/src/views/PopupView/GenericYesNoPopup/GenericYesNoPopup.scss
@@ -60,13 +60,16 @@
.TextButton {
margin-left: 20px;
- box-shadow: $secondaryColor 0 0 0 2px inset;
- background-color: $secondaryColor;
+ box-shadow: $secondaryColor 0 0 0 2px inset; // fallback if new css variables are not supported by browser
+ box-shadow: var(--leading-color) 0 0 0 2px inset;
+ background-color: $secondaryColor; // fallback if new css variables are not supported by browser
+ background-color: var(--leading-color);
color: white;
&:hover {
background-color: transparent;
- color: $secondaryColor;
+ color: $secondaryColor; // fallback if new css variables are not supported by browser
+ color: var(--leading-color);
}
&.disabled {
diff --git a/src/views/PopupView/InsertLabelNamesPopup/InsertLabelNamesPopup.tsx b/src/views/PopupView/InsertLabelNamesPopup/InsertLabelNamesPopup.tsx
index 40249a64..ac97f0b9 100644
--- a/src/views/PopupView/InsertLabelNamesPopup/InsertLabelNamesPopup.tsx
+++ b/src/views/PopupView/InsertLabelNamesPopup/InsertLabelNamesPopup.tsx
@@ -2,7 +2,7 @@ import React, {useState} from 'react'
import './InsertLabelNamesPopup.scss'
import {GenericYesNoPopup} from "../GenericYesNoPopup/GenericYesNoPopup";
import {PopupWindowType} from "../../../data/enums/PopupWindowType";
-import {updateActiveLabelNameIndex, updateLabelNamesList} from "../../../store/editor/actionCreators";
+import {updateActiveLabelNameIndex, updateLabelNamesList} from "../../../store/labels/actionCreators";
import {updateActivePopupType} from "../../../store/general/actionCreators";
import {AppState} from "../../../store";
import {connect} from "react-redux";
@@ -10,7 +10,6 @@ import Scrollbars from 'react-custom-scrollbars';
import TextInput from "../../Common/TextInput/TextInput";
import {ImageButton} from "../../Common/ImageButton/ImageButton";
import uuidv1 from 'uuid/v1';
-import {PopupActions} from "../../../logic/actions/PopupActions";
interface IProps {
updateActiveLabelNameIndex: (activeLabelIndex: number) => any;
@@ -58,7 +57,7 @@ const InsertLabelNamesPopup: React.FC = ({updateActiveLabelNameIndex, up
const labelNamesList: string[] = extractLabelNamesList();
if (labelNamesList.length > 0) {
updateLabelNamesList(labelNamesList);
- PopupActions.close();
+ updateActivePopupType(PopupWindowType.LOAD_AI_MODEL);
}
};
diff --git a/src/views/PopupView/LoadLabelNamesPopup/LoadLabelNamesPopup.tsx b/src/views/PopupView/LoadLabelNamesPopup/LoadLabelNamesPopup.tsx
index 46abd1ec..2188088e 100644
--- a/src/views/PopupView/LoadLabelNamesPopup/LoadLabelNamesPopup.tsx
+++ b/src/views/PopupView/LoadLabelNamesPopup/LoadLabelNamesPopup.tsx
@@ -2,14 +2,13 @@ import React, {useState} from 'react'
import './LoadLabelNamesPopup.scss'
import {AppState} from "../../../store";
import {connect} from "react-redux";
-import {updateActiveLabelNameIndex, updateLabelNamesList} from "../../../store/editor/actionCreators";
+import {updateActiveLabelNameIndex, updateLabelNamesList} from "../../../store/labels/actionCreators";
import {GenericYesNoPopup} from "../GenericYesNoPopup/GenericYesNoPopup";
import {PopupWindowType} from "../../../data/enums/PopupWindowType";
import {updateActivePopupType} from "../../../store/general/actionCreators";
import {useDropzone} from "react-dropzone";
import {FileUtil} from "../../../utils/FileUtil";
import {AcceptedFileType} from "../../../data/enums/AcceptedFileType";
-import {PopupActions} from "../../../logic/actions/PopupActions";
interface IProps {
updateActiveLabelNameIndex: (activeLabelIndex: number) => any;
@@ -44,7 +43,7 @@ const LoadLabelNamesPopup: React.FC = ({updateActiveLabelNameIndex, upda
if (labelsList.length > 0) {
updateActiveLabelNameIndex(0);
updateLabelNamesList(labelsList);
- PopupActions.close();
+ updateActivePopupType(PopupWindowType.LOAD_AI_MODEL);
}
};
diff --git a/src/views/PopupView/LoadModelPopup/LoadModelPopup.scss b/src/views/PopupView/LoadModelPopup/LoadModelPopup.scss
new file mode 100644
index 00000000..8b4255b4
--- /dev/null
+++ b/src/views/PopupView/LoadModelPopup/LoadModelPopup.scss
@@ -0,0 +1,38 @@
+@import '../../../settings/Settings';
+
+.LoadModelPopupContent {
+ display: flex;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ justify-content: center;
+ align-items: center;
+ align-content: center;
+ padding-top: 30px;
+ flex: 1;
+
+ .Message {
+ align-self: stretch;
+ color: white;
+ font-size: 15px;
+ padding: 0 40px 30px 40px;
+ }
+
+ .Companion {
+ align-self: stretch;
+ padding-bottom: 30px;
+ display: flex;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ justify-content: center;
+ align-items: center;
+ align-content: center;
+ height: 150px;
+
+ > img {
+ filter: brightness(0) invert(1);
+ max-width: 60px;
+ max-height: 60px;
+ user-select: none;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/views/PopupView/LoadModelPopup/LoadModelPopup.tsx b/src/views/PopupView/LoadModelPopup/LoadModelPopup.tsx
new file mode 100644
index 00000000..fdcf3a14
--- /dev/null
+++ b/src/views/PopupView/LoadModelPopup/LoadModelPopup.tsx
@@ -0,0 +1,61 @@
+import React, {useState} from "react";
+import {PopupActions} from "../../../logic/actions/PopupActions";
+import {GenericYesNoPopup} from "../GenericYesNoPopup/GenericYesNoPopup";
+import {ObjectDetector} from "../../../ai/ObjectDetector";
+import './LoadModelPopup.scss'
+import {Settings} from "../../../settings/Settings";
+import {ClipLoader} from "react-spinners";
+
+export const LoadModelPopup: React.FC = () => {
+ const [modelIsLoadingStatus, setModelIsLoadingStatus] = useState(false);
+
+ const onAccept = () => {
+ setModelIsLoadingStatus(true);
+ ObjectDetector.loadModel(() => {
+ PopupActions.close();
+ });
+ };
+
+ const onReject = () => {
+ PopupActions.close();
+ };
+
+ const renderContent = () => {
+ return
+
+ To speed up your work, you can use our AI, which will try to mark objects on your images. Don't worry,
+ your photos are still safe. To take care of your privacy, we decided not to send your images to the
+ server, but instead send our AI to you. When accepting, make sure that you have a fast and stable
+ connection - it may take a few minutes to load the model.
+
+
+ {modelIsLoadingStatus ?
+ :
+
+ }
+
+
+ };
+
+ return(
+
+ );
+};
\ No newline at end of file
diff --git a/src/views/PopupView/LoadMoreImagesPopup/LoadMoreImagesPopup.tsx b/src/views/PopupView/LoadMoreImagesPopup/LoadMoreImagesPopup.tsx
index de60324d..dbf44f3b 100644
--- a/src/views/PopupView/LoadMoreImagesPopup/LoadMoreImagesPopup.tsx
+++ b/src/views/PopupView/LoadMoreImagesPopup/LoadMoreImagesPopup.tsx
@@ -2,11 +2,11 @@ import React from 'react'
import './LoadMoreImagesPopup.scss'
import {AppState} from "../../../store";
import {connect} from "react-redux";
-import {addImageData} from "../../../store/editor/actionCreators";
+import {addImageData} from "../../../store/labels/actionCreators";
import {GenericYesNoPopup} from "../GenericYesNoPopup/GenericYesNoPopup";
import {useDropzone} from "react-dropzone";
import {FileUtil} from "../../../utils/FileUtil";
-import {ImageData} from "../../../store/editor/types";
+import {ImageData} from "../../../store/labels/types";
import {AcceptedFileType} from "../../../data/enums/AcceptedFileType";
import {PopupActions} from "../../../logic/actions/PopupActions";
diff --git a/src/views/PopupView/PopupView.tsx b/src/views/PopupView/PopupView.tsx
index c4d0087e..5f66bd56 100644
--- a/src/views/PopupView/PopupView.tsx
+++ b/src/views/PopupView/PopupView.tsx
@@ -8,6 +8,7 @@ import ExportLabelPopup from "./ExportLabelsPopup/ExportLabelPopup";
import InsertLabelNamesPopup from "./InsertLabelNamesPopup/InsertLabelNamesPopup";
import ExitProjectPopup from "./ExitProjectPopup/ExitProjectPopup";
import LoadMoreImagesPopup from "./LoadMoreImagesPopup/LoadMoreImagesPopup";
+import {LoadModelPopup} from "./LoadModelPopup/LoadModelPopup";
interface IProps {
activePopupType: PopupWindowType;
@@ -27,6 +28,8 @@ const PopupView: React.FC = ({activePopupType}) => {
return ;
case PopupWindowType.LOAD_IMAGES:
return ;
+ case PopupWindowType.LOAD_AI_MODEL:
+ return ;
default:
return null;
}