mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2025-01-26 22:23:16 -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 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(
|
||||
|
Loading…
x
Reference in New Issue
Block a user