improve zooming and scrolling
This commit is contained in:
Vendored
+4
-5
@@ -475,6 +475,7 @@ body[showing-chat] #chat-page-wrapper {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
#chat-page > div > #main > #task-page > .pane-wrapper > .pane > .main-content > div {
|
#chat-page > div > #main > #task-page > .pane-wrapper > .pane > .main-content > div {
|
||||||
animation: slide-up var(--animation-duration);
|
animation: slide-up var(--animation-duration);
|
||||||
@@ -485,14 +486,12 @@ body[showing-chat] #chat-page-wrapper {
|
|||||||
gap: var(--gap-between-tiles);
|
gap: var(--gap-between-tiles);
|
||||||
padding: var(--content-padding);
|
padding: var(--content-padding);
|
||||||
}
|
}
|
||||||
#chat-page > div > #main > #task-page .kanban-board-wrapper,
|
#chat-page > div > #main > #task-page .zoom {
|
||||||
#chat-page > div > #main > #task-page .status-page-content {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
gap: var(--large-gap);
|
gap: var(--large-gap);
|
||||||
width: 100%;
|
width: auto;
|
||||||
height: 100%;
|
height: auto;
|
||||||
overflow: visible;
|
|
||||||
transform-origin: top left;
|
transform-origin: top left;
|
||||||
padding: var(--content-padding);
|
padding: var(--content-padding);
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+125
-77
@@ -1136,32 +1136,82 @@
|
|||||||
function localeCompare(a, b) {
|
function localeCompare(a, b) {
|
||||||
return a.localeCompare(b);
|
return a.localeCompare(b);
|
||||||
}
|
}
|
||||||
function implementPinchZoom(element) {
|
function implementPinchZoom(targetSelector) {
|
||||||
let initialDistance = 0;
|
|
||||||
let pinching = false;
|
let pinching = false;
|
||||||
|
let initialDistance = 0;
|
||||||
|
let currentZoom = 1;
|
||||||
|
let initialZoom = 1;
|
||||||
|
let currentX = 0;
|
||||||
|
let currentY = 0;
|
||||||
|
let initialX = 0;
|
||||||
|
let initialY = 0;
|
||||||
|
let initialTouchX = 0;
|
||||||
|
let initialTouchY = 0;
|
||||||
|
const MIN = 0.25;
|
||||||
|
const MAX = 5;
|
||||||
|
const element = () => canvas.querySelector(targetSelector);
|
||||||
|
const parent = () => element().parentElement;
|
||||||
const distance = (e) => Math.hypot(
|
const distance = (e) => Math.hypot(
|
||||||
e.touches[0].pageX - e.touches[1].pageX,
|
e.touches[0].pageX - e.touches[1].pageX,
|
||||||
e.touches[0].pageY - e.touches[1].pageY
|
e.touches[0].pageY - e.touches[1].pageY
|
||||||
);
|
);
|
||||||
function apply(factor) {
|
const point = (e, direction, i) => e.touches[i][direction == "x" ? "clientX" : "clientY"];
|
||||||
element.style.transform = `scale(${(Math.floor(factor * 100) / 100).toString()})`;
|
const midpoint = (e, direction) => (point(e, direction, 0) + point(e, direction, 1)) / 2;
|
||||||
|
function apply(factor, offset) {
|
||||||
|
if (factor < MIN) return apply(MIN, offset);
|
||||||
|
if (factor > MAX) return apply(5, offset);
|
||||||
|
if (!element) return;
|
||||||
|
const [x, y] = offset;
|
||||||
|
element().style.transform = `scale(${(Math.floor(factor * 100) / 100).toString()}) translate(${x}px, ${y}px)`;
|
||||||
|
currentX = x;
|
||||||
|
currentY = y;
|
||||||
|
currentZoom = factor;
|
||||||
}
|
}
|
||||||
element.addEventListener("touchstart", (event) => {
|
const canvas = document.body;
|
||||||
if (event.touches.length != 2) return;
|
canvas.addEventListener("touchstart", (event) => {
|
||||||
initialDistance = distance(event);
|
document.activeElement.blur();
|
||||||
|
initialZoom = currentZoom;
|
||||||
|
initialX = currentX;
|
||||||
|
initialY = currentY;
|
||||||
|
if (event.touches.length != 2) {
|
||||||
|
pinching = false;
|
||||||
|
initialTouchX = event.touches[0].clientX;
|
||||||
|
initialTouchY = event.touches[0].clientY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
pinching = true;
|
pinching = true;
|
||||||
apply(1);
|
initialDistance = distance(event);
|
||||||
|
initialTouchX = midpoint(event, "x");
|
||||||
|
initialTouchY = midpoint(event, "y");
|
||||||
});
|
});
|
||||||
element.addEventListener("touchend", (event) => {
|
canvas.addEventListener("touchmove", (event) => {
|
||||||
if (event.touches.length == 2) return;
|
if (!pinching) {
|
||||||
pinching = false;
|
apply(currentZoom, [
|
||||||
});
|
initialX + (event.touches[0].clientX - initialTouchX) / initialZoom,
|
||||||
element.addEventListener("touchmove", (event) => {
|
initialY + (event.touches[0].clientY - initialTouchY) / initialZoom
|
||||||
if (!pinching) return;
|
]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.touches.length < 2) return;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const currentDistance = distance(event);
|
const currentDistance = distance(event);
|
||||||
const factor = currentDistance / initialDistance;
|
const midX = midpoint(event, "x");
|
||||||
apply(factor);
|
const midY = midpoint(event, "y");
|
||||||
|
const ratio = currentDistance / initialDistance;
|
||||||
|
const difference = currentDistance - initialDistance;
|
||||||
|
apply(initialZoom * ratio, [initialX + (midX - difference - initialTouchX) / initialZoom, initialY + (midY - difference - initialTouchY) / initialZoom]);
|
||||||
|
});
|
||||||
|
canvas.addEventListener("wheel", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (!event.shiftKey) {
|
||||||
|
apply(currentZoom, [currentX - event.deltaX, currentY - event.deltaY]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
apply(currentZoom + (event.deltaY < 0 ? 1 : -1) * 0.1, [initialX, initialY]);
|
||||||
|
});
|
||||||
|
canvas.addEventListener("scroll", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1174,7 +1224,7 @@
|
|||||||
this.connectionModel = connectionModel2;
|
this.connectionModel = connectionModel2;
|
||||||
this.chatListModel = chatListModel2;
|
this.chatListModel = chatListModel2;
|
||||||
this.fileTransferModel = fileTransferModel2;
|
this.fileTransferModel = fileTransferModel2;
|
||||||
this.BUILD = "Build 26.08.30.C";
|
this.BUILD = "Build 26.08.30.D";
|
||||||
// CONTEXT
|
// CONTEXT
|
||||||
this.contextStack = /* @__PURE__ */ new Map();
|
this.contextStack = /* @__PURE__ */ new Map();
|
||||||
this.closeContext = (contextId, fromHistoryEvent = false) => {
|
this.closeContext = (contextId, fromHistoryEvent = false) => {
|
||||||
@@ -1858,7 +1908,10 @@
|
|||||||
};
|
};
|
||||||
this.downloadFile = async () => {
|
this.downloadFile = async () => {
|
||||||
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
||||||
const backup = await this.coreViewModel.fileTransferModel.generateBackup(this.selectedPaths.value.values(), this.exportKey.value);
|
const backup = await this.coreViewModel.fileTransferModel.generateBackup(
|
||||||
|
this.selectedPaths.value.values(),
|
||||||
|
this.exportKey.value
|
||||||
|
);
|
||||||
const anchor = document.createElement("a");
|
const anchor = document.createElement("a");
|
||||||
anchor.href = window.URL.createObjectURL(backup);
|
anchor.href = window.URL.createObjectURL(backup);
|
||||||
anchor.download = `comms-${date}.bak`;
|
anchor.download = `comms-${date}.bak`;
|
||||||
@@ -1888,7 +1941,10 @@
|
|||||||
if (!fileString || !key) return;
|
if (!fileString || !key) return;
|
||||||
this.cannotDecryptImport.value = true;
|
this.cannotDecryptImport.value = true;
|
||||||
try {
|
try {
|
||||||
await this.coreViewModel.fileTransferModel.handleBackupFile(fileString, key);
|
await this.coreViewModel.fileTransferModel.handleBackupFile(
|
||||||
|
fileString,
|
||||||
|
key
|
||||||
|
);
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@@ -4907,7 +4963,7 @@
|
|||||||
const index = createPropertyValueIndexState(sortedStatuses, statusName);
|
const index = createPropertyValueIndexState(sortedStatuses, statusName);
|
||||||
return StatusNameCell(coreViewModel2, statusName, index, boardViewModel);
|
return StatusNameCell(coreViewModel2, statusName, index, boardViewModel);
|
||||||
};
|
};
|
||||||
const main = /* @__PURE__ */ createElement("div", { class: "status-page-content" }, /* @__PURE__ */ createElement(
|
return /* @__PURE__ */ createElement("div", { class: "status-page-content zoom" }, /* @__PURE__ */ createElement(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
class: "status-name-row",
|
class: "status-name-row",
|
||||||
@@ -4941,8 +4997,6 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
implementPinchZoom(main);
|
|
||||||
return main;
|
|
||||||
}
|
}
|
||||||
function StatusNameCell(coreViewModel2, statusName, index, boardViewModel) {
|
function StatusNameCell(coreViewModel2, statusName, index, boardViewModel) {
|
||||||
const taskViewModelsWithMatchingStatus = new ListState();
|
const taskViewModelsWithMatchingStatus = new ListState();
|
||||||
@@ -5066,7 +5120,7 @@
|
|||||||
|
|
||||||
// src/View/ChatPages/boardKanbanPage.tsx
|
// src/View/ChatPages/boardKanbanPage.tsx
|
||||||
function BoardKanbanPage(coreViewModel2, boardViewModel) {
|
function BoardKanbanPage(coreViewModel2, boardViewModel) {
|
||||||
const main = PropertyValueList(
|
return PropertyValueList(
|
||||||
"category",
|
"category",
|
||||||
(taskViewModel) => taskViewModel.task,
|
(taskViewModel) => taskViewModel.task,
|
||||||
boardViewModel.filteredTaskViewModels,
|
boardViewModel.filteredTaskViewModels,
|
||||||
@@ -5086,14 +5140,12 @@
|
|||||||
return /* @__PURE__ */ createElement(
|
return /* @__PURE__ */ createElement(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
class: "kanban-board-wrapper",
|
class: "kanban-board-wrapper zoom",
|
||||||
"children:append": [categories, categoryNameConverter]
|
"children:append": [categories, categoryNameConverter]
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
implementPinchZoom(main);
|
|
||||||
return main;
|
|
||||||
}
|
}
|
||||||
function Column(coreViewModel2, categoryName, index, boardViewModel) {
|
function Column(coreViewModel2, categoryName, index, boardViewModel) {
|
||||||
return FilteredList(
|
return FilteredList(
|
||||||
@@ -6800,9 +6852,7 @@
|
|||||||
function toggle() {
|
function toggle() {
|
||||||
isSelected.value = !isSelected.value;
|
isSelected.value = !isSelected.value;
|
||||||
}
|
}
|
||||||
return /* @__PURE__ */ createElement("button", { class: "tile", "toggle:selected": isSelected, "on:click": toggle }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", { class: "ellipsis" }, fileOption.label), /* @__PURE__ */ createElement("span", { class: "secondary ellipsis" }, StorageModel.pathComponentsToString(
|
return /* @__PURE__ */ createElement("button", { class: "tile", "toggle:selected": isSelected, "on:click": toggle }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", { class: "ellipsis" }, fileOption.label), /* @__PURE__ */ createElement("span", { class: "secondary ellipsis" }, StorageModel.pathComponentsToString(...fileOption.path))));
|
||||||
...fileOption.path
|
|
||||||
))));
|
|
||||||
}
|
}
|
||||||
function DirectionSelectionModal(coreViewModel2, connectionViewModel2, fileTransferViewModel2) {
|
function DirectionSelectionModal(coreViewModel2, connectionViewModel2, fileTransferViewModel2) {
|
||||||
const isPresented = createProxyState(
|
const isPresented = createProxyState(
|
||||||
@@ -6813,55 +6863,45 @@
|
|||||||
[connectionViewModel2.isConnected],
|
[connectionViewModel2.isConnected],
|
||||||
() => connectionViewModel2.isConnected.value == false
|
() => connectionViewModel2.isConnected.value == false
|
||||||
);
|
);
|
||||||
return /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isPresented }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.dataTransferModal.transferDataHeadline), /* @__PURE__ */ createElement(
|
return /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isPresented }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.dataTransferModal.transferDataHeadline), /* @__PURE__ */ createElement("div", { class: "flex-column gap content-margin-bottom" }, /* @__PURE__ */ createElement(
|
||||||
"div",
|
"button",
|
||||||
{
|
{
|
||||||
class: "flex-column gap content-margin-bottom"
|
class: "tile",
|
||||||
|
"toggle:disabled": isDisconnected,
|
||||||
|
"on:click": fileTransferViewModel2.showFileSelectionModal
|
||||||
},
|
},
|
||||||
/* @__PURE__ */ createElement(
|
/* @__PURE__ */ createElement("span", { class: "icon" }, "share_windows"),
|
||||||
"button",
|
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, coreViewModel2.translations.dataTransferModal.fromThisDeviceButton)),
|
||||||
{
|
/* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_forward")
|
||||||
class: "tile",
|
), /* @__PURE__ */ createElement(
|
||||||
"toggle:disabled": isDisconnected,
|
"button",
|
||||||
"on:click": fileTransferViewModel2.showFileSelectionModal
|
{
|
||||||
},
|
class: "tile",
|
||||||
/* @__PURE__ */ createElement("span", { class: "icon" }, "share_windows"),
|
"toggle:disabled": isDisconnected,
|
||||||
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, coreViewModel2.translations.dataTransferModal.fromThisDeviceButton)),
|
"on:click": fileTransferViewModel2.showTransferDataInputModal
|
||||||
/* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_forward")
|
},
|
||||||
),
|
/* @__PURE__ */ createElement("span", { class: "icon" }, "cloud_download"),
|
||||||
/* @__PURE__ */ createElement(
|
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, coreViewModel2.translations.dataTransferModal.toThisDeviceButton)),
|
||||||
"button",
|
/* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_forward")
|
||||||
{
|
), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement(
|
||||||
class: "tile",
|
"button",
|
||||||
"toggle:disabled": isDisconnected,
|
{
|
||||||
"on:click": fileTransferViewModel2.showTransferDataInputModal
|
class: "tile",
|
||||||
},
|
"on:click": fileTransferViewModel2.showExportSelectionModal
|
||||||
/* @__PURE__ */ createElement("span", { class: "icon" }, "cloud_download"),
|
},
|
||||||
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, coreViewModel2.translations.dataTransferModal.toThisDeviceButton)),
|
/* @__PURE__ */ createElement("span", { class: "icon" }, "file_save"),
|
||||||
/* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_forward")
|
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, coreViewModel2.translations.dataTransferModal.exportButton)),
|
||||||
),
|
/* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_forward")
|
||||||
/* @__PURE__ */ createElement("hr", null),
|
), /* @__PURE__ */ createElement(
|
||||||
/* @__PURE__ */ createElement(
|
"button",
|
||||||
"button",
|
{
|
||||||
{
|
class: "tile",
|
||||||
class: "tile",
|
"on:click": fileTransferViewModel2.showImportModal
|
||||||
"on:click": fileTransferViewModel2.showExportSelectionModal
|
},
|
||||||
},
|
/* @__PURE__ */ createElement("span", { class: "icon" }, "upload_file"),
|
||||||
/* @__PURE__ */ createElement("span", { class: "icon" }, "file_save"),
|
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, coreViewModel2.translations.dataTransferModal.importButton)),
|
||||||
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, coreViewModel2.translations.dataTransferModal.exportButton)),
|
/* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_forward")
|
||||||
/* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_forward")
|
))), /* @__PURE__ */ createElement("button", { "on:click": fileTransferViewModel2.close }, coreViewModel2.translations.general.closeButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "close"))));
|
||||||
),
|
|
||||||
/* @__PURE__ */ createElement(
|
|
||||||
"button",
|
|
||||||
{
|
|
||||||
class: "tile",
|
|
||||||
"on:click": fileTransferViewModel2.showImportModal
|
|
||||||
},
|
|
||||||
/* @__PURE__ */ createElement("span", { class: "icon" }, "upload_file"),
|
|
||||||
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, coreViewModel2.translations.dataTransferModal.importButton)),
|
|
||||||
/* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_forward")
|
|
||||||
)
|
|
||||||
)), /* @__PURE__ */ createElement("button", { "on:click": fileTransferViewModel2.close }, coreViewModel2.translations.general.closeButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "close"))));
|
|
||||||
}
|
}
|
||||||
function FileSelectionModal(coreViewModel2, fileTransferViewModel2) {
|
function FileSelectionModal(coreViewModel2, fileTransferViewModel2) {
|
||||||
const OptionConverter = (fileOption) => {
|
const OptionConverter = (fileOption) => {
|
||||||
@@ -7118,7 +7158,14 @@
|
|||||||
[fileTransferViewModel2.presentedModal],
|
[fileTransferViewModel2.presentedModal],
|
||||||
() => fileTransferViewModel2.presentedModal.value == 8 /* ImportSelection */
|
() => fileTransferViewModel2.presentedModal.value == 8 /* ImportSelection */
|
||||||
);
|
);
|
||||||
return /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isPresented }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.dataTransferModal.importHeadline), /* @__PURE__ */ createElement("div", { class: "flex-column gap content-margin-bottom" }, /* @__PURE__ */ createElement("input", { id: "file-transfer-input", type: "file", "on:change": fileTransferViewModel2.updateImportSelection }))), /* @__PURE__ */ createElement("div", { class: "flex-row width-100" }, /* @__PURE__ */ createElement(
|
return /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isPresented }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.dataTransferModal.importHeadline), /* @__PURE__ */ createElement("div", { class: "flex-column gap content-margin-bottom" }, /* @__PURE__ */ createElement(
|
||||||
|
"input",
|
||||||
|
{
|
||||||
|
id: "file-transfer-input",
|
||||||
|
type: "file",
|
||||||
|
"on:change": fileTransferViewModel2.updateImportSelection
|
||||||
|
}
|
||||||
|
))), /* @__PURE__ */ createElement("div", { class: "flex-row width-100" }, /* @__PURE__ */ createElement(
|
||||||
"button",
|
"button",
|
||||||
{
|
{
|
||||||
class: "flex",
|
class: "flex",
|
||||||
@@ -8031,4 +8078,5 @@
|
|||||||
StorageModal(coreViewModel, storageViewModel),
|
StorageModal(coreViewModel, storageViewModel),
|
||||||
SettingsModal(coreViewModel, settingsViewModel)
|
SettingsModal(coreViewModel, settingsViewModel)
|
||||||
);
|
);
|
||||||
|
implementPinchZoom(".zoom");
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -149,14 +149,15 @@ export default class FileTransferModel {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
const rawBackup = stringify(files);
|
const rawBackup = stringify(files);
|
||||||
console.log(rawBackup);
|
console.log(rawBackup);
|
||||||
const encrypted = await encryptString(rawBackup, passphrase);
|
const encrypted = await encryptString(rawBackup, passphrase);
|
||||||
const blob = new Blob([encrypted], {type: "text/plain"});
|
const blob = new Blob([encrypted], { type: "text/plain" });
|
||||||
return blob;
|
return blob;
|
||||||
};
|
};
|
||||||
|
|
||||||
readonly prepareFileForSending = (filePath: string[]): string => {
|
readonly prepareFileForSending = (filePath: string[]): string => {
|
||||||
const fileContent: string | undefined = this.storageModel.read(filePath);
|
const fileContent: string | undefined =
|
||||||
|
this.storageModel.read(filePath);
|
||||||
if (fileContent == null) return "";
|
if (fileContent == null) return "";
|
||||||
|
|
||||||
const fileData: FileData = {
|
const fileData: FileData = {
|
||||||
|
|||||||
@@ -278,32 +278,95 @@ export function localeCompare(a: string, b: string): number {
|
|||||||
return a.localeCompare(b);
|
return a.localeCompare(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ui
|
// ui
|
||||||
export function implementPinchZoom(element: HTMLElement) {
|
export function implementPinchZoom(targetSelector: string) {
|
||||||
let initialDistance = 0;
|
|
||||||
let pinching = false;
|
let pinching = false;
|
||||||
|
|
||||||
const distance = (e: TouchEvent) => Math.hypot(e.touches[0].pageX - e.touches[1].pageX,
|
let initialDistance = 0;
|
||||||
e.touches[0].pageY - e.touches[1].pageY);
|
|
||||||
function apply(factor) {
|
let currentZoom = 1;
|
||||||
element.style.transform = `scale(${(Math.floor(factor*100)/100).toString()})`;
|
let initialZoom = 1;
|
||||||
|
|
||||||
|
let currentX = 0;
|
||||||
|
let currentY = 0;
|
||||||
|
let initialX = 0;
|
||||||
|
let initialY = 0;
|
||||||
|
let initialTouchX = 0;
|
||||||
|
let initialTouchY = 0;
|
||||||
|
|
||||||
|
const MIN = 0.25;
|
||||||
|
const MAX = 5;
|
||||||
|
|
||||||
|
const element = (): HTMLElement => canvas.querySelector(targetSelector);
|
||||||
|
const parent = (): HTMLElement => element().parentElement;
|
||||||
|
const distance = (e: TouchEvent) =>
|
||||||
|
Math.hypot(
|
||||||
|
e.touches[0].pageX - e.touches[1].pageX,
|
||||||
|
e.touches[0].pageY - e.touches[1].pageY,
|
||||||
|
);
|
||||||
|
const point = (e: TouchEvent, direction: "x" | "y", i: number) =>
|
||||||
|
e.touches[i][direction == "x" ? "clientX" : "clientY"];
|
||||||
|
const midpoint = (e: TouchEvent, direction: "x" | "y") =>
|
||||||
|
(point(e, direction, 0) + point(e, direction, 1)) / 2;
|
||||||
|
|
||||||
|
function apply(factor: number, offset: [number, number]) {
|
||||||
|
if (factor < MIN) return apply(MIN, offset);
|
||||||
|
if (factor > MAX) return apply(5, offset);
|
||||||
|
if (!element) return;
|
||||||
|
|
||||||
|
const [x, y] = offset;
|
||||||
|
element().style.transform = `scale(${(Math.floor(factor * 100) / 100).toString()}) translate(${x}px, ${y}px)`;
|
||||||
|
currentX = x;
|
||||||
|
currentY = y;
|
||||||
|
currentZoom = factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
element.addEventListener("touchstart", (event: TouchEvent) => {
|
const canvas = document.body;
|
||||||
if (event.touches.length != 2) return;
|
canvas.addEventListener("touchstart", (event: TouchEvent) => {
|
||||||
initialDistance = distance(event);
|
(document.activeElement as HTMLElement).blur();
|
||||||
|
|
||||||
|
initialZoom = currentZoom;
|
||||||
|
initialX = currentX;
|
||||||
|
initialY = currentY;
|
||||||
|
|
||||||
|
if (event.touches.length != 2) {
|
||||||
|
pinching = false;
|
||||||
|
initialTouchX = event.touches[0].clientX;
|
||||||
|
initialTouchY = event.touches[0].clientY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pinching = true;
|
pinching = true;
|
||||||
apply(1);
|
initialDistance = distance(event);
|
||||||
|
initialTouchX = midpoint(event, "x");
|
||||||
|
initialTouchY = midpoint(event, "y");
|
||||||
});
|
});
|
||||||
element.addEventListener("touchend", (event: TouchEvent) => {
|
canvas.addEventListener("touchmove", (event: TouchEvent) => {
|
||||||
if (event.touches.length == 2) return;
|
if (!pinching) {
|
||||||
pinching = false;
|
apply(currentZoom, [
|
||||||
})
|
initialX + (((event.touches[0].clientX - initialTouchX)/initialZoom)),
|
||||||
element.addEventListener("touchmove", (event: TouchEvent) => {
|
initialY + ((event.touches[0].clientY - initialTouchY)/initialZoom),
|
||||||
if (!pinching) return;
|
]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.touches.length < 2) return;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const currentDistance = distance(event);
|
const currentDistance = distance(event);
|
||||||
const factor = currentDistance / initialDistance;
|
const midX = midpoint(event, "x");
|
||||||
apply(factor);
|
const midY = midpoint(event, "y");
|
||||||
})
|
const ratio = currentDistance / initialDistance;
|
||||||
}
|
const difference = currentDistance - initialDistance;
|
||||||
|
apply(initialZoom * ratio, [initialX + (midX - difference - initialTouchX)/initialZoom, initialY + (midY - difference - initialTouchY)/initialZoom]);
|
||||||
|
});
|
||||||
|
canvas.addEventListener("wheel", (event: WheelEvent) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (!event.shiftKey) {
|
||||||
|
apply(currentZoom, [currentX - event.deltaX, currentY - event.deltaY]);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
apply(currentZoom + (event.deltaY < 0 ? 1 : -1) * 0.1, [initialX, initialY]);
|
||||||
|
});
|
||||||
|
canvas.addEventListener("scroll", (event: MouseEvent) => {
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import * as React from "bloatless-react";
|
import * as React from "bloatless-react";
|
||||||
import * as Utility from "../../Model/Utility/utility";
|
|
||||||
|
|
||||||
import { ViewController } from "../viewController";
|
import { ViewController } from "../viewController";
|
||||||
import { TaskViewModelToEntry } from "../Components/taskEntry";
|
import { TaskViewModelToEntry } from "../Components/taskEntry";
|
||||||
import {
|
import {
|
||||||
@@ -12,12 +10,13 @@ import { TaskCategoryBulkChangeViewModel } from "../../ViewModel/Utility/taskPro
|
|||||||
import TaskViewModel from "../../ViewModel/Pages/taskViewModel";
|
import TaskViewModel from "../../ViewModel/Pages/taskViewModel";
|
||||||
import BoardViewModel from "../../ViewModel/Pages/boardViewModel";
|
import BoardViewModel from "../../ViewModel/Pages/boardViewModel";
|
||||||
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
|
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
|
||||||
|
import * as Utility from "../../Model/Utility/utility";
|
||||||
|
|
||||||
export function BoardKanbanPage(
|
export function BoardKanbanPage(
|
||||||
coreViewModel: CoreViewModel,
|
coreViewModel: CoreViewModel,
|
||||||
boardViewModel: BoardViewModel,
|
boardViewModel: BoardViewModel,
|
||||||
) {
|
) {
|
||||||
const main = PropertyValueList(
|
return PropertyValueList(
|
||||||
"category",
|
"category",
|
||||||
(taskViewModel: TaskViewModel) => taskViewModel.task,
|
(taskViewModel: TaskViewModel) => taskViewModel.task,
|
||||||
boardViewModel.filteredTaskViewModels,
|
boardViewModel.filteredTaskViewModels,
|
||||||
@@ -43,14 +42,12 @@ export function BoardKanbanPage(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
class="kanban-board-wrapper"
|
class="kanban-board-wrapper zoom"
|
||||||
children:append={[categories, categoryNameConverter]}
|
children:append={[categories, categoryNameConverter]}
|
||||||
></div>
|
></div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
Utility.implementPinchZoom(main);
|
|
||||||
return main;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Column(
|
function Column(
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import BoardViewModel, {
|
|||||||
BoardPageTypes,
|
BoardPageTypes,
|
||||||
} from "../../ViewModel/Pages/boardViewModel";
|
} from "../../ViewModel/Pages/boardViewModel";
|
||||||
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
|
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
|
||||||
|
import * as Utility from "../../Model/Utility/utility";
|
||||||
|
|
||||||
export function BoardPage(
|
export function BoardPage(
|
||||||
coreViewModel: CoreViewModel,
|
coreViewModel: CoreViewModel,
|
||||||
@@ -148,6 +149,7 @@ export function BoardPage(
|
|||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content main-content" children:set={pages}></div>
|
<div class="content main-content" children:set={pages}></div>
|
||||||
|
|
||||||
{BoardSettingsModal(coreViewModel, boardViewModel)}
|
{BoardSettingsModal(coreViewModel, boardViewModel)}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import * as React from "bloatless-react";
|
import * as React from "bloatless-react";
|
||||||
import * as Utility from "../../Model/Utility/utility";
|
|
||||||
|
|
||||||
import { ViewController } from "../viewController";
|
import { ViewController } from "../viewController";
|
||||||
import { TaskViewModelToEntry } from "../Components/taskEntry";
|
import { TaskViewModelToEntry } from "../Components/taskEntry";
|
||||||
import {
|
import {
|
||||||
@@ -17,6 +15,7 @@ import {
|
|||||||
import TaskViewModel from "../../ViewModel/Pages/taskViewModel";
|
import TaskViewModel from "../../ViewModel/Pages/taskViewModel";
|
||||||
import BoardViewModel from "../../ViewModel/Pages/boardViewModel";
|
import BoardViewModel from "../../ViewModel/Pages/boardViewModel";
|
||||||
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
|
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
|
||||||
|
import * as Utility from "../../Model/Utility/utility";
|
||||||
|
|
||||||
export function BoardStatusGridPage(
|
export function BoardStatusGridPage(
|
||||||
coreViewModel: CoreViewModel,
|
coreViewModel: CoreViewModel,
|
||||||
@@ -42,8 +41,8 @@ export function BoardStatusGridPage(
|
|||||||
return StatusNameCell(coreViewModel, statusName, index, boardViewModel);
|
return StatusNameCell(coreViewModel, statusName, index, boardViewModel);
|
||||||
};
|
};
|
||||||
|
|
||||||
const main = (
|
return (
|
||||||
<div class="status-page-content">
|
<div class="status-page-content zoom">
|
||||||
<div
|
<div
|
||||||
class="status-name-row"
|
class="status-name-row"
|
||||||
children:append={[statuses, statusNameCellConverter]}
|
children:append={[statuses, statusNameCellConverter]}
|
||||||
@@ -85,8 +84,6 @@ export function BoardStatusGridPage(
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
Utility.implementPinchZoom(main);
|
|
||||||
return main;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function StatusNameCell(
|
function StatusNameCell(
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#chat-page
|
#chat-page
|
||||||
@@ -24,16 +25,14 @@
|
|||||||
padding: var(--content-padding);
|
padding: var(--content-padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
#chat-page > div > #main > #task-page .kanban-board-wrapper,
|
#chat-page > div > #main > #task-page .zoom {
|
||||||
#chat-page > div > #main > #task-page .status-page-content {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
gap: var(--large-gap);
|
gap: var(--large-gap);
|
||||||
|
|
||||||
width: 100%;
|
width: auto;
|
||||||
height: 100%;
|
height: auto;
|
||||||
|
|
||||||
overflow: visible;
|
|
||||||
transform-origin: top left;
|
transform-origin: top left;
|
||||||
|
|
||||||
padding: var(--content-padding);
|
padding: var(--content-padding);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -145,14 +145,14 @@ const englishTranslations = {
|
|||||||
|
|
||||||
filesReceivedCount: (count: number) => `Files processed: ${count}.`,
|
filesReceivedCount: (count: number) => `Files processed: ${count}.`,
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
exportKey: "Encryption key",
|
exportKey: "Encryption key",
|
||||||
exportKeyConfirmation: "Confirm",
|
exportKeyConfirmation: "Confirm",
|
||||||
downloadFileButton: "Download",
|
downloadFileButton: "Download",
|
||||||
importFileButton: "Import",
|
importFileButton: "Import",
|
||||||
decryptImportButton: "Decrypt",
|
decryptImportButton: "Decrypt",
|
||||||
incorrectPassphraseError: "The encryption key is incorrect",
|
incorrectPassphraseError: "The encryption key is incorrect",
|
||||||
},
|
},
|
||||||
|
|
||||||
storage: {
|
storage: {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import ConnectionModel from "../../Model/Global/connectionModel";
|
|||||||
import ChatListModel from "../../Model/Chat/chatListModel";
|
import ChatListModel from "../../Model/Chat/chatListModel";
|
||||||
|
|
||||||
export default class CoreViewModel {
|
export default class CoreViewModel {
|
||||||
readonly BUILD = "Build 26.08.30.C";
|
readonly BUILD = "Build 26.08.30.D";
|
||||||
|
|
||||||
translations: Translations;
|
translations: Translations;
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export default class FileTransferViewModel extends Context {
|
|||||||
exportKey: React.State<string> = new React.State("");
|
exportKey: React.State<string> = new React.State("");
|
||||||
exportKeyConfirmation: React.State<string> = new React.State("");
|
exportKeyConfirmation: React.State<string> = new React.State("");
|
||||||
|
|
||||||
importedFile: React.State<File|undefined> = new React.State(undefined);
|
importedFile: React.State<File | undefined> = new React.State(undefined);
|
||||||
importedFileString: React.State<string> = new React.State("");
|
importedFileString: React.State<string> = new React.State("");
|
||||||
importKey: React.State<string> = new React.State("");
|
importKey: React.State<string> = new React.State("");
|
||||||
isImportKeyCorrect: React.State<boolean> = new React.State(true);
|
isImportKeyCorrect: React.State<boolean> = new React.State(true);
|
||||||
@@ -71,21 +71,20 @@ export default class FileTransferViewModel extends Context {
|
|||||||
this.receivingTransferChannel.value == "" ||
|
this.receivingTransferChannel.value == "" ||
|
||||||
this.receivingTransferKey.value == "",
|
this.receivingTransferKey.value == "",
|
||||||
);
|
);
|
||||||
|
|
||||||
cannotExport: React.State<boolean> = React.createProxyState(
|
cannotExport: React.State<boolean> = React.createProxyState(
|
||||||
[this.exportKey, this.exportKeyConfirmation],
|
[this.exportKey, this.exportKeyConfirmation],
|
||||||
() =>
|
() =>
|
||||||
this.exportKey.value == "" || this.exportKey.value != this.exportKeyConfirmation.value
|
this.exportKey.value == "" ||
|
||||||
|
this.exportKey.value != this.exportKeyConfirmation.value,
|
||||||
);
|
);
|
||||||
cannotImport: React.State<boolean> = React.createProxyState(
|
cannotImport: React.State<boolean> = React.createProxyState(
|
||||||
[this.importedFile],
|
[this.importedFile],
|
||||||
() =>
|
() => this.importedFile.value == undefined,
|
||||||
this.importedFile.value == undefined
|
|
||||||
);
|
);
|
||||||
cannotDecryptImport: React.State<boolean> = React.createProxyState(
|
cannotDecryptImport: React.State<boolean> = React.createProxyState(
|
||||||
[this.importKey],
|
[this.importKey],
|
||||||
() =>
|
() => this.importKey.value == "",
|
||||||
this.importKey.value == ""
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// handlers
|
// handlers
|
||||||
@@ -136,142 +135,149 @@ export default class FileTransferViewModel extends Context {
|
|||||||
};
|
};
|
||||||
|
|
||||||
downloadFile = async (): Promise<void> => {
|
downloadFile = async (): Promise<void> => {
|
||||||
const date = new Date().toISOString().split("T")[0];
|
const date = new Date().toISOString().split("T")[0];
|
||||||
|
|
||||||
const backup: Blob = await this.coreViewModel.fileTransferModel.generateBackup(this.selectedPaths.value.values(), this.exportKey.value);
|
const backup: Blob =
|
||||||
const anchor = document.createElement("a");
|
await this.coreViewModel.fileTransferModel.generateBackup(
|
||||||
anchor.href = window.URL.createObjectURL(backup);
|
this.selectedPaths.value.values(),
|
||||||
anchor.download = `comms-${date}.bak`;
|
this.exportKey.value,
|
||||||
anchor.click();
|
);
|
||||||
}
|
const anchor = document.createElement("a");
|
||||||
|
anchor.href = window.URL.createObjectURL(backup);
|
||||||
|
anchor.download = `comms-${date}.bak`;
|
||||||
|
anchor.click();
|
||||||
|
};
|
||||||
|
|
||||||
updateImportSelection = (): void => {
|
updateImportSelection = (): void => {
|
||||||
const input = document.getElementById("file-transfer-input");
|
const input = document.getElementById("file-transfer-input");
|
||||||
if (!input) return;
|
if (!input) return;
|
||||||
if (!(input instanceof HTMLInputElement)) return;
|
if (!(input instanceof HTMLInputElement)) return;
|
||||||
|
|
||||||
const file = input.files[0];
|
const file = input.files[0];
|
||||||
this.importedFile.value = file;
|
this.importedFile.value = file;
|
||||||
}
|
};
|
||||||
|
|
||||||
importFile = (): void => {
|
importFile = (): void => {
|
||||||
const file = this.importedFile.value;
|
const file = this.importedFile.value;
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.readAsText(file, "utf8");
|
reader.readAsText(file, "utf8");
|
||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
const result = reader.result;
|
const result = reader.result;
|
||||||
this.importedFileString.value = result.toString();
|
this.importedFileString.value = result.toString();
|
||||||
this.showImportDecryptDataModal();
|
this.showImportDecryptDataModal();
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
decryptImport = async (): Promise<void> => {
|
decryptImport = async (): Promise<void> => {
|
||||||
const fileString = this.importedFileString.value;
|
const fileString = this.importedFileString.value;
|
||||||
const key = this.importKey.value;
|
const key = this.importKey.value;
|
||||||
if (!fileString || !key) return;
|
if (!fileString || !key) return;
|
||||||
|
|
||||||
this.cannotDecryptImport.value = true;
|
this.cannotDecryptImport.value = true;
|
||||||
try {
|
try {
|
||||||
await this.coreViewModel.fileTransferModel.handleBackupFile(fileString, key);
|
await this.coreViewModel.fileTransferModel.handleBackupFile(
|
||||||
window.location.reload();
|
fileString,
|
||||||
} catch (e) {
|
key,
|
||||||
console.error(e);
|
);
|
||||||
this.isImportKeyCorrect.value = false;
|
window.location.reload();
|
||||||
this.cannotDecryptImport.value = false;
|
} catch (e) {
|
||||||
}
|
console.error(e);
|
||||||
}
|
this.isImportKeyCorrect.value = false;
|
||||||
|
this.cannotDecryptImport.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// view
|
// view
|
||||||
showDirectionSelectionModal = (): void => {
|
showDirectionSelectionModal = (): void => {
|
||||||
this.coreViewModel.context = this;
|
this.coreViewModel.context = this;
|
||||||
this.presentedModal.value = FileTransferModals.DirectionSelection;
|
this.presentedModal.value = FileTransferModals.DirectionSelection;
|
||||||
this.getOptions();
|
this.getOptions();
|
||||||
};
|
};
|
||||||
|
|
||||||
showFileSelectionModal = (): void => {
|
showFileSelectionModal = (): void => {
|
||||||
this.presentedModal.value = FileTransferModals.FileSelection;
|
this.presentedModal.value = FileTransferModals.FileSelection;
|
||||||
};
|
};
|
||||||
|
|
||||||
showTransferDataModal = (): void => {
|
showTransferDataModal = (): void => {
|
||||||
this.presentedModal.value = FileTransferModals.TransferDataDisplay;
|
this.presentedModal.value = FileTransferModals.TransferDataDisplay;
|
||||||
this.getTransferData();
|
this.getTransferData();
|
||||||
this.coreViewModel.fileTransferModel.prepareToSend();
|
this.coreViewModel.fileTransferModel.prepareToSend();
|
||||||
};
|
};
|
||||||
|
|
||||||
initiateTransfer = (): void => {
|
initiateTransfer = (): void => {
|
||||||
this.presentedModal.value = FileTransferModals.TransferDisplay;
|
this.presentedModal.value = FileTransferModals.TransferDisplay;
|
||||||
this.didNotFinishSending.value = true;
|
this.didNotFinishSending.value = true;
|
||||||
this.filePathsSent.clear();
|
this.filePathsSent.clear();
|
||||||
|
|
||||||
this.coreViewModel.fileTransferModel.sendFiles(
|
this.coreViewModel.fileTransferModel.sendFiles(
|
||||||
this.selectedPaths.value.values(),
|
this.selectedPaths.value.values(),
|
||||||
(path: string) => {
|
(path: string) => {
|
||||||
this.filePathsSent.add(path);
|
this.filePathsSent.add(path);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
this.didNotFinishSending.value = false;
|
this.didNotFinishSending.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
showTransferDataInputModal = (): void => {
|
showTransferDataInputModal = (): void => {
|
||||||
this.presentedModal.value = FileTransferModals.TransferDataInput;
|
this.presentedModal.value = FileTransferModals.TransferDataInput;
|
||||||
};
|
};
|
||||||
|
|
||||||
showExportSelectionModal = (): void => {
|
showExportSelectionModal = (): void => {
|
||||||
this.presentedModal.value = FileTransferModals.ExportFileSelection;
|
this.presentedModal.value = FileTransferModals.ExportFileSelection;
|
||||||
};
|
};
|
||||||
|
|
||||||
showExportModal = (): void => {
|
showExportModal = (): void => {
|
||||||
this.presentedModal.value = FileTransferModals.Export;
|
this.presentedModal.value = FileTransferModals.Export;
|
||||||
};
|
};
|
||||||
|
|
||||||
showImportModal = (): void => {
|
showImportModal = (): void => {
|
||||||
this.presentedModal.value = FileTransferModals.ImportSelection;
|
this.presentedModal.value = FileTransferModals.ImportSelection;
|
||||||
};
|
};
|
||||||
|
|
||||||
showImportDecryptDataModal = (): void => {
|
showImportDecryptDataModal = (): void => {
|
||||||
this.presentedModal.value = FileTransferModals.ImportDecryptData;
|
this.presentedModal.value = FileTransferModals.ImportDecryptData;
|
||||||
};
|
};
|
||||||
|
|
||||||
prepareReceivingData = (): void => {
|
prepareReceivingData = (): void => {
|
||||||
if (this.cannotPrepareToReceive.value == true) return;
|
if (this.cannotPrepareToReceive.value == true) return;
|
||||||
this.presentedModal.value = FileTransferModals.ReceptionDisplay;
|
this.presentedModal.value = FileTransferModals.ReceptionDisplay;
|
||||||
this.filePathsReceived.clear();
|
this.filePathsReceived.clear();
|
||||||
|
|
||||||
const transferData: TransferData = {
|
const transferData: TransferData = {
|
||||||
channel: this.receivingTransferChannel.value,
|
channel: this.receivingTransferChannel.value,
|
||||||
key: this.receivingTransferKey.value,
|
key: this.receivingTransferKey.value,
|
||||||
};
|
};
|
||||||
this.coreViewModel.fileTransferModel.prepareToReceive(transferData);
|
this.coreViewModel.fileTransferModel.prepareToReceive(transferData);
|
||||||
};
|
};
|
||||||
|
|
||||||
// exit
|
// exit
|
||||||
close = (): void => {
|
close = (): void => {
|
||||||
this.coreViewModel.closeContext(this.contextId);
|
this.coreViewModel.closeContext(this.contextId);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleContextClose = (): void => {
|
handleContextClose = (): void => {
|
||||||
this.presentedModal.value = undefined;
|
this.presentedModal.value = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
// init
|
// init
|
||||||
constructor(public readonly coreViewModel: CoreViewModel) {
|
constructor(public readonly coreViewModel: CoreViewModel) {
|
||||||
super("file-transfer");
|
super("file-transfer");
|
||||||
|
|
||||||
this.coreViewModel.fileTransferModel.fileHandlerManager.setHandler(
|
this.coreViewModel.fileTransferModel.fileHandlerManager.setHandler(
|
||||||
"file-transfer-view-model",
|
"file-transfer-view-model",
|
||||||
this.handleReceivedFile,
|
this.handleReceivedFile,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.coreViewModel.fileTransferModel.readyToSendHandlerManager.setHandler(
|
this.coreViewModel.fileTransferModel.readyToSendHandlerManager.setHandler(
|
||||||
"file-transfer-view-model",
|
"file-transfer-view-model",
|
||||||
() => this.initiateTransfer(),
|
() => this.initiateTransfer(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// keystrokes
|
// keystrokes
|
||||||
this.registerKeyStroke(CommonKeys.CloseOrCancel, this.close);
|
this.registerKeyStroke(CommonKeys.CloseOrCancel, this.close);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,18 +289,18 @@ export interface FileTransferOption {
|
|||||||
export enum FileTransferModals {
|
export enum FileTransferModals {
|
||||||
DirectionSelection,
|
DirectionSelection,
|
||||||
|
|
||||||
// sending
|
// sending
|
||||||
FileSelection,
|
FileSelection,
|
||||||
TransferDataDisplay,
|
TransferDataDisplay,
|
||||||
TransferDisplay,
|
TransferDisplay,
|
||||||
|
|
||||||
// receiving
|
// receiving
|
||||||
TransferDataInput,
|
TransferDataInput,
|
||||||
ReceptionDisplay,
|
ReceptionDisplay,
|
||||||
|
|
||||||
// export
|
// export
|
||||||
ExportFileSelection,
|
ExportFileSelection,
|
||||||
Export,
|
Export,
|
||||||
ImportSelection,
|
ImportSelection,
|
||||||
ImportDecryptData,
|
ImportDecryptData,
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2,7 +2,6 @@ import * as React from "bloatless-react";
|
|||||||
import "./colors.css";
|
import "./colors.css";
|
||||||
import "./coloredTile.css";
|
import "./coloredTile.css";
|
||||||
import "./base.css";
|
import "./base.css";
|
||||||
import * as Utility from "./Model/Utility/utility";
|
|
||||||
import HomeViewModel from "./ViewModel/Pages/homeViewModel";
|
import HomeViewModel from "./ViewModel/Pages/homeViewModel";
|
||||||
import StorageViewModel from "./ViewModel/Global/storageViewModel";
|
import StorageViewModel from "./ViewModel/Global/storageViewModel";
|
||||||
import SettingsViewModel from "./ViewModel/Global/settingsViewModel";
|
import SettingsViewModel from "./ViewModel/Global/settingsViewModel";
|
||||||
@@ -17,6 +16,7 @@ import { SettingsModal } from "./View/Modals/settingsModal";
|
|||||||
import { DataTransferModalWrapper } from "./View/Modals/dataTransferModal";
|
import { DataTransferModalWrapper } from "./View/Modals/dataTransferModal";
|
||||||
import { ConnectionModal } from "./View/Modals/connectionModal";
|
import { ConnectionModal } from "./View/Modals/connectionModal";
|
||||||
import v1Upgrader from "./Upgrader/v1";
|
import v1Upgrader from "./Upgrader/v1";
|
||||||
|
import * as Utility from "./Model/Utility/utility";
|
||||||
import StorageModel from "./Model/Global/storageModel";
|
import StorageModel from "./Model/Global/storageModel";
|
||||||
import SettingsModel from "./Model/Global/settingsModel";
|
import SettingsModel from "./Model/Global/settingsModel";
|
||||||
import FileTransferModel from "./Model/Global/fileTransferModel";
|
import FileTransferModel from "./Model/Global/fileTransferModel";
|
||||||
@@ -100,3 +100,4 @@ document
|
|||||||
StorageModal(coreViewModel, storageViewModel),
|
StorageModal(coreViewModel, storageViewModel),
|
||||||
SettingsModal(coreViewModel, settingsViewModel),
|
SettingsModal(coreViewModel, settingsViewModel),
|
||||||
);
|
);
|
||||||
|
Utility.implementPinchZoom(".zoom");
|
||||||
|
|||||||
Reference in New Issue
Block a user