Browse Source

fix: improve ux

version-14
hrwx 3 years ago
parent
commit
e18ca59dc6
2 changed files with 176 additions and 81 deletions
  1. +169
    -81
      frappe/public/js/frappe/ui/capture.js
  2. +7
    -0
      frappe/public/scss/common/controls.scss

+ 169
- 81
frappe/public/js/frappe/ui/capture.js View File

@@ -47,7 +47,7 @@ frappe.ui.Capture = class {
this.set_options(options); this.set_options(options);


this.facing_mode = "environment"; this.facing_mode = "environment";
this.images = []
this.images = [];
} }


set_options(options) { set_options(options) {
@@ -56,7 +56,44 @@ frappe.ui.Capture = class {
return this; return this;
} }


render() {
show() {
let me = this;

this.dialog = new frappe.ui.Dialog({
title: this.options.title,
animate: this.options.animate,
fields: [
{
fieldtype: "HTML",
fieldname: "capture"
},
{
fieldtype: "HTML",
fieldname: "total_count"
}
],
on_hide: this.stop_media_stream()
});

this.dialog.get_close_btn().on('click', () => {
me.hide();
});

this.render_stream()
.then(() => {
me.dialog.show();
})
.catch(err => {
if (me.options.error) {
frappe.show_alert(frappe.ui.Capture.ERR_MESSAGE, 3);
}

throw err;
});
}

render_stream() {
let me = this;
let constraints = { let constraints = {
video: { video: {
facingMode: this.facing_mode facingMode: this.facing_mode
@@ -64,94 +101,145 @@ frappe.ui.Capture = class {
} }


return navigator.mediaDevices.getUserMedia(constraints).then(stream => { return navigator.mediaDevices.getUserMedia(constraints).then(stream => {
this.stream = stream;
me.stream = stream;
me.dialog.custom_actions.empty();


this.dialog = new frappe.ui.Dialog({
title: this.options.title,
animate: this.options.animate,
on_hide: () => this.stop_media_stream()
});
me.setup_take_photo_action();
me.setup_preview_action();
me.setup_toggle_camera();


this.dialog.get_close_btn().on('click', () => {
this.hide();
});
me.$template = $(frappe.ui.Capture.TEMPLATE);


const set_take_photo_action = () => {
this.dialog.set_primary_action(__('Take Photo'), () => {
const data_url = frappe._.get_data_uri(video);
$e.find('.fc-preview').attr('src', data_url);

this.images.push(data_url);

$e.find('.fc-stream').hide();
$e.find('.fc-preview').show();

this.dialog.set_secondary_action_label(__('Retake'));
this.dialog.get_secondary_btn().show();
this.dialog.custom_actions.find(".btn-multiple").show();

this.dialog.set_primary_action(__('Submit'), () => {
this.hide();
if (this.callback) this.callback(this.images);
});
});

this.dialog.set_secondary_action_label(__('Switch Camera'));
this.dialog.set_secondary_action(() => {
this.facing_mode = this.facing_mode == "environment" ? "user" : "environment";
frappe.show_alert({
message: __("Switching Camera")
});
this.hide();
this.show();
});
};

set_take_photo_action();

this.dialog.set_secondary_action(() => {
this.images.pop();
$e.find('.fc-preview').hide();
$e.find('.fc-stream').show();

this.dialog.get_primary_btn().off('click');
set_take_photo_action();
});
me.video = me.$template.find('video')[0];
me.video.srcObject = me.stream;
me.video.play();


this.dialog.add_custom_action(__("Take Multiple"), () => {
$e.find('.fc-preview').hide();
$e.find('.fc-stream').show();
let field = me.dialog.get_field("capture");
$(field.wrapper).html(me.$template);
});
}


this.dialog.get_primary_btn().off('click');
this.dialog.custom_actions.find(".btn-multiple").hide();
set_take_photo_action();
}, "btn-multiple");
render_preview() {
this.$template.find('.fc-stream-container').hide();
this.$template.find('.fc-preview-container').show();

let images = ``;

this.images.forEach((image, idx) => {
images += `
<div class="mt-1 p-1 rounded col-md-3 col-sm-4" data-idx="${idx}">
<span class="capture-remove-btn" data-idx="${idx}">
${frappe.utils.icon("close", "lg")}
</span>
<img class="rounded" src="${image}" data-idx="${idx}">
</div>
`;
});


this.dialog.custom_actions.find(".btn-multiple").hide();
this.$template.find('.fc-preview-container').empty();
$(this.$template.find('.fc-preview-container')).html(
`<div class="row">
${images}
</div>`
);

this.setup_capture_action();
this.setup_submit_action();
this.setup_remove_action();
this.update_count();
this.dialog.custom_actions.empty();
}


const $e = $(frappe.ui.Capture.TEMPLATE);
setup_take_photo_action() {
let me = this;


const video = $e.find('video')[0];
video.srcObject = this.stream;
video.play();
const $container = $(this.dialog.body);
this.dialog.set_primary_action(__('Take Photo'), () => {
const data_url = frappe._.get_data_uri(me.video);


$container.html($e);
me.images.push(data_url);
me.setup_preview_action();
me.update_count();
}); });
} }


show() {
this.render()
.then(() => {
this.dialog.show();
})
.catch(err => {
if (this.options.error) {
frappe.show_alert(frappe.ui.Capture.ERR_MESSAGE, 3);
}
setup_preview_action() {
let me = this;


throw err;
if (!this.images.length) {
return;
}

this.dialog.set_secondary_action_label(__("Preview"));
this.dialog.set_secondary_action(() => {
me.dialog.get_primary_btn().off('click');
me.render_preview();
});
}

setup_remove_action() {
let me = this;
let elements = this.$template[0].getElementsByClassName("capture-remove-btn");

elements.forEach(el => {
el.onclick = () => {
let idx = parseInt(el.getAttribute("data-idx"))

me.images.splice(idx, 1);
me.render_preview();
}
});
}

update_count() {
let field = this.dialog.get_field("total_count");
let msg = `${__("Total Images")}: <b>${this.images.length}`;

if (this.images.length === 0) {
msg = __("No Images");
}

$(field.wrapper).html(`
<div class="row mt-2">
<div class="offset-4 col-4 d-flex justify-content-center">${msg}</b></div>
</div>
`);
}

setup_toggle_camera() {
let me = this;

this.dialog.add_custom_action(__("Switch Camera"), () => {
me.facing_mode = me.facing_mode == "environment" ? "user" : "environment";

frappe.show_alert({
message: __("Switching Camera")
}); });

me.stop_media_stream();
me.render_stream();
}, "btn-switch");
}

setup_capture_action() {
let me = this;

this.dialog.set_secondary_action_label(__("Capture"));
this.dialog.set_secondary_action(() => {
me.dialog.get_primary_btn().off('click');
me.render_stream();
});
}

setup_submit_action() {
let me = this;

this.dialog.set_primary_action(__('Submit'), () => {
me.hide();

if (me.callback) {
me.callback(me.images);
}
});
} }


hide() { hide() {
@@ -179,11 +267,11 @@ frappe.ui.Capture.OPTIONS = {
frappe.ui.Capture.ERR_MESSAGE = __('Unable to load camera.'); frappe.ui.Capture.ERR_MESSAGE = __('Unable to load camera.');
frappe.ui.Capture.TEMPLATE = ` frappe.ui.Capture.TEMPLATE = `
<div class="frappe-capture"> <div class="frappe-capture">
<div class="panel panel-default">
<div class="embed-responsive embed-responsive-16by9">
<img class="fc-preview embed-responsive-item" style="object-fit: contain; display: none;"/>
<video class="fc-stream embed-responsive-item">${frappe.ui.Capture.ERR_MESSAGE}</video>
</div>
<div class="embed-responsive embed-responsive-16by9 fc-stream-container">
<video class="fc-stream embed-responsive-item">${frappe.ui.Capture.ERR_MESSAGE}</video>
</div>
<div class="fc-preview-container px-2" style="display: none;">
</div> </div>
</div> </div>
`; `;

+ 7
- 0
frappe/public/scss/common/controls.scss View File

@@ -460,3 +460,10 @@ button.data-pill {
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
} }

.capture-remove-btn {
position: absolute;
top: 0;
right: 0;
cursor: pointer;
}

Loading…
Cancel
Save