Media viewer arrows & swipe
Some layout fixes in chat for mobile
This commit is contained in:
parent
8a5a91b3c4
commit
e6e1f58e56
@ -171,10 +171,10 @@
|
|||||||
<div class="btn-menu-item menu-menu-delete danger tgico-delete rp btn-disabled">Delete</div>
|
<div class="btn-menu-item menu-menu-delete danger tgico-delete rp btn-disabled">Delete</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="media-viewer-switchers">
|
{{!-- <div class="media-viewer-switchers"> --}}
|
||||||
<div class="media-viewer-switcher media-viewer-switcher-left menu-prev"><span class="tgico-down media-viewer-prev-button"></span></div>
|
<div class="media-viewer-switcher media-viewer-switcher-left menu-prev"><span class="tgico-down media-viewer-prev-button"></span></div>
|
||||||
<div class="media-viewer-switcher media-viewer-switcher-right menu-next"><span class="tgico-down media-viewer-next-button"></span></div>
|
<div class="media-viewer-switcher media-viewer-switcher-right menu-next"><span class="tgico-down media-viewer-next-button"></span></div>
|
||||||
</div>
|
{{!-- </div> --}}
|
||||||
</div>
|
</div>
|
||||||
<div class="popup popup-send-photo popup-new-media">
|
<div class="popup popup-send-photo popup-new-media">
|
||||||
<div class="popup-container z-depth-1">
|
<div class="popup-container z-depth-1">
|
||||||
|
@ -2003,6 +2003,7 @@ export class AppImManager {
|
|||||||
<use xlink:href="#b13RmHDQtl" opacity="1" fill="#fff" fill-opacity="1"></use>
|
<use xlink:href="#b13RmHDQtl" opacity="1" fill="#fff" fill-opacity="1"></use>
|
||||||
</svg>`;
|
</svg>`;
|
||||||
bubbleContainer.append(forward);
|
bubbleContainer.append(forward);
|
||||||
|
bubble.classList.add('with-beside-button');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2589,6 +2590,7 @@ export class AppImManager {
|
|||||||
goto.classList.add('bubble-beside-button', 'goto-original', 'tgico-next');
|
goto.classList.add('bubble-beside-button', 'goto-original', 'tgico-next');
|
||||||
bubbleContainer.append(goto);
|
bubbleContainer.append(goto);
|
||||||
bubble.dataset.savedFrom = message.savedFrom;
|
bubble.dataset.savedFrom = message.savedFrom;
|
||||||
|
bubble.classList.add('with-beside-button');
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!bubble.classList.contains('sticker')) {
|
if(!bubble.classList.contains('sticker')) {
|
||||||
|
@ -11,7 +11,7 @@ import { renderImageFromUrl, parseMenuButtonsTo } from "../../components/misc";
|
|||||||
import AvatarElement from "../../components/avatar";
|
import AvatarElement from "../../components/avatar";
|
||||||
import LazyLoadQueue from "../../components/lazyLoadQueue";
|
import LazyLoadQueue from "../../components/lazyLoadQueue";
|
||||||
import appForward from "../../components/appForward";
|
import appForward from "../../components/appForward";
|
||||||
import { isSafari, mediaSizes } from "../config";
|
import { isSafari, mediaSizes, touchSupport } from "../config";
|
||||||
import appAudio from "../../components/appAudio";
|
import appAudio from "../../components/appAudio";
|
||||||
import { deferredPromise } from "../polyfill";
|
import { deferredPromise } from "../polyfill";
|
||||||
import { MTDocument } from "../../types";
|
import { MTDocument } from "../../types";
|
||||||
@ -19,6 +19,54 @@ import { MTDocument } from "../../types";
|
|||||||
// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию
|
// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию
|
||||||
// TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)
|
// TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)
|
||||||
|
|
||||||
|
class SwipeHandler {
|
||||||
|
private xDown: number;
|
||||||
|
private yDown: number;
|
||||||
|
|
||||||
|
constructor(element: HTMLElement, private onSwipe: (xDiff: number, yDiff: number) => boolean) {
|
||||||
|
element.addEventListener('touchstart', this.handleTouchStart, false);
|
||||||
|
element.addEventListener('touchmove', this.handleTouchMove, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleTouchStart = (evt: TouchEvent) => {
|
||||||
|
const firstTouch = evt.touches[0];
|
||||||
|
this.xDown = firstTouch.clientX;
|
||||||
|
this.yDown = firstTouch.clientY;
|
||||||
|
};
|
||||||
|
|
||||||
|
handleTouchMove = (evt: TouchEvent) => {
|
||||||
|
if(this.xDown == null || this.yDown == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const xUp = evt.touches[0].clientX;
|
||||||
|
const yUp = evt.touches[0].clientY;
|
||||||
|
|
||||||
|
const xDiff = this.xDown - xUp;
|
||||||
|
const yDiff = this.yDown - yUp;
|
||||||
|
|
||||||
|
// if(Math.abs(xDiff) > Math.abs(yDiff)) { /*most significant*/
|
||||||
|
// if(xDiff > 0) { /* left swipe */
|
||||||
|
|
||||||
|
// } else { /* right swipe */
|
||||||
|
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// if(yDiff > 0) { /* up swipe */
|
||||||
|
|
||||||
|
// } else { /* down swipe */
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
/* reset values */
|
||||||
|
if(this.onSwipe(xDiff, yDiff)) {
|
||||||
|
this.xDown = null;
|
||||||
|
this.yDown = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export class AppMediaViewer {
|
export class AppMediaViewer {
|
||||||
public wholeDiv = document.querySelector('.media-viewer-whole') as HTMLDivElement;
|
public wholeDiv = document.querySelector('.media-viewer-whole') as HTMLDivElement;
|
||||||
private overlaysDiv = this.wholeDiv.firstElementChild as HTMLDivElement;
|
private overlaysDiv = this.wholeDiv.firstElementChild as HTMLDivElement;
|
||||||
@ -66,6 +114,8 @@ export class AppMediaViewer {
|
|||||||
|
|
||||||
private lazyLoadQueue: LazyLoadQueue;
|
private lazyLoadQueue: LazyLoadQueue;
|
||||||
|
|
||||||
|
private highlightSwitchersTimeout: number;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.log = logger('AMV');
|
this.log = logger('AMV');
|
||||||
this.preloader = new ProgressivePreloader();
|
this.preloader = new ProgressivePreloader();
|
||||||
@ -152,6 +202,33 @@ export class AppMediaViewer {
|
|||||||
//this.content.mover.addEventListener('click', this.onClickBinded);
|
//this.content.mover.addEventListener('click', this.onClickBinded);
|
||||||
//this.content.mover.append(this.buttons.prev, this.buttons.next);
|
//this.content.mover.append(this.buttons.prev, this.buttons.next);
|
||||||
this.setNewMover();
|
this.setNewMover();
|
||||||
|
|
||||||
|
if(touchSupport) {
|
||||||
|
const swipeHandler = new SwipeHandler(this.wholeDiv, (xDiff, yDiff) => {
|
||||||
|
//console.log(xDiff, yDiff);
|
||||||
|
|
||||||
|
const percents = Math.abs(xDiff) / appPhotosManager.windowW;
|
||||||
|
if(percents > .2 || xDiff > 125) {
|
||||||
|
//console.log('will swipe', xDiff);
|
||||||
|
|
||||||
|
if(xDiff < 0) {
|
||||||
|
this.buttons.prev.click();
|
||||||
|
} else {
|
||||||
|
this.buttons.next.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const percentsY = Math.abs(yDiff) / appPhotosManager.windowH;
|
||||||
|
if(percentsY > .2 || yDiff > 125) {
|
||||||
|
this.buttons.close.click();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickDownload = (e: MouseEvent) => {
|
onClickDownload = (e: MouseEvent) => {
|
||||||
@ -178,6 +255,21 @@ export class AppMediaViewer {
|
|||||||
if(target.tagName == 'A') return;
|
if(target.tagName == 'A') return;
|
||||||
cancelEvent(e);
|
cancelEvent(e);
|
||||||
|
|
||||||
|
if(touchSupport) {
|
||||||
|
if(this.highlightSwitchersTimeout) {
|
||||||
|
clearTimeout(this.highlightSwitchersTimeout);
|
||||||
|
} else {
|
||||||
|
this.wholeDiv.classList.add('highlight-switchers');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.highlightSwitchersTimeout = setTimeout(() => {
|
||||||
|
this.wholeDiv.classList.remove('highlight-switchers');
|
||||||
|
this.highlightSwitchersTimeout = 0;
|
||||||
|
}, 3e3);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let mover: HTMLElement = null;
|
let mover: HTMLElement = null;
|
||||||
['media-viewer-mover', 'media-viewer-buttons', 'media-viewer-author'].find(s => {
|
['media-viewer-mover', 'media-viewer-buttons', 'media-viewer-author'].find(s => {
|
||||||
try {
|
try {
|
||||||
|
@ -464,6 +464,7 @@ export class AppSidebarRight extends SidebarSlider {
|
|||||||
|
|
||||||
let thumb: HTMLImageElement;
|
let thumb: HTMLImageElement;
|
||||||
const sizes = media.sizes || media.thumbs;
|
const sizes = media.sizes || media.thumbs;
|
||||||
|
|
||||||
const willHaveThumb = !isDownloaded && sizes && sizes[0].bytes;
|
const willHaveThumb = !isDownloaded && sizes && sizes[0].bytes;
|
||||||
if(willHaveThumb) {
|
if(willHaveThumb) {
|
||||||
thumb = new Image();
|
thumb = new Image();
|
||||||
@ -496,8 +497,10 @@ export class AppSidebarRight extends SidebarSlider {
|
|||||||
promises.push(promise);
|
promises.push(promise);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isDownloaded) load();
|
if(sizes?.length) {
|
||||||
else this.lazyLoadQueue.push({div, load});
|
if(isDownloaded) load();
|
||||||
|
else this.lazyLoadQueue.push({div, load});
|
||||||
|
}
|
||||||
|
|
||||||
elemsToAppend.push(div);
|
elemsToAppend.push(div);
|
||||||
this.mediaDivsByIDs[message.mid] = div;
|
this.mediaDivsByIDs[message.mid] = div;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
$chat-max-width: 696px;
|
$chat-max-width: 696px;
|
||||||
$time-background: rgba(0, 0, 0, .35);
|
$time-background: rgba(0, 0, 0, .35);
|
||||||
|
$handhelds-margin: 5.5625rem;
|
||||||
|
$beside-button-margin: 2.875rem;
|
||||||
|
|
||||||
#bubble-contextmenu > div {
|
#bubble-contextmenu > div {
|
||||||
padding: 0 84px 0 16px;
|
padding: 0 84px 0 16px;
|
||||||
@ -161,14 +163,13 @@ $time-background: rgba(0, 0, 0, .35);
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
|
@include respond-to(handhelds) {
|
||||||
|
padding: 0 .5rem .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
@include respond-to(handhelds) {
|
@include respond-to(not-handhelds) {
|
||||||
padding: 0 .5rem .5rem;
|
padding-bottom: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include respond-to(not-handhelds) {
|
|
||||||
padding-bottom: 21px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @include respond-to(handhelds) {
|
/* @include respond-to(handhelds) {
|
||||||
@ -883,15 +884,20 @@ $time-background: rgba(0, 0, 0, .35);
|
|||||||
//margin-left: 3rem; #DO JS3
|
//margin-left: 3rem; #DO JS3
|
||||||
|
|
||||||
@include respond-to(handhelds) {
|
@include respond-to(handhelds) {
|
||||||
max-width: calc(100% - 3rem);
|
max-width: calc(100% - #{$handhelds-margin});
|
||||||
margin-left: 45px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-channel:not(.is-chat) {
|
&.is-channel:not(.is-chat) {
|
||||||
.bubble__container {
|
.bubble {
|
||||||
max-width: 100%;
|
&__container {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.with-beside-button .bubble__container {
|
||||||
|
max-width: calc(100% - #{$beside-button-margin}) !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.has-rights) {
|
&:not(.has-rights) {
|
||||||
|
@ -45,12 +45,12 @@ $bubble-margin: .25rem;
|
|||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
||||||
@include respond-to(not-handhelds) {
|
//@include respond-to(not-handhelds) {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
//}
|
||||||
|
|
||||||
@include respond-to(handhelds) {
|
@include respond-to(handhelds) {
|
||||||
max-width: unquote("min(calc(100% - 46px), #{$chat-max-width})");
|
max-width: unquote("min(100%, #{$chat-max-width - 16px})");
|
||||||
|
|
||||||
html.is-mac & {
|
html.is-mac & {
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
@ -146,6 +146,10 @@ $bubble-margin: .25rem;
|
|||||||
max-width: 85%;
|
max-width: 85%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include respond-to(handhelds) {
|
||||||
|
max-width: calc(100% - #{$handhelds-margin});
|
||||||
|
}
|
||||||
|
|
||||||
> .user-avatar {
|
> .user-avatar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: -45px;
|
left: -45px;
|
||||||
@ -163,6 +167,12 @@ $bubble-margin: .25rem;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* &.with-beside-button &__container {
|
||||||
|
@include respond-to(handhelds) {
|
||||||
|
max-width: calc(100% - #{$handhelds-margin}) !important;
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
&.service {
|
&.service {
|
||||||
//padding: 1rem 0;
|
//padding: 1rem 0;
|
||||||
padding: $bubble-margin 0;
|
padding: $bubble-margin 0;
|
||||||
@ -1231,7 +1241,7 @@ $bubble-margin: .25rem;
|
|||||||
} */
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
@include respond-to(handhelds) {
|
/* @include respond-to(handhelds) {
|
||||||
.bubble.is-in {
|
.bubble.is-in {
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
@ -1239,7 +1249,7 @@ $bubble-margin: .25rem;
|
|||||||
.bubble.is-out {
|
.bubble.is-out {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
}
|
} */
|
||||||
|
|
||||||
.bubble.is-out {
|
.bubble.is-out {
|
||||||
.bubble__container {
|
.bubble__container {
|
||||||
@ -1450,7 +1460,7 @@ $bubble-margin: .25rem;
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-progress {
|
.progress-line {
|
||||||
&__loaded {
|
&__loaded {
|
||||||
background-color: #90e18d !important;
|
background-color: #90e18d !important;
|
||||||
}
|
}
|
||||||
|
@ -127,44 +127,57 @@ $move-duration: .35s;
|
|||||||
left: 0;
|
left: 0;
|
||||||
top: 60px;
|
top: 60px;
|
||||||
width: 7rem;
|
width: 7rem;
|
||||||
height: 100%;
|
height: calc(100% - 120px);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
|
|
||||||
html.no-touch &:hover {
|
html.no-touch & {
|
||||||
> span {
|
height: calc(100% - 60px);
|
||||||
opacity: 1;
|
|
||||||
|
&:hover {
|
||||||
|
> span {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include respond-to(handhelds) {
|
@include respond-to(handhelds) {
|
||||||
width: 4rem;
|
width: 4rem;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&-switcher-right {
|
&-right {
|
||||||
left: auto;
|
left: auto;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-prev-button, &-next-button {
|
&-prev-button, &-next-button {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 3rem;
|
font-size: 2rem;
|
||||||
left: 2rem;
|
left: 1rem;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translateY(-50%) rotate(90deg);
|
transform: translateY(-50%) rotate(90deg);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: $open-duration opacity;
|
transition: $open-duration opacity;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
/* box-shadow: 0 1px 2px 0 rgba(16, 35, 47, 0.07); */
|
/* box-shadow: 0 1px 2px 0 rgba(16, 35, 47, 0.07); */
|
||||||
|
|
||||||
|
@include respond-to(not-handhelds) {
|
||||||
|
font-size: 3rem;
|
||||||
|
left: 2rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-next-button {
|
&-next-button {
|
||||||
left: auto;
|
left: auto;
|
||||||
right: 2rem;
|
right: 1rem;
|
||||||
transform: translateY(-50%) rotate(-90deg);
|
transform: translateY(-50%) rotate(-90deg);
|
||||||
|
|
||||||
|
@include respond-to(not-handhelds) {
|
||||||
|
right: 2rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-mover {
|
&-mover {
|
||||||
@ -298,6 +311,12 @@ $move-duration: .35s;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.highlight-switchers {
|
||||||
|
.media-viewer-switcher > span {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-switchers {
|
&-switchers {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user