Skip to content

Commit

Permalink
add option to just download inline images on long press, fix #2925
Browse files Browse the repository at this point in the history
Also, change the positioning handling for the dropdown, so that it appears underneath the mouse, rather than below the image element
  • Loading branch information
johnbotris committed Apr 12, 2021
1 parent 9df24aa commit da53f7e
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 22 deletions.
23 changes: 15 additions & 8 deletions src/gui/base/DropdownN.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ import stream from "mithril/stream/stream.js"
import type {PosRect} from "./Dropdown"
import {Keys} from "../../api/common/TutanotaConstants"
import {newMouseEvent} from "../HtmlUtils"
import {DomRectReadOnlyPolyfilled} from "./Dropdown"

assertMainOrNode()

export type DropDownChildAttrs = string | NavButtonAttrs | ButtonAttrs;
export type DropdownChildAttrs = string | NavButtonAttrs | ButtonAttrs;


// TODO: add resize listener like in the old Dropdown
export class DropdownN {
children: $ReadOnlyArray<DropDownChildAttrs>;
children: $ReadOnlyArray<DropdownChildAttrs>;
_domDropdown: HTMLElement;
origin: ?PosRect;
maxHeight: number;
Expand All @@ -40,7 +41,7 @@ export class DropdownN {
_isFilterable: boolean;


constructor(lazyChildren: lazy<$ReadOnlyArray<DropDownChildAttrs>>, width: number) {
constructor(lazyChildren: lazy<$ReadOnlyArray<DropdownChildAttrs>>, width: number) {
this.children = []
this.maxHeight = 0
this._width = width
Expand Down Expand Up @@ -271,7 +272,7 @@ export class DropdownN {
return Promise.resolve()
}

_visibleChildren(): Array<DropDownChildAttrs> {
_visibleChildren(): Array<DropdownChildAttrs> {
return this.children.filter(b => {
return (typeof b === "string")
? b.includes(this._filterString().toLowerCase())
Expand All @@ -284,13 +285,13 @@ export class DropdownN {
}
}

export function createDropdown(lazyButtons: lazy<$ReadOnlyArray<DropDownChildAttrs>>, width: number = 200): clickHandler {
export function createDropdown(lazyButtons: lazy<$ReadOnlyArray<DropdownChildAttrs>>, width: number = 200): clickHandler {
return createAsyncDropdown(() => Promise.resolve(lazyButtons()), width)
}

const importBase = typeof module !== "undefined" ? module.id : __moduleName

export function createAsyncDropdown(lazyButtons: lazyAsync<$ReadOnlyArray<DropDownChildAttrs>>, width: number = 200): clickHandler {
export function createAsyncDropdown(lazyButtons: lazyAsync<$ReadOnlyArray<DropdownChildAttrs>>, width: number = 200): clickHandler {
// not all browsers have the actual button as e.currentTarget, but all of them send it as a second argument (see https://github.com/tutao/tutanota/issues/1110)
return ((e, dom) => {
let originalButtons = lazyButtons()
Expand Down Expand Up @@ -320,6 +321,12 @@ export function createAsyncDropdown(lazyButtons: lazyAsync<$ReadOnlyArray<DropDo
}: clickHandler)
}

export function showDropDownAtPosition(buttons: $ReadOnlyArray<DropdownChildAttrs>, xPos: number, yPos: number, width: number = 200) {
const dropdown = new DropdownN(() => buttons, width)
dropdown.setOrigin(new DomRectReadOnlyPolyfilled(xPos, yPos, 0, 0))
modal.displayUnique(dropdown, false)
}

// We override type of click to be optional because we wrap it in our own
export type DropdownButtonAttrs = $Rest<ButtonAttrs, {click?: clickHandler}>

Expand All @@ -334,8 +341,8 @@ export type DropdownButtonAttrs = $Rest<ButtonAttrs, {click?: clickHandler}>
*/
export function attachDropdown(
mainButtonAttrs: DropdownButtonAttrs,
childAttrs: lazy<$Promisable<$ReadOnlyArray<DropDownChildAttrs>>>,
showDropdown?: lazy<boolean> = () => true,
childAttrs: lazy<$Promisable<$ReadOnlyArray<DropdownChildAttrs>>>,
showDropdown: lazy<boolean> = () => true,
width?: number): ButtonAttrs {

const oldClick = mainButtonAttrs.click
Expand Down
23 changes: 21 additions & 2 deletions src/gui/base/GuiUtils.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
//@flow

import type {Country} from "../../api/common/CountryList"
import {DropDownSelector} from "./DropDownSelector"
import {Countries} from "../../api/common/CountryList"
import {lang} from "../../misc/LanguageViewModel"
import {DropDownSelector} from "./DropDownSelector"
import type {TranslationKey} from "../../misc/LanguageViewModel"
import {lang} from "../../misc/LanguageViewModel"
import {assertNotNull} from "../../api/common/utils/Utils"

// TODO Use DropDownSelectorN
export function createCountryDropdown(selectedCountry: Stream<?Country>, helpLabel?: lazy<string>, label: TranslationKey | lazy<string> = "invoiceCountry_label"): DropDownSelector<?Country> {
Expand All @@ -21,3 +22,21 @@ export function createCountryDropdown(selectedCountry: Stream<?Country>, helpLab
})
return countryInput
}

/**
* Get either the coord of a mouseevent or the coord of the first touch of a touch event
* @param event
* @returns {{x: number, y: number}}
*/
export function getCoordsOfMouseOrTouchEvent(event: MouseEvent | TouchEvent): {x: number, y: number} {
return event instanceof MouseEvent
? {
x: event.clientX,
y: event.clientY
}
: {
// Why would touches be empty?
x: assertNotNull(event.touches.item(0)).clientX,
y: assertNotNull(event.touches.item(0)).clientY
}
}
2 changes: 1 addition & 1 deletion src/mail/view/MailGuiUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export function getMailFolderIcon(mail: Mail): AllIconsEnum {
}

export function replaceCidsWithInlineImages(dom: HTMLElement, inlineImages: InlineImages,
onContext: (TutanotaFile | DataFile, Event, HTMLElement) => mixed): Array<HTMLElement> {
onContext: (TutanotaFile | DataFile, (MouseEvent | TouchEvent), HTMLElement) => mixed): Array<HTMLElement> {
// all image tags which have cid attribute. The cid attribute has been set by the sanitizer for adding a default image.
const imageElements: Array<HTMLElement> = Array.from(dom.querySelectorAll("img[cid]"))
const elementsWithCid = []
Expand Down
27 changes: 16 additions & 11 deletions src/mail/view/MailViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ import type {ButtonAttrs, ButtonColorEnum} from "../../gui/base/ButtonN"
import {ButtonColors, ButtonN, ButtonType} from "../../gui/base/ButtonN"
import {styles} from "../../gui/styles"
import {worker} from "../../api/main/WorkerClient"
import {createAsyncDropdown, createDropdown} from "../../gui/base/DropdownN"
import {createAsyncDropdown, createDropdown, showDropDownAtPosition} from "../../gui/base/DropdownN"
import {navButtonRoutes} from "../../misc/RouteChange"
import {createEmailSenderListElement} from "../../api/entities/sys/EmailSenderListElement"
import {RecipientButton} from "../../gui/base/RecipientButton"
Expand All @@ -115,6 +115,7 @@ import {stringifyFragment} from "../../gui/HtmlUtils"
import {locator} from "../../api/main/MainLocator"
import {makeMailBundle} from "../export/Bundler"
import {exportMails} from "../export/Exporter"
import {getCoordsOfMouseOrTouchEvent} from "../../gui/base/GuiUtils"

assertMainOrNode()

Expand Down Expand Up @@ -811,19 +812,23 @@ export class MailViewer {
_replaceInlineImages() {
this._inlineImages.then((loadedInlineImages) => {
this._domBodyDeferred.promise.then(domBody => {
replaceCidsWithInlineImages(domBody, loadedInlineImages, (file, event, dom) =>
file._type !== "DataFile"
? createDropdown(() => [
replaceCidsWithInlineImages(domBody, loadedInlineImages, (file, event, dom) => {
if (file._type !== "DataFile") {
const coords = getCoordsOfMouseOrTouchEvent(event)
showDropDownAtPosition([
{
label: "download_action",
click: () => {
this._downloadAndOpenAttachment(downcast(file), true)
},
click: () => this._downloadAndOpenAttachment(file, false),
type: ButtonType.Dropdown
}
])(downcast(event), dom)
: noOp
)
},
{
label: "open_action",
click: () => this._downloadAndOpenAttachment(file, true),
type: ButtonType.Dropdown
},
], coords.x, coords.y)
}
})
})
})
}
Expand Down

0 comments on commit da53f7e

Please sign in to comment.