init
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
[story]
|
||||
new = New story
|
||||
new_edit = Edit your story
|
||||
new_publish = Publish your story
|
||||
to_roster = Publish to my contacts
|
||||
uploading = Uploading the story
|
||||
publishing = Publishing the story
|
||||
publishing_text = Almost there…
|
||||
published = Story published
|
||||
@@ -0,0 +1,180 @@
|
||||
#publishstories {
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: rgb(var(--movim-background-main));
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
#publishstories #publishstoriesswitch,
|
||||
#publishstories #publishstoriesgallery {
|
||||
width: 5.5rem;
|
||||
height: 5.5rem;
|
||||
line-height: 5.5rem;
|
||||
margin-top: 0.75rem;
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
#publishstories.show,
|
||||
#publishstories.shoot,
|
||||
#publishstories.edit {
|
||||
transform: translateX(0);
|
||||
transition: transform 0.4s var(--decelerate-easing);
|
||||
}
|
||||
|
||||
#publishstories #publishstoriesbackedit,
|
||||
#publishstories #publishstoriesback {
|
||||
margin-left: 0;
|
||||
padding: 1rem 0;
|
||||
}
|
||||
|
||||
#publishstories #publishstoriesshoot,
|
||||
#publishstories #publishstoriesgallery,
|
||||
#publishstories #publishstoriesswitch,
|
||||
#publishstories #publishstoriessource,
|
||||
#publishstories #publishstoriesnext,
|
||||
#publishstories #publishactions,
|
||||
#publishstories #publishstoriesbackedit,
|
||||
#publishstories #publishstoriespreview,
|
||||
#publishstories.edit.publish #publishstoriesback,
|
||||
#publishstories.edit.publish #publishstoriesnext,
|
||||
#publishstories.shoot #publishstoriesheadedit,
|
||||
#publishstories.edit #publishstorieshead,
|
||||
#publishstories.edit.publish #publishstorieshead,
|
||||
#publishstories.edit.publish #publishstoriesheadedit,
|
||||
#publishstories.shoot.error video,
|
||||
#publishstories form {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#publishstories.shoot.error:before {
|
||||
font-family: 'Material Symbols';
|
||||
content: '\e04c';
|
||||
color: var(--movim-font);
|
||||
font-size: 7rem;
|
||||
opacity: 0.5;
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: calc(50% - 3.5rem);
|
||||
top: calc(50% - 3.5rem);
|
||||
}
|
||||
|
||||
#publishstories.shoot:not(.error) #publishstoriesshoot,
|
||||
#publishstories.shoot #publishstoriesgallery,
|
||||
#publishstories.shoot:not(.error) #publishstoriesswitch.enabled,
|
||||
#publishstories.edit form,
|
||||
#publishstories.edit #publishstoriesnext,
|
||||
#publishstories.edit.publish #publishactions,
|
||||
#publishstories.edit.publish #publishstoriespreview,
|
||||
#publishstories.edit.publish #publishstoriesbackedit {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
#publishstories input[type=file] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#publishstories #publishactions,
|
||||
#publishstories form {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 3rem;
|
||||
left: 50%;
|
||||
translate: -50%;
|
||||
max-width: calc(56.25vh - 8.25rem);
|
||||
/* 16:9 */
|
||||
}
|
||||
|
||||
#publishstories form {
|
||||
background-image: linear-gradient(to bottom, transparent, rgba(var(--movim-background-main), 1) 100%);
|
||||
padding: 1.5rem 2rem;
|
||||
box-sizing: border-box;
|
||||
bottom: 7.25rem;
|
||||
border-radius: 2rem;
|
||||
animation: fadeIn 0.5s;
|
||||
transition: bottom 0.3s, max-width 0.3s;
|
||||
}
|
||||
|
||||
#publishstories canvas,
|
||||
#publishstories video {
|
||||
aspect-ratio: 9 / 16;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
translate: -50% -50%;
|
||||
animation: zoom 0.3s;
|
||||
transition: top 0.3s, height 0.3s;
|
||||
}
|
||||
|
||||
#publishstories .bottom_center {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 2rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#publishstories .bottom_center>button {
|
||||
position: relative;
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#publishstories video {
|
||||
background-image: url(../theme/img/cloud_spinner.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-size: 9rem;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
#publishstories.shoot canvas,
|
||||
#publishstories.edit video {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#publishstories.edit canvas {
|
||||
animation: zoomOut 0.3s;
|
||||
border-radius: 2rem;
|
||||
height: calc(100% - 15rem);
|
||||
box-shadow: var(--elevation-5);
|
||||
}
|
||||
|
||||
#publishstories #publishactions {
|
||||
animation: fadeIn 0.5s;
|
||||
max-height: 7rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#publishstories #publishactions ul {
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
#publishstories #publishactions.uploading ul {
|
||||
transform: translateY(-7rem);
|
||||
}
|
||||
|
||||
#publishstories #publishactions.publishing ul {
|
||||
transform: translateY(-14rem);
|
||||
}
|
||||
|
||||
#publishstories.edit.publish canvas {
|
||||
top: calc(50% - 2rem);
|
||||
height: calc(100% - 21rem);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#publishstories.edit.publish form {
|
||||
bottom: 12.5rem;
|
||||
max-width: calc(56.25vh - 11.5rem);
|
||||
}
|
||||
|
||||
#publishstories.edit.publish form textarea {
|
||||
pointer-events: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
@@ -0,0 +1,401 @@
|
||||
MAX_ZOOM = 5;
|
||||
MIN_ZOOM = 0.1;
|
||||
SCROLL_SENSITIVITY = 0.0005;
|
||||
|
||||
var PublishStories = {
|
||||
main: undefined,
|
||||
back: undefined,
|
||||
video: undefined,
|
||||
videoSelect: undefined,
|
||||
canvas: undefined,
|
||||
imageCanvas: undefined,
|
||||
|
||||
canvasMinWidth: 1080,
|
||||
canvasMinHeight: 1920,
|
||||
|
||||
cameraOffset: { x: 0, y: 0 },
|
||||
cameraZoom: 1,
|
||||
isDragging: false,
|
||||
dragStart: { x: 0, y: 0 },
|
||||
initialPinchDistance: null,
|
||||
lastZoom: 1,
|
||||
|
||||
init: function () {
|
||||
PublishStories_ajaxGetContactsCount();
|
||||
|
||||
MovimTpl.loadingPage();
|
||||
|
||||
MovimTpl.pushAnchorState('story', function () {
|
||||
document.querySelector('#publishstories').classList = '';
|
||||
PublishStories.close();
|
||||
});
|
||||
|
||||
PublishStories.main = document.querySelector('#publishstories');
|
||||
PublishStories.back = document.querySelector("#publishstories #publishstoriesback");
|
||||
PublishStories.video = document.querySelector("#publishstories video");
|
||||
PublishStories.videoSelect = document.querySelector("#publishstories select#publishstoriessource");
|
||||
PublishStories.canvas = document.querySelector('#publishstories canvas');
|
||||
|
||||
PublishStories.main.addEventListener('mousemove', PublishStories.onMainPointerMove);
|
||||
|
||||
PublishStories.canvas.addEventListener('mousedown', PublishStories.onPointerDown);
|
||||
PublishStories.canvas.addEventListener('touchstart', (e) => PublishStories.handleTouch(e, PublishStories.onPointerDown));
|
||||
PublishStories.canvas.addEventListener('mouseup', PublishStories.onPointerUp);
|
||||
PublishStories.canvas.addEventListener('touchend', (e) => PublishStories.handleTouch(e, PublishStories.onPointerUp));
|
||||
PublishStories.canvas.addEventListener('mousemove', PublishStories.onPointerMove);
|
||||
PublishStories.canvas.addEventListener('touchmove', (e) => PublishStories.handleTouch(e, PublishStories.onPointerMove));
|
||||
PublishStories.canvas.addEventListener('wheel', (e) => PublishStories.adjustZoom(e.deltaY * SCROLL_SENSITIVITY));
|
||||
|
||||
PublishStories.main.querySelector('#publishstoriesswitch').onclick = () => {
|
||||
PublishStories.videoSelect.selectedIndex++;
|
||||
if (PublishStories.videoSelect.selectedIndex == -1) {
|
||||
PublishStories.videoSelect.selectedIndex = 0;
|
||||
}
|
||||
|
||||
Toast.send(PublishStories.videoSelect.options[PublishStories.videoSelect.selectedIndex].label);
|
||||
PublishStories.getStream();
|
||||
};
|
||||
|
||||
PublishStories.main.classList = 'show';
|
||||
PublishStories.back.onclick = () => { history.back(); };
|
||||
|
||||
PublishStories.close();
|
||||
PublishStories.getStream(true);
|
||||
},
|
||||
|
||||
draw: function () {
|
||||
if (PublishStories.imageCanvas == undefined) return;
|
||||
|
||||
PublishStories.canvas.width = PublishStories.canvasMinWidth;
|
||||
PublishStories.canvas.height = PublishStories.canvasMinHeight;
|
||||
|
||||
let context = PublishStories.canvas.getContext('2d');
|
||||
ctx.clearRect(0, 0, PublishStories.canvas.width, PublishStories.canvas.height)
|
||||
context.fillStyle = MovimUtils.imageToHex(PublishStories.imageCanvas);
|
||||
context.fillRect(0, 0, PublishStories.canvas.width, PublishStories.canvas.height);
|
||||
|
||||
// Let's move!
|
||||
context.translate(PublishStories.canvas.width / 2, PublishStories.canvas.height / 2);
|
||||
context.scale(PublishStories.cameraZoom, PublishStories.cameraZoom);
|
||||
context.translate(
|
||||
-PublishStories.canvas.width / 2 + PublishStories.cameraOffset.x,
|
||||
-PublishStories.canvas.height / 2 + PublishStories.cameraOffset.y
|
||||
);
|
||||
|
||||
let adjustedHeight = PublishStories.canvas.height > PublishStories.imageCanvas.height
|
||||
? PublishStories.imageCanvas.height
|
||||
: PublishStories.canvas.height;
|
||||
|
||||
let ratio = adjustedHeight / PublishStories.imageCanvas.height;
|
||||
|
||||
context.drawImage(
|
||||
PublishStories.imageCanvas,
|
||||
PublishStories.canvas.width / 2 - PublishStories.imageCanvas.width * ratio / 2,
|
||||
PublishStories.canvas.height / 2 - adjustedHeight / 2,
|
||||
PublishStories.imageCanvas.width * ratio,
|
||||
adjustedHeight
|
||||
);
|
||||
|
||||
requestAnimationFrame(PublishStories.draw);
|
||||
},
|
||||
|
||||
goToPublish: function () {
|
||||
let title = PublishStories.main.querySelector('form textarea[name=title]');
|
||||
|
||||
if (title.value == '') {
|
||||
PublishStories_ajaxNoTitle();
|
||||
return;
|
||||
}
|
||||
|
||||
PublishStories.main.classList.add('publish');
|
||||
},
|
||||
|
||||
goToEdit: function () {
|
||||
PublishStories.main.classList.remove('publish');
|
||||
},
|
||||
|
||||
publish: function () {
|
||||
PublishStories.main.querySelector('#publishactions').classList.add('uploading');
|
||||
|
||||
PublishStories.canvas.toBlob(
|
||||
function (blob) {
|
||||
Upload.prepare(blob);
|
||||
Upload.name = 'story.jpg';
|
||||
Upload.init(true);
|
||||
},
|
||||
'image/jpeg',
|
||||
0.85
|
||||
);
|
||||
},
|
||||
|
||||
close: function () {
|
||||
if (!PublishStories.video) return;
|
||||
|
||||
let stream = PublishStories.video.srcObject;
|
||||
|
||||
if (stream) {
|
||||
stream.getTracks().forEach(track => track.stop());
|
||||
}
|
||||
|
||||
PublishStories.video.srcObject = null;
|
||||
PublishStories.imageCanvas = undefined;
|
||||
PublishStories.main.querySelector('form').reset();
|
||||
PublishStories.main.querySelector('#publishactions').classList = '';
|
||||
|
||||
PublishStories.reset();
|
||||
PublishStories.main.classList = '';
|
||||
PublishStories.main == undefined;
|
||||
},
|
||||
|
||||
openImage: function () {
|
||||
PublishStories.main.querySelector('input[type=file]').click();
|
||||
},
|
||||
|
||||
applyImage: function () {
|
||||
file = PublishStories.main.querySelector('input[type=file]').files[0];
|
||||
|
||||
if (!file.type.match(/image.*/)) {
|
||||
console.log("Not a picture !");
|
||||
PublishStories.reset();
|
||||
} else {
|
||||
var reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.addEventListener('load', function (ev) {
|
||||
var image = new Image();
|
||||
image.src = reader.result;
|
||||
image.onload = function () {
|
||||
PublishStories.drawMediaToImageCanvas(image, image.width, image.height, 1);
|
||||
PublishStories.draw();
|
||||
PublishStories.main.classList = 'edit';
|
||||
}
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
shoot: function () {
|
||||
if (PublishStories.imageCapture) {
|
||||
PublishStories.imageCapture.grabFrame()
|
||||
.then(image => {
|
||||
PublishStories.drawMediaToImageCanvas(
|
||||
image,
|
||||
image.width,
|
||||
image.height,
|
||||
PublishStories.getRatioFromHeight(image.height)
|
||||
);
|
||||
|
||||
PublishStories.draw();
|
||||
})
|
||||
.catch(error => console.log(error));
|
||||
|
||||
} else {
|
||||
PublishStories.drawMediaToImageCanvas(
|
||||
PublishStories.video,
|
||||
PublishStories.video.videoWidth,
|
||||
PublishStories.video.videoHeight,
|
||||
PublishStories.getRatioFromHeight(PublishStories.video.videoHeight)
|
||||
);
|
||||
|
||||
PublishStories.video.pause();
|
||||
PublishStories.draw();
|
||||
}
|
||||
|
||||
PublishStories.main.classList = 'edit';
|
||||
},
|
||||
|
||||
getRatioFromHeight: function (height) {
|
||||
let ratio = PublishStories.canvasMinHeight / height;
|
||||
if (ratio < 1) ratio = 1;
|
||||
|
||||
return ratio;
|
||||
},
|
||||
|
||||
drawMediaToImageCanvas: function (media, width, height, ratio) {
|
||||
PublishStories.imageCanvas = document.createElement('canvas');
|
||||
PublishStories.imageCanvas.width = width * ratio;
|
||||
PublishStories.imageCanvas.height = height * ratio;
|
||||
|
||||
var context = PublishStories.imageCanvas.getContext('2d');
|
||||
context.drawImage(media, 0, 0, PublishStories.imageCanvas.width, PublishStories.imageCanvas.height);
|
||||
},
|
||||
|
||||
reset: function () {
|
||||
if (PublishStories.videoSelect.options.length > 0) {
|
||||
PublishStories.main.classList = 'shoot';
|
||||
PublishStories.video.play();
|
||||
} else {
|
||||
PublishStories.main.classList = 'shoot error';
|
||||
}
|
||||
|
||||
PublishStories.cameraOffset = { x: 0, y: 0 };
|
||||
PublishStories.cameraZoom = PublishStories.lastZoom = 1;
|
||||
},
|
||||
|
||||
getStream: function (init) {
|
||||
PublishStories.main.classList = 'wait';
|
||||
|
||||
if (PublishStories.video.srcObject) {
|
||||
PublishStories.video.srcObject.getTracks().forEach(track => track.stop());
|
||||
}
|
||||
|
||||
const videoSource = PublishStories.videoSelect.value;
|
||||
const constraints = {
|
||||
video: {
|
||||
deviceId: videoSource ? { exact: videoSource } : undefined,
|
||||
width: { ideal: 1920 },
|
||||
height: { ideal: 1920 }
|
||||
}
|
||||
};
|
||||
|
||||
navigator.mediaDevices.getUserMedia(constraints)
|
||||
.then(stream => {
|
||||
MovimTpl.finishedPage();
|
||||
PublishStories.gotStream(stream);
|
||||
|
||||
if (init) {
|
||||
navigator.mediaDevices.enumerateDevices().then(PublishStories.gotDevices);
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
MovimTpl.finishedPage();
|
||||
PublishStories.noStream()
|
||||
});
|
||||
},
|
||||
|
||||
noStream: function (stream) {
|
||||
PublishStories.main.classList = 'shoot error';
|
||||
},
|
||||
|
||||
gotStream: function (stream) {
|
||||
PublishStories.main.classList = 'shoot';
|
||||
|
||||
PublishStories.videoSelect.selectedIndex = [...PublishStories.videoSelect.options].
|
||||
findIndex(option => option.text === stream.getVideoTracks()[0].label);
|
||||
PublishStories.video.srcObject = stream;
|
||||
PublishStories.video.play();
|
||||
|
||||
// We try to use ImageCapture
|
||||
if (typeof (ImageCapture) != 'undefined') {
|
||||
const track = stream.getVideoTracks()[0];
|
||||
PublishStories.imageCapture = new ImageCapture(track);
|
||||
}
|
||||
|
||||
// If we cancel after the authorization was given
|
||||
if (PublishStories.main.classList == '') {
|
||||
PublishStories.close();
|
||||
};
|
||||
},
|
||||
|
||||
gotDevices: function (devicesInfo) {
|
||||
PublishStories.videoSelect.innerHTML = '';
|
||||
|
||||
for (const deviceInfo of devicesInfo) {
|
||||
if (deviceInfo.kind === 'videoinput') {
|
||||
const option = document.createElement('option');
|
||||
option.value = deviceInfo.deviceId;
|
||||
option.text = deviceInfo.label || `Camera ${PublishStories.videoSelect.length + 1}`;
|
||||
|
||||
if (!PublishStories.videoSelect.querySelector('option[value="' + deviceInfo.deviceId + '"]')) {
|
||||
PublishStories.videoSelect.appendChild(option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PublishStories.videoSelect.options.length >= 2) {
|
||||
document.querySelector("#publishstories #publishstoriesswitch").classList.add('enabled');
|
||||
}
|
||||
},
|
||||
|
||||
onPointerDown: function (e) {
|
||||
PublishStories.isDragging = true
|
||||
PublishStories.dragStart.x = MovimUtils.getEventLocation(e).x / PublishStories.cameraZoom - PublishStories.cameraOffset.x
|
||||
PublishStories.dragStart.y = MovimUtils.getEventLocation(e).y / PublishStories.cameraZoom - PublishStories.cameraOffset.y
|
||||
},
|
||||
|
||||
onPointerUp: function (e) {
|
||||
PublishStories.isDragging = false
|
||||
PublishStories.initialPinchDistance = null
|
||||
PublishStories.lastZoom = PublishStories.cameraZoom
|
||||
},
|
||||
|
||||
onMainPointerMove: function (e) {
|
||||
if (!PublishStories.main.classList.contains('edit') || !MovimUtils.getEventLocation(e)) return;
|
||||
|
||||
let borders = PublishStories.canvas.getBoundingClientRect();
|
||||
|
||||
if (MovimUtils.getEventLocation(e).x < borders.left
|
||||
|| MovimUtils.getEventLocation(e).x > borders.right
|
||||
|| MovimUtils.getEventLocation(e).y < borders.top
|
||||
|| MovimUtils.getEventLocation(e).y > borders.bottom) {
|
||||
PublishStories.onPointerUp(e);
|
||||
}
|
||||
},
|
||||
|
||||
onPointerMove: function (e) {
|
||||
if (PublishStories.isDragging) {
|
||||
PublishStories.cameraOffset.x = MovimUtils.getEventLocation(e).x / PublishStories.cameraZoom - PublishStories.dragStart.x
|
||||
PublishStories.cameraOffset.y = MovimUtils.getEventLocation(e).y / PublishStories.cameraZoom - PublishStories.dragStart.y
|
||||
}
|
||||
},
|
||||
|
||||
handleTouch: function (e, singleTouchHandler) {
|
||||
if (e.touches.length == 1) {
|
||||
singleTouchHandler(e)
|
||||
}
|
||||
else if (e.type == "touchmove" && e.touches.length == 2) {
|
||||
PublishStories.isDragging = false
|
||||
PublishStories.handlePinch(e)
|
||||
}
|
||||
},
|
||||
|
||||
handlePinch: function (e) {
|
||||
e.preventDefault()
|
||||
|
||||
let touch1 = { x: e.touches[0].clientX, y: e.touches[0].clientY }
|
||||
let touch2 = { x: e.touches[1].clientX, y: e.touches[1].clientY }
|
||||
|
||||
// This is distance squared, but no need for an expensive sqrt as it's only used in ratio
|
||||
let currentDistance = (touch1.x - touch2.x) ** 2 + (touch1.y - touch2.y) ** 2
|
||||
|
||||
if (PublishStories.initialPinchDistance == null) {
|
||||
PublishStories.initialPinchDistance = currentDistance
|
||||
}
|
||||
else {
|
||||
PublishStories.adjustZoom(null, currentDistance / PublishStories.initialPinchDistance)
|
||||
}
|
||||
},
|
||||
|
||||
adjustZoom: function (zoomAmount, zoomFactor) {
|
||||
if (!PublishStories.isDragging) {
|
||||
if (zoomAmount) {
|
||||
PublishStories.cameraZoom += zoomAmount
|
||||
}
|
||||
else if (zoomFactor) {
|
||||
PublishStories.cameraZoom = zoomFactor * PublishStories.lastZoom
|
||||
}
|
||||
|
||||
PublishStories.cameraZoom = Math.min(PublishStories.cameraZoom, MAX_ZOOM)
|
||||
PublishStories.cameraZoom = Math.max(PublishStories.cameraZoom, MIN_ZOOM)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MovimEvents.registerWindow('loaded', 'publishstories', () => {
|
||||
Upload.attach((file) => {
|
||||
if (PublishStories.main && PublishStories.main.classList.contains('publish')) {
|
||||
PublishStories.main.querySelector('#publishactions').classList.remove('uploading');
|
||||
PublishStories.main.querySelector('#publishactions').classList.add('publishing');
|
||||
PublishStories_ajaxPublish(MovimUtils.formToJson('metadata'), file.id);
|
||||
}
|
||||
});
|
||||
|
||||
Upload.fail(() => {
|
||||
PublishStories.main.querySelector('#publishactions').classList.remove('uploading');
|
||||
});
|
||||
|
||||
Upload.progress((percent) => {
|
||||
if (PublishStories.main != undefined && PublishStories.main.classList.contains('publish')) {
|
||||
PublishStories.main.querySelector('#publishactionsprogress').innerHTML =
|
||||
percent + '%';
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user