From f3b09ecfdecaa0f976737f04f140f79924b5ddfa Mon Sep 17 00:00:00 2001 From: Ludovic <54670129+lbr38@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:48:57 +0100 Subject: [PATCH] 5.1.0 --- README.md | 2 +- www/controllers/Motion/Config.php | 137 ++++++++------ www/controllers/ajax/motion.php | 17 +- www/public/assets/icons/cpu.svg | 65 ++++--- www/public/resources/js/motion.js | 107 +++++++---- www/public/resources/styles/common.css | 170 ++++++++---------- www/public/resources/styles/motionui.css | 33 +++- www/version | 2 +- www/views/includes/camera/edit/form.inc.php | 38 ++-- .../camera/edit/motion-config-form.inc.php | 79 ++++---- .../includes/containers/cameras/list.inc.php | 10 +- .../containers/motion/events/list.inc.php | 2 +- www/views/includes/footer.inc.php | 2 +- www/views/includes/panels/camera/add.inc.php | 23 +-- .../includes/panels/motion/alert.inc.php | 61 +++---- .../includes/panels/motion/autostart.inc.php | 130 +++++++------- www/views/includes/panels/settings.inc.php | 8 +- .../includes/tables/motion/events.inc.php | 87 +++++---- 18 files changed, 524 insertions(+), 449 deletions(-) diff --git a/README.md b/README.md index 20e32cdd..e9bf95e3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # motion-UI -A web responsive interface to manage motion (an open-source motion detection software) and visualize live stream from http cameras. +A web responsive interface to manage motion (an open-source motion detection software) and visualize cameras live stream.
diff --git a/www/controllers/Motion/Config.php b/www/controllers/Motion/Config.php index a7ea3d41..ec1455d5 100644 --- a/www/controllers/Motion/Config.php +++ b/www/controllers/Motion/Config.php @@ -167,6 +167,16 @@ public function edit(string $file, array $params) * Edit and overwrite current params with new params */ foreach ($params as $param => $details) { + // Ignore if param is empty + if (empty($param)) { + continue; + } + + // Ignore if param value is empty + if (empty($details['value'])) { + continue; + } + $status = $details['status']; $value = $details['value']; @@ -194,17 +204,48 @@ private function write(string $file, array $params) { $content = ''; - foreach ($params as $param => $details) { + foreach ($params as $name => $details) { + $name = \Controllers\Common::validateData($name); $status = $details['status']; $value = $details['value']; + /** + * Check that parameter name is valid and does not contains invalid caracters + */ + if (\Controllers\Common::isAlphanumDash($name) === false) { + throw new Exception($name . ' parameter name contains invalid caracter(s)'); + } + + /** + * Case the option is 'netcam_url' or 'netcam_high_url' + */ + if ($status == 'enabled' and ($name == 'netcam_url' or $name == 'netcam_high_url')) { + /** + * Check that URL starts with http:// or https:// or rtsp:// + */ + if (!preg_match('#((^https?|rtsp)://)#', $value)) { + throw new Exception('' . $name . ' parameter value must start with http:// or https:// or rtsp://'); + } + + if (\Controllers\Common::isAlphanumDash($value, array('.', '/', ':', '=', '?', '&', '@')) === false) { + throw new Exception('' . $name . ' parameter value contains invalid caracter(s)'); + } + /** + * All other options + */ + } else { + if (\Controllers\Common::isAlphanumDash($value, array('.', ' ', ',', ':', '/', '%Y', '%m', '%d', '%H', '%M', '%S', '%q', '%v', '%t', '%w', '%h', '%D', '%f', '%{eventid}', '%{fps}', '(', ')', '=', '\'', '[', ']', '@')) === false) { + throw new Exception('' . $name . ' parameter value contains invalid caracter(s)'); + } + } + if ($status == 'enabled') { $status = ''; } else { $status = ';'; } - $content .= $status . $param . " " . $value . PHP_EOL . PHP_EOL; + $content .= $status . $name . " " . $value . PHP_EOL . PHP_EOL; } /** @@ -217,78 +258,58 @@ private function write(string $file, array $params) unset($content); } - // TODO : fait doublon avec la fonction edit() ci-dessus /** * Edit motion configuration file (in /var/lib/motionui/cameras/) */ - public function configure(string $cameraId, array $options) + public function configure(string $cameraId, array $params) { - $filename = CAMERAS_MOTION_CONF_AVAILABLE_DIR . '/camera-' . $cameraId . '.conf'; + $file = CAMERAS_MOTION_CONF_AVAILABLE_DIR . '/camera-' . $cameraId . '.conf'; - if (!file_exists($filename)) { - throw new Exception('Camera configuration file does not exist: ' . $filename); + if (!file_exists($file)) { + throw new Exception('Camera configuration file does not exist: ' . $file); } - $content = ''; - - foreach ($options as $option) { - /** - * Comment the parameter with a semicolon in the final file if status sent is not 'enabled' - */ - if ($option['status'] == 'enabled') { - $optionStatus = ''; - } else { - $optionStatus = ';'; - } + /** + * Edit and overwrite current params with new params + */ + $this->edit($file, $params); - /** - * Check that option name is valid and does not contains invalid caracters - */ - if (\Controllers\Common::isAlphanumDash($option['name']) === false) { - throw new Exception('' . $option['name'] . ' parameter name contains invalid caracter(s)'); + /** + * Restart motion service if running + */ + if ($this->motionServiceController->isRunning()) { + if (!file_exists(DATA_DIR . '/motion.restart')) { + touch(DATA_DIR . '/motion.restart'); } + } + } - /** - * Case the option is 'netcam_url' or 'netcam_high_url' - */ - if ($option['status'] == 'enabled' and ($option['name'] == 'netcam_url' or $option['name'] == 'netcam_high_url')) { - /** - * Check that URL starts with http:// or https:// or rtsp:// - */ - if (!preg_match('#((^https?|rtsp)://)#', $option['value'])) { - throw new Exception('' . $option['name'] . ' parameter value must start with http:// or https:// or rtsp://'); - } - - if (\Controllers\Common::isAlphanumDash($option['value'], array('.', '/', ':', '=', '?', '&', '@')) === false) { - throw new Exception('' . $option['name'] . ' parameter value contains invalid caracter(s)'); - } - /** - * All other options - */ - } else { - if (\Controllers\Common::isAlphanumDash($option['value'], array('.', ' ', ',', ':', '/', '%Y', '%m', '%d', '%H', '%M', '%S', '%q', '%v', '%t', '%w', '%h', '%D', '%f', '%{eventid}', '%{fps}', '(', ')', '=', '\'', '[', ']', '@')) === false) { - throw new Exception('' . $option['name'] . ' parameter value contains invalid caracter(s)'); - } - } + /** + * Delete parameter from motion configuration file + */ + public function deleteParameter(int $id, string $param) + { + $file = CAMERAS_MOTION_CONF_AVAILABLE_DIR . '/camera-' . $id . '.conf'; - $optionName = \Controllers\Common::validateData($option['name']); - $optionValue = $option['value']; + /** + * First get current params + */ + $currentParams = $this->getConfig($file); - /** - * If there is no error then forge the parameter line with its name and value, separated by a space ' ' - * Else forge the same line but leave the value empty so that the user can re-enter it - */ - $content .= $optionStatus . $optionName . " " . $optionValue . PHP_EOL . PHP_EOL; - } + /** + * Delete param from current params + */ + unset($currentParams[$param]); /** - * Write to file + * Order params */ - if (file_exists($filename)) { - file_put_contents($filename, trim($content)); - } + ksort($currentParams); - unset($content); + /** + * Write new configuration + */ + $this->write($file, $currentParams); /** * Restart motion service if running diff --git a/www/controllers/ajax/motion.php b/www/controllers/ajax/motion.php index 012185d6..86ce0367 100644 --- a/www/controllers/ajax/motion.php +++ b/www/controllers/ajax/motion.php @@ -270,7 +270,7 @@ /** * Configure motion */ -if ($_POST['action'] == "configureMotion" and !empty($_POST['cameraId']) and !empty($_POST['params'])) { +if ($_POST['action'] == "configure-motion" and !empty($_POST['cameraId']) and !empty($_POST['params'])) { $mymotionConfig = new \Controllers\Motion\Config(); try { @@ -282,4 +282,19 @@ response(HTTP_OK, 'Configuration saved.'); } +/** + * Delete motion parameter from configuration file + */ +if ($_POST['action'] == 'delete-param-from-config' and !empty($_POST['cameraId']) and !empty($_POST['name'])) { + $mymotionConfig = new \Controllers\Motion\Config(); + + try { + $mymotionConfig->deleteParameter($_POST['cameraId'], $_POST['name']); + } catch (\Exception $e) { + response(HTTP_BAD_REQUEST, $e->getMessage()); + } + + response(HTTP_OK, 'Parameter deleted'); +} + response(HTTP_BAD_REQUEST, 'Invalid action'); diff --git a/www/public/assets/icons/cpu.svg b/www/public/assets/icons/cpu.svg index 373572de..3d62eb14 100644 --- a/www/public/assets/icons/cpu.svg +++ b/www/public/assets/icons/cpu.svg @@ -3,39 +3,46 @@ - - - + xmlns:svg="http://www.w3.org/2000/svg"> + + + + diff --git a/www/public/resources/js/motion.js b/www/public/resources/js/motion.js index bd03af8d..d61a1c00 100644 --- a/www/public/resources/js/motion.js +++ b/www/public/resources/js/motion.js @@ -383,12 +383,56 @@ $(document).on('click','.get-motion-config-form-btn',function () { }); /** - * Event: save motion configuration file + * Event: Collapse motion parameter div + */ +$(document).on('click','.motion-param-collapse-btn',function () { + var id = $(this).attr('param-id'); + + $('.motion-param-div[param-id=' + id + ']').toggle(); +}); + +/** + * Event: Delete motion parameter + */ +$(document).on('click','.motion-param-delete-btn',function (e) { + // Prevent parent to be triggered + e.stopPropagation(); + + var cameraId = $(this).attr('camera-id'); + var name = $(this).attr('param-name'); + + confirmBox('Are you sure you want to delete ' + name + ' parameter?', function () { + ajaxRequest( + // Controller: + 'motion', + // Action: + 'delete-param-from-config', + // Data: + { + cameraId: cameraId, + name: name + }, + // Print success alert: + true, + // Print error alert: + true, + // Reload containers: + [], + // Execute function on success: + [ + "reloadMotionConfigEditForm(" + cameraId + ");" + ] + ); + }, 'Delete'); +}); + +/** + * Event: edit motion configuration file */ $(document).on('submit','#camera-motion-settings-form',function () { event.preventDefault(); - var params = []; + var params = {}; /** * Get the name of the configuration file @@ -400,9 +444,9 @@ $(document).on('submit','#camera-motion-settings-form',function () { */ /** - * First count all span that has name=option-name in the form + * First count all span that has name=param-name in the form */ - var countTotal = $(this).find('span[name=option-name]').length + var countTotal = $(this).find('span[name=param-name]').length /** * Every configuration param and its value have an Id @@ -410,58 +454,47 @@ $(document).on('submit','#camera-motion-settings-form',function () { */ if (countTotal > 0) { for (let i = 0; i < countTotal; i++) { - /** - * Get parameter status (slider checked or not) - */ - if ($(this).find('input[name=option-status][option-id=' + i + ']').is(':checked')) { - var option_status = 'enabled'; - } else { - var option_status = ''; - } + var status = 'disabled'; /** * Get parameter name and its value */ - var option_name = $(this).find('span[name=option-name][option-id=' + i + ']').attr('value'); - var option_value = $(this).find('input[name=option-value][option-id=' + i + ']').val() + var name = $(this).find('span[name=param-name][param-id=' + i + ']').attr('value'); + var value = $(this).find('input[name=param-value][param-id=' + i + ']').val() + if ($(this).find('input[name=param-status][param-id=' + i + ']').is(':checked')) { + var status = 'enabled'; + } - /** - * Push all to params - */ - params.push( - { - status: option_status, - name: option_name, - value: option_value - } - ); + params[name] = { + status: status, + value: value + } } } /** * Add additional parameter if any */ - if ($(this).find('input[name=additional-option-status]').is(':checked')) { - var option_status = 'enabled'; - } else { - var option_status = ''; + var status = 'disabled'; + + var name = $(this).find('input[name=additional-param-name]').val(); + var value = $(this).find('input[name=additional-param-value]').val(); + if ($(this).find('input[name=additional-param-status]').is(':checked')) { + var status = 'enabled'; } - var option_name = $(this).find('input[name=additional-option-name]').val(); - var option_value = $(this).find('input[name=additional-option-value]').val(); - params.push( - { - status: option_status, - name: option_name, - value: option_value + if (name != '' && value != '') { + params[name] = { + status: status, + value: value } - ); + } ajaxRequest( // Controller: 'motion', // Action: - 'configureMotion', + 'configure-motion', // Data: { cameraId: cameraId, diff --git a/www/public/resources/styles/common.css b/www/public/resources/styles/common.css index 44f516ad..d58d21be 100644 --- a/www/public/resources/styles/common.css +++ b/www/public/resources/styles/common.css @@ -1,11 +1,16 @@ /** - * v1.11 + * v1.12 */ @font-face{font-family: 'Roboto'; src: url('/assets/fonts/Roboto/Roboto-Regular.ttf') format('truetype');} /** * Color picker * https://www.w3schools.com/colors/colors_picker.asp?colorhex=182b3e + * + * + * Contrast colors + * https://app.contrast-finder.org/ + * http://colorsafe.co/ */ body { @@ -24,7 +29,7 @@ a:hover { } p, label, a, i, span { - font-size: 14px; + font-size: 15px; color: white; } @@ -65,14 +70,36 @@ h5 { margin-bottom: 10px; } +/* Generally used for input forms */ +h6 { + line-height: 1.5em; + font-size: 13px; + font-weight: bold; + color: rgb(255 255 255 / 85%); + margin-top: 20px; + margin-bottom: 1px; +} + +.note { + font-size: 13.5px; + font-style: italic; + color: #8A99AA; + margin-bottom: 2px; +} + +.required::after { + content: ' *'; + font-size: 12px; + color: #F32F63; +} + hr { - border-color: gray; - opacity: 0.11; + border-color: #8a99aa57; } pre { font-family: monospace, monospace; - font-size: 12px; + font-size: 13px; } pre.codeblock { @@ -81,6 +108,7 @@ pre.codeblock { border-radius: 8px; font-size: 12px; line-height: 1.5; + text-align: left; padding: 20px; } @@ -100,12 +128,12 @@ pre.codeblock { .pointer { cursor: pointer; } .bold { font-weight: bold; } .greentext{color:#14be7e !important} -.redtext{color:#FF495C !important} +.redtext{color:#F32F63 !important} .yellowtext{color:#FCCA46 !important} .graytext { color : gray; } .bkg-green { background-color: #14be7e !important; color: white !important; } .bkg-yellow { background-color: #ffb536 !important; color: white !important; } -.bkg-red { background-color: #FF495C !important; color: white !important; } +.bkg-red { background-color: #F32F63 !important; color: white !important; } .bkg-gray { background-color: #cdcdcd8f !important; color: white !important; } .bck-blue { background-color: #182b3e !important} .bck-blue-alt {background-color: #1d3349 !important} @@ -113,7 +141,7 @@ pre.codeblock { .center { text-align: center; } .baseline { vertical-align: baseline; } .vertical-align-text-top{vertical-align: text-top !important} -.font-size-11{font-size: 11px !important}.font-size-12{font-size: 12px !important}.font-size-13{font-size: 13px !important}.font-size-14{font-size: 14px !important}.font-size-15{font-size: 15px !important}.font-size-16{font-size: 16px !important}.font-size-17{font-size: 17px !important}.font-size-18{font-size: 18px !important}.font-size-20{font-size: 20px !important}.font-size-22{font-size: 22px !important} +.font-size-10{font-size:10px !important}.font-size-11{font-size: 11px !important}.font-size-12{font-size: 12px !important}.font-size-13{font-size: 13px !important}.font-size-14{font-size: 14px !important}.font-size-15{font-size: 15px !important}.font-size-16{font-size: 16px !important}.font-size-17{font-size: 17px !important}.font-size-18{font-size: 18px !important}.font-size-20{font-size: 20px !important}.font-size-22{font-size: 22px !important} .mediumopacity,.mediumopacity-cst{opacity: 0.55} .lowopacity,.lowopacity-cst{opacity: 0.60} /* lowopacity-cst is used for constant lowopacity even on hover */ .opacity-80,.opacity-80-cst{opacity: 0.80} @@ -132,6 +160,7 @@ pre.codeblock { .grid-2 {grid-template-columns: 1fr 1fr !important} .grid-2-1 {grid-template-columns: 2fr 1fr !important} .grid-3 {grid-template-columns: 1fr 1fr 1fr !important} +.grid-4 {grid-template-columns: 1fr 1fr 1fr 1fr !important} .grid-fr-1-2 {grid-template-columns: 1fr 2fr !important} .grid-fr-2-1 {grid-template-columns: 2fr 1fr !important} .grid-fr-4-1 {grid-template-columns: 4fr 1fr !important} @@ -154,7 +183,7 @@ pre.codeblock { .column-gap-20{column-gap: 20px}.column-gap-30{column-gap: 30px}.column-gap-40{column-gap: 40px}.column-gap-50{column-gap: 50px}.column-gap-60{column-gap: 60px}.column-gap-70{column-gap: 70px}.column-gap-80{column-gap: 80px}.column-gap-90{column-gap: 90px}.column-gap-100{column-gap: 100px} .row-gap-1 {row-gap: 1px}.row-gap-2 {row-gap: 2px}.row-gap-4 {row-gap: 4px}.row-gap-5 {row-gap: 5px}.row-gap-6 {row-gap: 6px}.row-gap-7 {row-gap: 7px}.row-gap-8 {row-gap: 8px}.row-gap-9{row-gap: 9px}.row-gap-10{row-gap: 10px}.row-gap-15{row-gap: 15px}.row-gap-20{row-gap: 20px} .padding-left-15{padding-left:15px !important}.padding-left-20{padding-left:20px !important}.padding-left-30{padding-left:30px !important}.padding-left-40{padding-left:40px !important} -.padding-right-15{padding-right:15px !important}.padding-right-20{padding-right:20px !important}.paddin-right-30{padding-right:30px !important}.padding-right-40{padding-right:40px !important} +.padding-right-15{padding-right:15px !important}.padding-right-20{padding-right:20px !important}.padding-right-30{padding-right:30px !important}.padding-right-40{padding-right:40px !important} .margin-left-0 {margin-left: 0px !important}.margin-left-5 {margin-left: 5px !important}.margin-left-10 {margin-left: 10px !important}.margin-left-15 {margin-left: 15px !important}.margin-left-20 {margin-left: 20px !important}.margin-left-30 {margin-left: 30px !important}.margin-left-40 {margin-left: 40px !important} .margin-right-0 {margin-right: 0px !important}.margin-right-5 {margin-right: 5px !important}.margin-right-10 {margin-right: 10px !important}.margin-right-15 {margin-right: 15px !important}.margin-right-20 {margin-right: 20px !important}.margin-right-30 {margin-right: 30px !important}.margin-right-40 {margin-right: 40px !important} .margin-top-0 {margin-top: 0px !important}.margin-top-5 {margin-top: 5px !important}.margin-top-10 {margin-top: 10px !important}.margin-top-15 {margin-top: 15px !important}.margin-top-20 {margin-top: 20px !important}.margin-top-30 {margin-top: 30px !important}.margin-top-40 {margin-top: 40px !important} @@ -169,7 +198,7 @@ code { color: white; background-color: #3c434d; padding: .2em .4em; - border-radius: 6px; + border-radius: 50px; } /** @@ -180,7 +209,6 @@ table { font-size: 14px; table-layout: auto !important; } -.table-large { width: 100%; } th { text-align: left; @@ -192,22 +220,12 @@ td { vertical-align: middle; color: white; } -.td-fit { - width: 1% !important; - white-space: nowrap !important; - padding-left: 2px; - padding-right: 2px; -} -.td-small { width: 200px; } -.td-medium { width: 300px; } -.td-large { width: 500px; } -.td-10, .td-30, .td-50, .td-100 { + +.td-50, .td-100 { width: 0px; margin: 0px; white-space: nowrap; } -.td-10 { padding-right: 10px !important; } -.td-30 { padding-right: 30px !important; } .td-50 { padding-right: 50px !important; } .td-100 { padding-right: 100px !important; } @@ -239,7 +257,7 @@ td { font-weight: bold; } .table-generic-blue tr { background-color: #1d3349; } -.table-generic-red tr { background-color: #FF495C; } +.table-generic-red tr { background-color: #F32F63; } /** * Generic table with pagination @@ -264,27 +282,13 @@ td { grid-template-columns: 5% auto 10%; } -/* Generally used for input forms */ -h6 { - line-height: 1.5em; - font-size: 13px; - font-weight: bold; - color: rgb(255 255 255 / 80%); - margin-top: 15px; - margin-bottom: 5px; -} -.input-note { - font-size: 12.5px; - color: #606b76; -} - /** * Icons */ .icon, .icon-small, .icon-medium, .icon-lowopacity, .icon-mediumopacity, .icon-nf, .icon-np { - height: 15px; - /* margin-left: 5px; - margin-right: 5px; */ + /* height: 16px; */ + /* height: 17px; */ + height: 19px; vertical-align: middle; cursor: pointer; } @@ -387,7 +391,7 @@ input[type=checkbox]:not(.onoff-switch-input):checked { display: inline-block; font-size: 14px; cursor: pointer; - box-shadow: rgba(12, 18, 20, 0.504) 0px 0px 10px 1px; + box-shadow: rgba(12, 18, 20, 0.504) 0px 0px 5px 1px; } /* All transparent buttons */ @@ -408,30 +412,30 @@ input[type=checkbox]:not(.onoff-switch-input):checked { } /* All red buttons */ .btn-large-red, .btn-medium-red, .btn-small-red, .btn-xsmall-red, .btn-xxsmall-red, .btn-fit-red, .round-btn-red { - background-color: #FF495C; + background-color: #F32F63; } /* All yellow buttons */ .btn-large-yellow, .btn-medium-yellow, .btn-small-yellow, .btn-xsmall-yellow, .btn-xxsmall-yellow, .btn-fit-yellow, .round-btn-yellow { background-color: #ffb536; } /* All large buttons */ -.btn-large, .btn-large-blue, .btn-large-green, .btn-large-red { +.btn-large, .btn-large-blue, .btn-large-green, .btn-large-red, .btn-large-tr { width: 100%; } /* All medium buttons */ -.btn-medium, .btn-medium-blue, .btn-medium-green, .btn-medium-red { +.btn-medium, .btn-medium-blue, .btn-medium-green, .btn-medium-red, .btn-medium-tr { width: 150px; } /* All small buttons */ -.btn-small, .btn-small-blue, .btn-small-green, .btn-small-red { +.btn-small, .btn-small-blue, .btn-small-green, .btn-small-red, .btn-small-tr { width: 100px; } /* All very small buttons */ -.btn-xsmall, .btn-xsmall-blue, .btn-xsmall-green, .btn-xsmall-red { +.btn-xsmall, .btn-xsmall-blue, .btn-xsmall-green, .btn-xsmall-red, .btn-xsmall-tr { width: 50px; } /* All very very small buttons */ -.btn-xxsmall, .btn-xxsmall-blue, .btn-xxsmall-green, .btn-xxsmall-red { +.btn-xxsmall, .btn-xxsmall-blue, .btn-xxsmall-green, .btn-xxsmall-red, .btn-xxsmall-tr { margin: 2px; width: 30px; } @@ -446,8 +450,8 @@ input[type=checkbox]:not(.onoff-switch-input):checked { /* All transparent to red buttons (hover) */ .btn-large-tr-to-red:hover, .btn-medium-tr-to-red:hover, .btn-small-tr-to-red:hover, .btn-xsmall-tr-to-red:hover, .btn-xxsmall-tr-to-red:hover, .btn-fit-tr-to-red:hover, .round-btn-tr-to-red:hover { transition-duration: 0.2s; - background-color: #ff3347; - border: 1px solid #ff3347; + background-color: #f10e4b; + border: 1px solid #f10e4b; opacity: 1; } @@ -464,7 +468,7 @@ input[type=checkbox]:not(.onoff-switch-input):checked { /* All red buttons (hover) */ .btn-large-red:hover, .btn-medium-red:hover, .btn-small-red:hover, .btn-xsmall-red:hover, .btn-xxsmall-red:hover, .btn-fit-red:hover, .round-btn-red:hover { transition-duration: 0.2s; - background-color: #ff3347; + background-color: #f10e4b; } /** @@ -522,10 +526,10 @@ input[type=checkbox]:not(.onoff-switch-input):checked { padding-left: 8px; } .slide-btn-red { - background-color: #FF495C; + background-color: #F32F63; } .slide-btn-red:hover { - background-color: #ff3347; + background-color: #f10e4b; } .slide-btn-yellow { background-color: #eb984e; @@ -612,48 +616,6 @@ textarea { border-radius: 60px; } -/* Green checkmark, red crossmark and yellow pending icons */ -.checkmark, .crossmark, .pending { - display: inline-block; - position: relative; - min-width: 14px; - min-height: 14px; - max-width: 14px; - max-height: 14px; - border-radius: 50%; - text-align: center; - vertical-align: middle; - font-size: 12px; -} -.checkmark { - background-color: #15bf7f; -} -.crossmark { - background-color: #FF495C; -} -.pending { - background-color: #ffb536; -} -.checkmark::after, .crossmark::after, .pending::after { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - line-height: 1; -} -.checkmark::after { - content: '✔'; - color: white; -} -.crossmark::after { - content: '🞪'; - color: white; -} -.pending::after { - content: '⧗'; - color: white; -} - .label-black, .label-white, .label-green, .label-blue, .label-red, .label-yellow { font-size: 13px; vertical-align: middle; @@ -683,7 +645,7 @@ textarea { background-color: #5473e8; } .label-red { - background-color: #FF495C; + background-color: #F32F63; } .label-yellow { background-color: #ffb536; @@ -867,7 +829,7 @@ textarea { grid-template-columns: repeat(3, 33%); } .alert-success { background-color: #14be7e; } -.alert-error { background-color: #FF495C; } +.alert-error { background-color: #F32F63; } .alert span, .alert-success span, .alert-error span, .confirmAlert span, .alert a, .alert-success a, .alert-error a, .confirmAlert a { font-size: 16px; @@ -886,10 +848,10 @@ textarea { box-shadow: rgb(12 18 20 / 67%) 0px 0px 0px 1px; } [class*="btn-doConfirm"] { - background-color: #FF495C; + background-color: #F32F63; } [class*="btn-doConfirm"]:hover { - background-color: #ff3347; + background-color: #f10e4b; } .btn-doGeneric:hover { background-color: #1d3349; @@ -983,6 +945,16 @@ textarea { margin-top: 0; } +.details-div { + padding: 10px; + background-color: #182b3e; + border-left: 1px solid #24405c; + border-right: 1px solid #24405c; + border-bottom: 1px solid #24405c; + border-top: none; + border-radius: 8px; +} + /* Desktop configuration */ @media (min-width:1025px) { /** diff --git a/www/public/resources/styles/motionui.css b/www/public/resources/styles/motionui.css index 323a29cf..624a86e5 100644 --- a/www/public/resources/styles/motionui.css +++ b/www/public/resources/styles/motionui.css @@ -247,8 +247,18 @@ h3 { #motion-events-captures-acquit-container { position: fixed; - bottom: 80px; - right: 20px; + bottom: 85px; + right: 25px; +} + +#motion-events-captures-acquit-container .acquit-events-btn { + min-width: 50px; + height: 50px !important; +} + +#motion-events-captures-acquit-container .acquit-events-btn img { + width: 37px !important; + padding-left: 7px !important; } .event-container { @@ -287,8 +297,14 @@ h3 { flex-direction: row; justify-content: space-between; align-items: center; - width: 90%; - margin-bottom: 15px; + width: 95%; +} + +.event-camera-name-id { + display: flex; + flex-direction: column; + align-items: flex-end; + row-gap: 10px; } .event-camera { @@ -633,7 +649,7 @@ footer #github img { width: 25px; } } .select-all-media-checkbox { - margin-right: 10px; + margin-right: 14px; } .event-media-checkbox-container { @@ -800,8 +816,6 @@ footer #github img { width: 25px; } border-radius: 0 250px 250px 0; } - /* toto */ - .main-container { grid-template-columns: repeat(1, 100%); justify-content: space-around; @@ -848,6 +862,11 @@ footer #github img { width: 25px; } margin-bottom: 0; } + .event-camera-name-id { + align-items: center; + row-gap: 20px; + } + .event-media-checkbox, .select-all-media-checkbox { width: 22px !important; height: 22px !important; diff --git a/www/version b/www/version index 28cbf7c0..acf69b48 100644 --- a/www/version +++ b/www/version @@ -1 +1 @@ -5.0.0 \ No newline at end of file +5.1.0 \ No newline at end of file diff --git a/www/views/includes/camera/edit/form.inc.php b/www/views/includes/camera/edit/form.inc.php index 52a4f847..f2c3dff0 100644 --- a/www/views/includes/camera/edit/form.inc.php +++ b/www/views/includes/camera/edit/form.inc.php @@ -2,15 +2,15 @@

#

-

Global settings

- -
NAME
+
NAME
-
DEVICE or URL
+
DEVICE or URL
+

Device path like /dev/video0 or URL like http://... or rtsp://... are supported.

-
RESOLUTION
+
RESOLUTION
+

The selected resolution should match the resolution of the camera.

FRAME RATE
-

Set to 0 to use the default frame rate of the camera.

+

Set to 0 to use the default frame rate of the camera.

ROTATE
-

Set to 0 to disable rotation.

+

Set to 0 to disable rotation.

TEXT LEFT
+

Text to display on the left side of the camera feed.

TEXT RIGHT
+

Text to display on the right side of the camera feed.

TIMESTAMP LEFT
+

Display timestamp on the left side of the camera feed.

TIMESTAMP RIGHT
+

Display timestamp on the right side of the camera feed.