allow correcting file transfer data if no files were received

This commit is contained in:
marlon-erler
2026-09-05 02:26:10 +02:00
parent dbc3fd225d
commit e4d162f0ab
9 changed files with 11778 additions and 8849 deletions
+49 -49
View File
@@ -335,64 +335,64 @@ export function implementPinchZoom(canvas: HTMLElement) {
}
canvas.addEventListener("touchstart", (event: TouchEvent) => {
(document.activeElement as HTMLElement).blur();
(document.activeElement as HTMLElement).blur();
if (lastElement != undefined && lastElement != element()) reset();
lastElement = element();
if (lastElement != undefined && lastElement != element()) reset();
lastElement = element();
initialZoom = currentZoom;
initialX = currentX;
initialY = currentY;
initialZoom = currentZoom;
initialX = currentX;
initialY = currentY;
if (event.touches.length != 2) {
pinching = false;
initialTouchX = event.touches[0].clientX;
initialTouchY = event.touches[0].clientY;
return;
}
if (event.touches.length != 2) {
pinching = false;
initialTouchX = event.touches[0].clientX;
initialTouchY = event.touches[0].clientY;
return;
}
pinching = true;
initialDistance = distance(event);
initialTouchX = midpoint(event, "x");
initialTouchY = midpoint(event, "y");
pinching = true;
initialDistance = distance(event);
initialTouchX = midpoint(event, "x");
initialTouchY = midpoint(event, "y");
});
canvas.addEventListener("touchmove", (event: TouchEvent) => {
if (!pinching) {
apply(currentZoom, [
initialX +
(event.touches[0].clientX - initialTouchX) / initialZoom,
initialY +
(event.touches[0].clientY - initialTouchY) / initialZoom,
]);
return;
}
if (event.touches.length < 2) return;
event.preventDefault();
const currentDistance = distance(event);
const midX = midpoint(event, "x");
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,
]);
if (!pinching) {
apply(currentZoom, [
initialX +
(event.touches[0].clientX - initialTouchX) / initialZoom,
initialY +
(event.touches[0].clientY - initialTouchY) / initialZoom,
]);
return;
}
if (event.touches.length < 2) return;
event.preventDefault();
const currentDistance = distance(event);
const midX = midpoint(event, "x");
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,
]);
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();
event.preventDefault();
});
}
+114 -112
View File
@@ -45,125 +45,127 @@ export function BoardPage(
}),
);
const wrapper = <div class="content main-content" children:set={pages}></div>
Utility.implementPinchZoom(wrapper);
const wrapper = (
<div class="content main-content" children:set={pages}></div>
);
Utility.implementPinchZoom(wrapper);
// task modal
const taskSettingsModal = React.createProxyState(
[boardViewModel.selectedTaskViewModel],
() => {
if (boardViewModel.selectedTaskViewModel.value == undefined) {
return <div></div>;
} else {
ViewController.setFocusWithDelay();
[boardViewModel.selectedTaskViewModel],
() => {
if (boardViewModel.selectedTaskViewModel.value == undefined) {
return <div></div>;
} else {
ViewController.setFocusWithDelay();
return TaskSettingsModal(
coreViewModel,
boardViewModel.selectedTaskViewModel.value,
);
}
},
return TaskSettingsModal(
coreViewModel,
boardViewModel.selectedTaskViewModel.value,
);
}
},
);
return (
<div class="pane">
<div class="toolbar">
<span>
<button
class="ghost board-close-button"
aria-label={
coreViewModel.translations.chatPage.task
.closeBoardButtonAudioLabel
}
on:click={boardViewModel.close}
>
<span class="icon">arrow_back</span>
</button>
<button
class="ghost board-toggle-button inset-outline"
aria-label={
coreViewModel.translations.chatPage.task
.toggleBoardButtonAudioLabel
}
on:click={
boardViewModel.taskPageViewModel.toggleBoardList
}
toggle:selected={
boardViewModel.taskPageViewModel.isShowingBoadList
}
>
<span class="icon">dock_to_right</span>
</button>
<button
class="ghost"
aria-label={
coreViewModel.translations.chatPage.task
.boardSettingsHeadline
}
on:click={boardViewModel.showSettings}
>
<span class="icon">settings</span>
</button>
</span>
<span class="scroll-h ribbon">
{BoardViewToggleButton(
coreViewModel.translations.chatPage.task
.listViewButtonAudioLabel,
"view_list",
BoardPageTypes.List,
boardViewModel,
)}
{BoardViewToggleButton(
coreViewModel.translations.chatPage.task
.kanbanViewButtonAudioLabel,
"view_kanban",
BoardPageTypes.Kanban,
boardViewModel,
)}
{BoardViewToggleButton(
coreViewModel.translations.chatPage.task
.statusViewButtonAudioLabel,
"grid_view",
BoardPageTypes.StatusGrid,
boardViewModel,
)}
</span>
<span>
<button
class="ghost inset-outline"
aria-label={
coreViewModel.translations.chatPage.task
.filterTasksButtonAudioLabel
}
on:click={boardViewModel.showFilterModal}
toggle:selected={boardViewModel.isFilterActive}
>
<span class="icon">filter_alt</span>
</button>
<button
class="ghost"
aria-label={
coreViewModel.translations.chatPage.task
.createTaskButtonAudioLabel
}
on:click={boardViewModel.createTask}
>
<span class="icon">add</span>
</button>
</span>
</div>
<div class="pane">
<div class="toolbar">
<span>
<button
class="ghost board-close-button"
aria-label={
coreViewModel.translations.chatPage.task
.closeBoardButtonAudioLabel
}
on:click={boardViewModel.close}
>
<span class="icon">arrow_back</span>
</button>
<button
class="ghost board-toggle-button inset-outline"
aria-label={
coreViewModel.translations.chatPage.task
.toggleBoardButtonAudioLabel
}
on:click={
boardViewModel.taskPageViewModel.toggleBoardList
}
toggle:selected={
boardViewModel.taskPageViewModel.isShowingBoadList
}
>
<span class="icon">dock_to_right</span>
</button>
<button
class="ghost"
aria-label={
coreViewModel.translations.chatPage.task
.boardSettingsHeadline
}
on:click={boardViewModel.showSettings}
>
<span class="icon">settings</span>
</button>
</span>
<span class="scroll-h ribbon">
{BoardViewToggleButton(
coreViewModel.translations.chatPage.task
.listViewButtonAudioLabel,
"view_list",
BoardPageTypes.List,
boardViewModel,
)}
{BoardViewToggleButton(
coreViewModel.translations.chatPage.task
.kanbanViewButtonAudioLabel,
"view_kanban",
BoardPageTypes.Kanban,
boardViewModel,
)}
{BoardViewToggleButton(
coreViewModel.translations.chatPage.task
.statusViewButtonAudioLabel,
"grid_view",
BoardPageTypes.StatusGrid,
boardViewModel,
)}
</span>
<span>
<button
class="ghost inset-outline"
aria-label={
coreViewModel.translations.chatPage.task
.filterTasksButtonAudioLabel
}
on:click={boardViewModel.showFilterModal}
toggle:selected={boardViewModel.isFilterActive}
>
<span class="icon">filter_alt</span>
</button>
<button
class="ghost"
aria-label={
coreViewModel.translations.chatPage.task
.createTaskButtonAudioLabel
}
on:click={boardViewModel.createTask}
>
<span class="icon">add</span>
</button>
</span>
</div>
{wrapper}
{wrapper}
{BoardSettingsModal(coreViewModel, boardViewModel)}
{SearchModal(
coreViewModel,
boardViewModel.searchViewModel,
coreViewModel.translations.chatPage.task.filterTasksHeadline,
TaskViewModelToEntry,
boardViewModel.isPresentingFilterModal,
)}
<div children:set={taskSettingsModal}></div>
</div>
);
{BoardSettingsModal(coreViewModel, boardViewModel)}
{SearchModal(
coreViewModel,
boardViewModel.searchViewModel,
coreViewModel.translations.chatPage.task.filterTasksHeadline,
TaskViewModelToEntry,
boardViewModel.isPresentingFilterModal,
)}
<div children:set={taskSettingsModal}></div>
</div>
);
}
Binary file not shown.
+25 -12
View File
@@ -375,7 +375,7 @@ function TransferDisplayModal(
coreViewModel.translations.dataTransferModal
.transferDataHeadline
}
</h2>
</h2>
<p
class="secondary"
@@ -394,11 +394,11 @@ function TransferDisplayModal(
coreViewModel.translations.dataTransferModal
.allFilesSent
}
</p>
</p>
<hr></hr>
<div class="flex-column gap content-margin-bottom">
<hr></hr>
<div class="flex-column gap content-margin-bottom">
<div class="tile">
<span class="icon">forum</span>
<div>
@@ -514,8 +514,8 @@ function TransferDataInputModal(
.transferChannelHeadline
}
</span>
<input
type="number"
<input
type="number"
on:enter={
fileTransferViewModel.prepareReceivingData
}
@@ -536,7 +536,7 @@ function TransferDataInputModal(
}
</span>
<input
type="number"
type="number"
on:enter={
fileTransferViewModel.prepareReceivingData
}
@@ -612,10 +612,23 @@ function DataReceptionModal(
]}
></div>
</main>
<button on:click={ViewController.reload}>
{coreViewModel.translations.general.reloadAppButton}
<span class="icon">refresh</span>
</button>
<div class="flex-row width-100">
<button
class="flex"
on:click={
fileTransferViewModel.showTransferDataInputModal
}
toggle:disabled={
fileTransferViewModel.cannotExitReception
}
>
{coreViewModel.translations.general.backButton}
</button>
<button class="flex" on:click={ViewController.reload}>
{coreViewModel.translations.general.reloadAppButton}
<span class="icon">refresh</span>
</button>
</div>
</div>
</div>
);
@@ -71,6 +71,10 @@ export default class FileTransferViewModel extends Context {
this.receivingTransferChannel.value == "" ||
this.receivingTransferKey.value == "",
);
cannotExitReception: React.State<boolean> = React.createProxyState(
[this.filePathsReceived],
() => this.filePathsReceived.value.size > 0,
);
cannotExport: React.State<boolean> = React.createProxyState(
[this.exportKey, this.exportKeyConfirmation],