mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2025-01-27 22:46:01 -05:00
Add "Copy config" option to "Add camera" dialog
This commit is contained in:
parent
1fde947f36
commit
81ea7d8a87
@ -5,7 +5,7 @@
|
|||||||
use crate::stream::{self, Opener};
|
use crate::stream::{self, Opener};
|
||||||
use base::strutil::{decode_size, encode_size};
|
use base::strutil::{decode_size, encode_size};
|
||||||
use cursive::traits::{Finder, Nameable, Resizable, Scrollable};
|
use cursive::traits::{Finder, Nameable, Resizable, Scrollable};
|
||||||
use cursive::views::{self, ViewRef};
|
use cursive::views::{self, Dialog, ViewRef};
|
||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
use db::writer;
|
use db::writer;
|
||||||
use failure::{bail, format_err, Error, ResultExt};
|
use failure::{bail, format_err, Error, ResultExt};
|
||||||
@ -434,6 +434,127 @@ fn edit_stream_url(type_: db::StreamType, content: &str, mut test_button: ViewRe
|
|||||||
test_button.set_enabled(enable_test);
|
test_button.set_enabled(enable_test);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_camera_values(
|
||||||
|
db: &Arc<db::Database>,
|
||||||
|
camera_id: i32,
|
||||||
|
dialog: &mut Dialog,
|
||||||
|
overwrite_uuid: bool,
|
||||||
|
) -> (String, i64) {
|
||||||
|
let dirs: Vec<_> = ::std::iter::once(("<none>".into(), None))
|
||||||
|
.chain(
|
||||||
|
db.lock()
|
||||||
|
.sample_file_dirs_by_id()
|
||||||
|
.iter()
|
||||||
|
.map(|(&id, d)| (d.path.to_owned(), Some(id))),
|
||||||
|
)
|
||||||
|
.collect();
|
||||||
|
let l = db.lock();
|
||||||
|
let camera = l.cameras_by_id().get(&camera_id).expect("missing camera");
|
||||||
|
if overwrite_uuid {
|
||||||
|
dialog
|
||||||
|
.call_on_name("uuid", |v: &mut views::TextView| {
|
||||||
|
v.set_content(camera.uuid.to_string())
|
||||||
|
})
|
||||||
|
.expect("missing TextView");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut bytes = 0;
|
||||||
|
for (i, sid) in camera.streams.iter().enumerate() {
|
||||||
|
let t = db::StreamType::from_index(i).unwrap();
|
||||||
|
|
||||||
|
// Find the index into dirs of the stored sample file dir.
|
||||||
|
let mut selected_dir = 0;
|
||||||
|
if let Some(s) = sid.map(|sid| l.streams_by_id().get(&sid).unwrap()) {
|
||||||
|
if let Some(id) = s.sample_file_dir_id {
|
||||||
|
for (i, &(_, d_id)) in dirs.iter().skip(1).enumerate() {
|
||||||
|
if Some(id) == d_id {
|
||||||
|
selected_dir = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bytes += s.sample_file_bytes;
|
||||||
|
let u = if s.config.retain_bytes == 0 {
|
||||||
|
"0 / 0 (0.0%)".to_owned()
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
"{} / {} ({:.1}%)",
|
||||||
|
s.fs_bytes,
|
||||||
|
s.config.retain_bytes,
|
||||||
|
100. * s.fs_bytes as f32 / s.config.retain_bytes as f32
|
||||||
|
)
|
||||||
|
};
|
||||||
|
dialog.call_on_name(&format!("{}_url", t.as_str()), |v: &mut views::EditView| {
|
||||||
|
if let Some(url) = s.config.url.as_ref() {
|
||||||
|
v.set_content(url.as_str().to_owned());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let test_button = dialog
|
||||||
|
.find_name::<views::Button>(&format!("{}_test", t.as_str()))
|
||||||
|
.unwrap();
|
||||||
|
edit_stream_url(
|
||||||
|
t,
|
||||||
|
s.config.url.as_ref().map(Url::as_str).unwrap_or(""),
|
||||||
|
test_button,
|
||||||
|
);
|
||||||
|
dialog.call_on_name(
|
||||||
|
&format!("{}_usage_cap", t.as_str()),
|
||||||
|
|v: &mut views::TextView| v.set_content(u),
|
||||||
|
);
|
||||||
|
dialog.call_on_name(
|
||||||
|
&format!("{}_record", t.as_str()),
|
||||||
|
|v: &mut views::Checkbox| {
|
||||||
|
v.set_checked(s.config.mode == db::json::STREAM_MODE_RECORD)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
dialog.call_on_name(
|
||||||
|
&format!("{}_rtsp_transport", t.as_str()),
|
||||||
|
|v: &mut views::SelectView<&'static str>| {
|
||||||
|
v.set_selection(match s.config.rtsp_transport.as_str() {
|
||||||
|
"tcp" => 1,
|
||||||
|
"udp" => 2,
|
||||||
|
_ => 0,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
);
|
||||||
|
dialog.call_on_name(&format!("{}_flush_if_sec", t), |v: &mut views::EditView| {
|
||||||
|
v.set_content(s.config.flush_if_sec.to_string())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
log::debug!("setting {} dir to {}", t.as_str(), selected_dir);
|
||||||
|
dialog.call_on_name(
|
||||||
|
&format!("{}_sample_file_dir", t),
|
||||||
|
|v: &mut views::SelectView<Option<i32>>| v.set_selection(selected_dir),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let name = camera.short_name.clone();
|
||||||
|
for &(view_id, content) in &[
|
||||||
|
("short_name", &*camera.short_name),
|
||||||
|
(
|
||||||
|
"onvif_base_url",
|
||||||
|
camera
|
||||||
|
.config
|
||||||
|
.onvif_base_url
|
||||||
|
.as_ref()
|
||||||
|
.map_or("", Url::as_str),
|
||||||
|
),
|
||||||
|
("username", &camera.config.username),
|
||||||
|
("password", &camera.config.password),
|
||||||
|
] {
|
||||||
|
dialog
|
||||||
|
.call_on_name(view_id, |v: &mut views::EditView| {
|
||||||
|
v.set_content(content.to_string())
|
||||||
|
})
|
||||||
|
.expect("missing EditView");
|
||||||
|
}
|
||||||
|
dialog
|
||||||
|
.call_on_name("description", |v: &mut views::TextArea| {
|
||||||
|
v.set_content(camera.config.description.clone())
|
||||||
|
})
|
||||||
|
.expect("missing TextArea");
|
||||||
|
(name, bytes)
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds or updates a camera.
|
/// Adds or updates a camera.
|
||||||
/// (The former if `item` is None; the latter otherwise.)
|
/// (The former if `item` is None; the latter otherwise.)
|
||||||
fn edit_camera_dialog(db: &Arc<db::Database>, siv: &mut Cursive, item: &Option<i32>) {
|
fn edit_camera_dialog(db: &Arc<db::Database>, siv: &mut Cursive, item: &Option<i32>) {
|
||||||
@ -525,108 +646,7 @@ fn edit_camera_dialog(db: &Arc<db::Database>, siv: &mut Cursive, item: &Option<i
|
|||||||
|
|
||||||
let mut dialog = views::Dialog::around(layout.scrollable());
|
let mut dialog = views::Dialog::around(layout.scrollable());
|
||||||
let dialog = if let Some(camera_id) = *item {
|
let dialog = if let Some(camera_id) = *item {
|
||||||
let l = db.lock();
|
let (name, bytes) = load_camera_values(db, camera_id, &mut dialog, true);
|
||||||
let camera = l.cameras_by_id().get(&camera_id).expect("missing camera");
|
|
||||||
dialog
|
|
||||||
.call_on_name("uuid", |v: &mut views::TextView| {
|
|
||||||
v.set_content(camera.uuid.to_string())
|
|
||||||
})
|
|
||||||
.expect("missing TextView");
|
|
||||||
|
|
||||||
let mut bytes = 0;
|
|
||||||
for (i, sid) in camera.streams.iter().enumerate() {
|
|
||||||
let t = db::StreamType::from_index(i).unwrap();
|
|
||||||
|
|
||||||
// Find the index into dirs of the stored sample file dir.
|
|
||||||
let mut selected_dir = 0;
|
|
||||||
if let Some(s) = sid.map(|sid| l.streams_by_id().get(&sid).unwrap()) {
|
|
||||||
if let Some(id) = s.sample_file_dir_id {
|
|
||||||
for (i, &(_, d_id)) in dirs.iter().skip(1).enumerate() {
|
|
||||||
if Some(id) == d_id {
|
|
||||||
selected_dir = i + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bytes += s.sample_file_bytes;
|
|
||||||
let u = if s.config.retain_bytes == 0 {
|
|
||||||
"0 / 0 (0.0%)".to_owned()
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"{} / {} ({:.1}%)",
|
|
||||||
s.fs_bytes,
|
|
||||||
s.config.retain_bytes,
|
|
||||||
100. * s.fs_bytes as f32 / s.config.retain_bytes as f32
|
|
||||||
)
|
|
||||||
};
|
|
||||||
dialog.call_on_name(&format!("{}_url", t.as_str()), |v: &mut views::EditView| {
|
|
||||||
if let Some(url) = s.config.url.as_ref() {
|
|
||||||
v.set_content(url.as_str().to_owned());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let test_button = dialog
|
|
||||||
.find_name::<views::Button>(&format!("{}_test", t.as_str()))
|
|
||||||
.unwrap();
|
|
||||||
edit_stream_url(
|
|
||||||
t,
|
|
||||||
s.config.url.as_ref().map(Url::as_str).unwrap_or(""),
|
|
||||||
test_button,
|
|
||||||
);
|
|
||||||
dialog.call_on_name(
|
|
||||||
&format!("{}_usage_cap", t.as_str()),
|
|
||||||
|v: &mut views::TextView| v.set_content(u),
|
|
||||||
);
|
|
||||||
dialog.call_on_name(
|
|
||||||
&format!("{}_record", t.as_str()),
|
|
||||||
|v: &mut views::Checkbox| {
|
|
||||||
v.set_checked(s.config.mode == db::json::STREAM_MODE_RECORD)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
dialog.call_on_name(
|
|
||||||
&format!("{}_rtsp_transport", t.as_str()),
|
|
||||||
|v: &mut views::SelectView<&'static str>| {
|
|
||||||
v.set_selection(match s.config.rtsp_transport.as_str() {
|
|
||||||
"tcp" => 1,
|
|
||||||
"udp" => 2,
|
|
||||||
_ => 0,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
);
|
|
||||||
dialog.call_on_name(&format!("{}_flush_if_sec", t), |v: &mut views::EditView| {
|
|
||||||
v.set_content(s.config.flush_if_sec.to_string())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
log::debug!("setting {} dir to {}", t.as_str(), selected_dir);
|
|
||||||
dialog.call_on_name(
|
|
||||||
&format!("{}_sample_file_dir", t),
|
|
||||||
|v: &mut views::SelectView<Option<i32>>| v.set_selection(selected_dir),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let name = camera.short_name.clone();
|
|
||||||
for &(view_id, content) in &[
|
|
||||||
("short_name", &*camera.short_name),
|
|
||||||
(
|
|
||||||
"onvif_base_url",
|
|
||||||
camera
|
|
||||||
.config
|
|
||||||
.onvif_base_url
|
|
||||||
.as_ref()
|
|
||||||
.map_or("", Url::as_str),
|
|
||||||
),
|
|
||||||
("username", &camera.config.username),
|
|
||||||
("password", &camera.config.password),
|
|
||||||
] {
|
|
||||||
dialog
|
|
||||||
.call_on_name(view_id, |v: &mut views::EditView| {
|
|
||||||
v.set_content(content.to_string())
|
|
||||||
})
|
|
||||||
.expect("missing EditView");
|
|
||||||
}
|
|
||||||
dialog
|
|
||||||
.call_on_name("description", |v: &mut views::TextArea| {
|
|
||||||
v.set_content(camera.config.description.clone())
|
|
||||||
})
|
|
||||||
.expect("missing TextArea");
|
|
||||||
dialog
|
dialog
|
||||||
.title("Edit camera")
|
.title("Edit camera")
|
||||||
.button("Edit", {
|
.button("Edit", {
|
||||||
@ -644,14 +664,47 @@ fn edit_camera_dialog(db: &Arc<db::Database>, siv: &mut Cursive, item: &Option<i
|
|||||||
|v: &mut views::TextView| v.set_content("<new>"),
|
|v: &mut views::TextView| v.set_content("<new>"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
dialog.title("Add camera").button("Add", {
|
dialog
|
||||||
let db = db.clone();
|
.title("Add camera")
|
||||||
move |s| press_edit(s, &db, None)
|
.button("Add", {
|
||||||
})
|
let db = db.clone();
|
||||||
|
move |s| press_edit(s, &db, None)
|
||||||
|
})
|
||||||
|
.button("Copy config", {
|
||||||
|
let db = db.clone();
|
||||||
|
move |s| copy_camera_dialog(s, &db)
|
||||||
|
})
|
||||||
};
|
};
|
||||||
siv.add_layer(dialog.dismiss_button("Cancel"));
|
siv.add_layer(dialog.dismiss_button("Cancel"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn copy_camera_dialog(siv: &mut Cursive, db: &Arc<db::Database>) {
|
||||||
|
siv.add_layer(
|
||||||
|
views::Dialog::around(
|
||||||
|
views::SelectView::new()
|
||||||
|
.with_all(
|
||||||
|
db.lock()
|
||||||
|
.cameras_by_id()
|
||||||
|
.iter()
|
||||||
|
.map(|(&id, camera)| (format!("{}: {}", id, camera.short_name), id)),
|
||||||
|
)
|
||||||
|
.on_submit({
|
||||||
|
let db = db.clone();
|
||||||
|
move |siv, &camera_id| {
|
||||||
|
siv.pop_layer();
|
||||||
|
let screen = siv.screen_mut();
|
||||||
|
let dialog = screen.get_mut(views::LayerPosition::FromFront(0)).unwrap();
|
||||||
|
let dialog = dialog.downcast_mut::<Dialog>().unwrap();
|
||||||
|
load_camera_values(&db, camera_id, dialog, false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.full_width(),
|
||||||
|
)
|
||||||
|
.dismiss_button("Cancel")
|
||||||
|
.title("Select camera to copy"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn top_dialog(db: &Arc<db::Database>, siv: &mut Cursive) {
|
pub fn top_dialog(db: &Arc<db::Database>, siv: &mut Cursive) {
|
||||||
siv.add_layer(
|
siv.add_layer(
|
||||||
views::Dialog::around(
|
views::Dialog::around(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user