Add "Copy config" option to "Add camera" dialog

This commit is contained in:
Skye 2023-07-01 13:47:37 -04:00 committed by Scott Lamb
parent 1fde947f36
commit 81ea7d8a87

View File

@ -5,7 +5,7 @@
use crate::stream::{self, Opener};
use base::strutil::{decode_size, encode_size};
use cursive::traits::{Finder, Nameable, Resizable, Scrollable};
use cursive::views::{self, ViewRef};
use cursive::views::{self, Dialog, ViewRef};
use cursive::Cursive;
use db::writer;
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);
}
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.
/// (The former if `item` is None; the latter otherwise.)
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 dialog = if let Some(camera_id) = *item {
let l = db.lock();
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");
let (name, bytes) = load_camera_values(db, camera_id, &mut dialog, true);
dialog
.title("Edit camera")
.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>"),
);
}
dialog.title("Add camera").button("Add", {
let db = db.clone();
move |s| press_edit(s, &db, None)
})
dialog
.title("Add camera")
.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"));
}
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) {
siv.add_layer(
views::Dialog::around(