diff --git a/bun.lockb b/bun.lockb index 359d9827..143adbbb 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/node_modules/@types/hammerjs/LICENSE b/node_modules/@types/hammerjs/LICENSE new file mode 100644 index 00000000..9e841e7a --- /dev/null +++ b/node_modules/@types/hammerjs/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/node_modules/@types/hammerjs/README.md b/node_modules/@types/hammerjs/README.md new file mode 100644 index 00000000..0d5db159 --- /dev/null +++ b/node_modules/@types/hammerjs/README.md @@ -0,0 +1,15 @@ +# Installation +> `npm install --save @types/hammerjs` + +# Summary +This package contains type definitions for hammerjs (http://hammerjs.github.io/). + +# Details +Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/hammerjs. + +### Additional Details + * Last updated: Mon, 07 Oct 2024 22:07:58 GMT + * Dependencies: none + +# Credits +These definitions were written by [Han Lin Yap](https://github.com/codler). diff --git a/node_modules/@types/hammerjs/index.d.ts b/node_modules/@types/hammerjs/index.d.ts new file mode 100644 index 00000000..83372314 --- /dev/null +++ b/node_modules/@types/hammerjs/index.d.ts @@ -0,0 +1,345 @@ +declare var Hammer: HammerStatic; + +declare module "hammerjs" { + export = Hammer; +} + +interface HammerStatic { + new(element: HTMLElement | SVGElement, options?: HammerOptions): HammerManager; + + defaults: HammerDefaults; + + VERSION: number; + + INPUT_START: 1; + INPUT_MOVE: 2; + INPUT_END: 4; + INPUT_CANCEL: 8; + + STATE_POSSIBLE: 1; + STATE_BEGAN: 2; + STATE_CHANGED: 4; + STATE_ENDED: 8; + STATE_RECOGNIZED: 8; // same as STATE_ENDED + STATE_CANCELLED: 16; + STATE_FAILED: 32; + + DIRECTION_NONE: 1; + DIRECTION_LEFT: 2; + DIRECTION_RIGHT: 4; + DIRECTION_UP: 8; + DIRECTION_DOWN: 16; + DIRECTION_HORIZONTAL: 6; // DIRECTION_LEFT | DIRECTION_RIGHT + DIRECTION_VERTICAL: 24; // DIRECTION_UP | DIRECTION_DOWN + DIRECTION_ALL: 30; // DIRECTION_HORIZONTAL | DIRECTION_VERTICAL + + Manager: HammerManagerConstructor; + Input: HammerInput; + TouchAction: TouchAction; + + TouchInput: TouchInput; + MouseInput: MouseInput; + PointerEventInput: PointerEventInput; + TouchMouseInput: TouchMouseInput; + SingleTouchInput: SingleTouchInput; + + Recognizer: RecognizerStatic; + AttrRecognizer: AttrRecognizerStatic; + Tap: TapRecognizerStatic; + Pan: PanRecognizerStatic; + Swipe: SwipeRecognizerStatic; + Pinch: PinchRecognizerStatic; + Rotate: RotateRecognizerStatic; + Press: PressRecognizerStatic; + + on(target: EventTarget, types: string, handler: Function): void; + off(target: EventTarget, types: string, handler: Function): void; + each(obj: any, iterator: Function, context: any): void; + merge(dest: any, src: any): any; + extend(dest: any, src: any, merge: boolean): any; + inherit(child: Function, base: Function, properties: any): any; + bindFn(fn: Function, context: any): Function; + prefixed(obj: any, property: string): string; +} + +type RecognizerTuple = + | [RecognizerStatic] + | [RecognizerStatic, RecognizerOptions] + | [RecognizerStatic, RecognizerOptions, string | string[]] + | [RecognizerStatic, RecognizerOptions, string | string[], (string | Recognizer) | Array]; + +interface HammerDefaults extends HammerOptions { + domEvents: boolean; + enable: boolean; + preset: RecognizerTuple[]; + touchAction: string; + cssProps: CssProps; + + inputClass: HammerInput; + inputTarget: EventTarget; +} + +interface CssProps { + contentZooming: string; + tapHighlightColor: string; + touchCallout: string; + touchSelect: string; + userDrag: string; + userSelect: string; +} + +interface HammerOptions { + cssProps?: CssProps | undefined; + domEvents?: boolean | undefined; + enable?: boolean | ((manager: HammerManager) => boolean) | undefined; + preset?: RecognizerTuple[] | undefined; + touchAction?: string | undefined; + recognizers?: RecognizerTuple[] | undefined; + + inputClass?: HammerInput | undefined; + inputTarget?: EventTarget | undefined; +} + +interface HammerManagerConstructor { + new(element: EventTarget, options?: HammerOptions): HammerManager; +} + +interface HammerListener { + (event: HammerInput): void; +} + +interface HammerManager { + add(recogniser: Recognizer): Recognizer; + add(recogniser: Recognizer): HammerManager; + add(recogniser: Recognizer[]): Recognizer; + add(recogniser: Recognizer[]): HammerManager; + destroy(): void; + emit(event: string, data: any): void; + get(recogniser: Recognizer): Recognizer; + get(recogniser: string): Recognizer; + off(events: string, handler?: HammerListener): void; + on(events: string, handler: HammerListener): void; + recognize(inputData: any): void; + remove(recogniser: Recognizer): HammerManager; + remove(recogniser: string): HammerManager; + set(options: HammerOptions): HammerManager; + stop(force: boolean): void; +} + +declare class HammerInput { + constructor(manager: HammerManager, callback: Function); + + destroy(): void; + handler(): void; + init(): void; + + /** Name of the event. Like panstart. */ + type: string; + + /** Movement of the X axis. */ + deltaX: number; + + /** Movement of the Y axis. */ + deltaY: number; + + /** Total time in ms since the first input. */ + deltaTime: number; + + /** Distance moved. */ + distance: number; + + /** Angle moved. */ + angle: number; + + /** Velocity on the X axis, in px/ms. */ + velocityX: number; + + /** Velocity on the Y axis, in px/ms */ + velocityY: number; + + /** Highest velocityX/Y value. */ + velocity: number; + + overallVelocity: number; + + overallVelocityX: number; + + overallVelocityY: number; + + /** Direction moved. Matches the DIRECTION constants. */ + direction: number; + + /** Direction moved from it's starting point. Matches the DIRECTION constants. */ + offsetDirection: number; + + /** Scaling that has been done when multi-touch. 1 on a single touch. */ + scale: number; + + /** Rotation that has been done when multi-touch. 0 on a single touch. */ + rotation: number; + + /** Center position for multi-touch, or just the single pointer. */ + center: HammerPoint; + + /** The amount of multi-taps being recognized. */ + tapCount?: number; + + /** Source event object, type TouchEvent, MouseEvent or PointerEvent. */ + srcEvent: TouchEvent | MouseEvent | PointerEvent; + + /** Target that received the event. */ + target: HTMLElement; + + /** Primary pointer type, could be touch, mouse, pen or kinect. */ + pointerType: string; + + /** Event type, matches the INPUT constants. */ + eventType: + | HammerStatic["INPUT_START"] + | HammerStatic["INPUT_MOVE"] + | HammerStatic["INPUT_END"] + | HammerStatic["INPUT_CANCEL"]; + + /** true when the first input. */ + isFirst: boolean; + + /** true when the final (last) input. */ + isFinal: boolean; + + /** Array with all pointers, including the ended pointers (touchend, mouseup). */ + pointers: any[]; + + /** Array with all new/moved/lost pointers. */ + changedPointers: any[]; + + /** Maximum number of pointers detected in the gesture */ + maxPointers: number; + + /** Timestamp of a gesture */ + timeStamp: number; + + /** Reference to the srcEvent.preventDefault() method. Only for experts! */ + preventDefault: Function; +} + +declare class MouseInput extends HammerInput { + constructor(manager: HammerManager, callback: Function); +} + +declare class PointerEventInput extends HammerInput { + constructor(manager: HammerManager, callback: Function); +} + +declare class SingleTouchInput extends HammerInput { + constructor(manager: HammerManager, callback: Function); +} + +declare class TouchInput extends HammerInput { + constructor(manager: HammerManager, callback: Function); +} + +declare class TouchMouseInput extends HammerInput { + constructor(manager: HammerManager, callback: Function); +} + +interface RecognizerOptions { + direction?: number | undefined; + enable?: boolean | ((recognizer: Recognizer, inputData: HammerInput) => boolean) | undefined; + event?: string | undefined; + interval?: number | undefined; + pointers?: number | undefined; + posThreshold?: number | undefined; + taps?: number | undefined; + threshold?: number | undefined; + time?: number | undefined; + velocity?: number | undefined; +} + +interface RecognizerStatic { + new(options?: RecognizerOptions): Recognizer; +} + +interface Recognizer { + defaults: any; + + canEmit(): boolean; + canRecognizeWith(otherRecognizer: Recognizer): boolean; + dropRecognizeWith(otherRecognizer: Recognizer | Recognizer[] | string): Recognizer; + dropRequireFailure(otherRecognizer: Recognizer | Recognizer[] | string): Recognizer; + emit(input: HammerInput): void; + getTouchAction(): any[]; + hasRequireFailures(): boolean; + process(inputData: HammerInput): string; + recognize(inputData: HammerInput): void; + recognizeWith(otherRecognizer: Recognizer | Recognizer[] | string): Recognizer; + requireFailure(otherRecognizer: Recognizer | Recognizer[] | string): Recognizer; + reset(): void; + set(options?: RecognizerOptions): Recognizer; + tryEmit(input: HammerInput): void; +} + +interface AttrRecognizerStatic { + attrTest(input: HammerInput): boolean; + process(input: HammerInput): any; +} + +interface AttrRecognizer extends Recognizer { + new(options?: RecognizerOptions): AttrRecognizer; +} + +interface PanRecognizerStatic { + new(options?: RecognizerOptions): PanRecognizer; +} + +interface PanRecognizer extends AttrRecognizer { +} + +interface PinchRecognizerStatic { + new(options?: RecognizerOptions): PinchRecognizer; +} + +interface PinchRecognizer extends AttrRecognizer { +} + +interface PressRecognizerStatic { + new(options?: RecognizerOptions): PressRecognizer; +} + +interface PressRecognizer extends AttrRecognizer { +} + +interface RotateRecognizerStatic { + new(options?: RecognizerOptions): RotateRecognizer; +} + +interface RotateRecognizer extends AttrRecognizer { +} + +interface SwipeRecognizerStatic { + new(options?: RecognizerOptions): SwipeRecognizer; +} + +interface SwipeRecognizer extends AttrRecognizer { +} + +interface TapRecognizerStatic { + new(options?: RecognizerOptions): TapRecognizer; +} + +interface TapRecognizer extends AttrRecognizer { +} + +declare class TouchAction { + constructor(manager: HammerManager, value: string); + + compute(): string; + preventDefaults(input: HammerInput): void; + preventSrc(srcEvent: any): void; + set(value: string): void; + update(): void; +} + +interface HammerPoint { + x: number; + y: number; +} diff --git a/node_modules/@types/hammerjs/package.json b/node_modules/@types/hammerjs/package.json new file mode 100644 index 00000000..5b9abafa --- /dev/null +++ b/node_modules/@types/hammerjs/package.json @@ -0,0 +1,25 @@ +{ + "name": "@types/hammerjs", + "version": "2.0.46", + "description": "TypeScript definitions for hammerjs", + "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/hammerjs", + "license": "MIT", + "contributors": [ + { + "name": "Han Lin Yap", + "githubUsername": "codler", + "url": "https://github.com/codler" + } + ], + "main": "", + "types": "index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/DefinitelyTyped/DefinitelyTyped.git", + "directory": "types/hammerjs" + }, + "scripts": {}, + "dependencies": {}, + "typesPublisherContentHash": "940610a83da8b99e3035028564e9536f6c44025e0387899fdaafa00474821be4", + "typeScriptVersion": "4.8" +} \ No newline at end of file diff --git a/package.json b/package.json index c2ae3f0b..feff6f07 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "dependencies": { + "@types/hammerjs": "^2.0.46", "@types/uuid": "^10.0.0", "bloatless-react": "1.3.14", "esbuild": "^0.23.1", diff --git a/src/.index.tsx.swp b/src/.index.tsx.swp new file mode 100644 index 00000000..91f0b2a2 Binary files /dev/null and b/src/.index.tsx.swp differ diff --git a/src/Model/Utility/utility.ts b/src/Model/Utility/utility.ts index 8ccde202..baf50031 100644 --- a/src/Model/Utility/utility.ts +++ b/src/Model/Utility/utility.ts @@ -1,4 +1,5 @@ import { checkIsValidObject, checkMatchesObjectStructure } from "./typeSafety"; +import * as Hammer from "hammerjs"; export interface Stringifiable { toString(): string; @@ -323,76 +324,84 @@ export function implementPinchZoom(canvas: HTMLElement) { 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); + function apply(factor: number, _offset?: [number, number]) { + if (factor < MIN) return apply(MIN, _offset); + if (factor > MAX) return apply(5, _offset); - 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; + let x: number, y: number; + if (_offset) [x, y] = _offset; + else { + x = currentX + y = currentY + } + element().style.transform = `scale(${factor.toString()}) translate(${x}px, ${y}px)`; + currentX = x; + currentY = y; + currentZoom = factor; } - canvas.addEventListener("touchstart", (event: TouchEvent) => { - (document.activeElement as HTMLElement).blur(); - - if (lastElement != undefined && lastElement != element()) reset(); - lastElement = element(); - - 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; - 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, - ]); - }); 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(); + + initialZoom = currentZoom; + initialX = currentX; + initialY = currentY; + + if (!event.shiftKey) { + apply(currentZoom, [ + currentX - event.deltaX, + currentY - event.deltaY, + ]); + return; + } + apply(currentZoom - event.deltaY * 0.01); }); canvas.addEventListener("scroll", (event: MouseEvent) => { - event.preventDefault(); + event.preventDefault(); + }); + + canvas.addEventListener("touchstart", (event: TouchEvent) => { + (document.activeElement as HTMLElement).blur(); + + if (lastElement != undefined && lastElement != element()) reset(); + lastElement = element(); + + 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; + 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, + ]); }); } diff --git a/src/ViewModel/Global/.coreViewModel.ts.swp b/src/ViewModel/Global/.coreViewModel.ts.swp index 5196f81c..f1deea67 100644 Binary files a/src/ViewModel/Global/.coreViewModel.ts.swp and b/src/ViewModel/Global/.coreViewModel.ts.swp differ diff --git a/src/ViewModel/Global/.fileTransferViewModel.ts.swp b/src/ViewModel/Global/.fileTransferViewModel.ts.swp deleted file mode 100644 index 2b17644e..00000000 Binary files a/src/ViewModel/Global/.fileTransferViewModel.ts.swp and /dev/null differ diff --git a/src/ViewModel/Global/coreViewModel.ts b/src/ViewModel/Global/coreViewModel.ts index 8f897998..6cce6625 100644 --- a/src/ViewModel/Global/coreViewModel.ts +++ b/src/ViewModel/Global/coreViewModel.ts @@ -9,7 +9,7 @@ import ConnectionModel from "../../Model/Global/connectionModel"; import ChatListModel from "../../Model/Chat/chatListModel"; export default class CoreViewModel { - readonly BUILD = "Build 26.09.05.A"; + readonly BUILD = "Build 26.09.06.A"; translations: Translations; diff --git a/src/index.tsx b/src/index.tsx index a44a0c5e..34daa9fe 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -100,4 +100,3 @@ document StorageModal(coreViewModel, storageViewModel), SettingsModal(coreViewModel, settingsViewModel), ); -Utility.implementPinchZoom(".zoom");