meli/ui/src/components/contacts/contact_list.rs

319 lines
9.3 KiB
Rust
Raw Normal View History

2019-02-21 15:31:01 +02:00
use super::*;
2019-02-26 17:50:47 +02:00
use melib::CardId;
2019-02-21 15:31:01 +02:00
const MAX_COLS: usize = 500;
#[derive(Debug, PartialEq)]
enum ViewMode {
List,
2019-02-26 17:50:47 +02:00
View(CardId),
2019-02-21 15:31:01 +02:00
}
#[derive(Debug)]
pub struct ContactList {
cursor_pos: usize,
new_cursor_pos: usize,
account_pos: usize,
length: usize,
content: CellBuffer,
2019-02-26 17:50:47 +02:00
id_positions: Vec<CardId>,
2019-03-14 12:19:25 +02:00
2019-02-21 15:31:01 +02:00
mode: ViewMode,
dirty: bool,
2019-04-10 22:01:02 +03:00
view: Option<Box<Component>>,
id: ComponentId,
2019-02-21 15:31:01 +02:00
}
impl Default for ContactList {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for ContactList {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", ContactList::DESCRIPTION)
2019-02-21 15:31:01 +02:00
}
}
impl ContactList {
const DESCRIPTION: &'static str = "contact list";
2019-02-21 15:31:01 +02:00
pub fn new() -> Self {
let content = CellBuffer::new(0, 0, Cell::with_char(' '));
ContactList {
cursor_pos: 0,
new_cursor_pos: 0,
length: 0,
account_pos: 0,
2019-02-21 15:44:26 +02:00
id_positions: Vec::new(),
2019-02-21 15:31:01 +02:00
mode: ViewMode::List,
content,
dirty: true,
view: None,
2019-04-11 00:04:17 +03:00
id: ComponentId::new_v4(),
2019-02-21 15:31:01 +02:00
}
}
2019-02-26 17:50:47 +02:00
pub fn for_account(pos: usize) -> Self {
ContactList {
account_pos: pos,
..Self::new()
}
}
2019-03-14 12:19:25 +02:00
2019-02-21 15:31:01 +02:00
fn initialize(&mut self, context: &mut Context) {
let account = &mut context.accounts[self.account_pos];
let book = &mut account.address_book;
2019-02-25 12:14:44 +02:00
self.length = book.len();
2019-03-14 12:19:25 +02:00
self.content
2019-03-31 20:08:04 +03:00
.resize(MAX_COLS, book.len() + 1, Cell::with_char(' '));
clear_area(&mut self.content, ((0, 0), (MAX_COLS - 1, self.length)));
2019-02-21 15:31:01 +02:00
2019-02-21 15:44:26 +02:00
self.id_positions.clear();
if self.id_positions.capacity() < book.len() {
2019-03-14 12:19:25 +02:00
self.id_positions.reserve(book.len());
2019-02-21 15:31:01 +02:00
}
let mut maxima = ("Name".len(), "E-mail".len());
2019-02-21 15:31:01 +02:00
2019-03-31 20:08:04 +03:00
for c in book.values() {
self.id_positions.push(*c.id());
maxima.0 = std::cmp::max(maxima.0, c.name().split_graphemes().len());
maxima.1 = std::cmp::max(maxima.1, c.email().split_graphemes().len());
2019-03-31 20:08:04 +03:00
}
maxima.0 += 5;
maxima.1 += maxima.0 + 5;
2019-07-06 20:36:59 +03:00
let (x, _) = write_string_to_grid(
"NAME",
2019-03-31 20:08:04 +03:00
&mut self.content,
2019-07-06 20:36:59 +03:00
Color::Black,
Color::White,
Attr::Default,
2019-03-31 20:08:04 +03:00
((0, 0), (MAX_COLS - 1, self.length)),
false,
2019-04-04 14:24:05 +03:00
);
2019-07-06 20:36:59 +03:00
for x in x..maxima.0 {
self.content[(x, 0)].set_bg(Color::White);
}
2019-03-31 20:08:04 +03:00
write_string_to_grid(
2019-07-06 20:36:59 +03:00
"E-MAIL",
2019-03-31 20:08:04 +03:00
&mut self.content,
2019-07-06 20:36:59 +03:00
Color::Black,
Color::White,
Attr::Default,
((maxima.0, 0), (MAX_COLS - 1, self.length)),
2019-03-31 20:08:04 +03:00
false,
2019-04-04 14:24:05 +03:00
);
2019-07-06 20:36:59 +03:00
for x in x..maxima.1 {
self.content[(x, 0)].set_bg(Color::White);
}
2019-03-31 20:08:04 +03:00
write_string_to_grid(
"URL",
&mut self.content,
2019-07-06 20:36:59 +03:00
Color::Black,
Color::White,
Attr::Default,
((maxima.1, 0), (MAX_COLS - 1, self.length)),
2019-03-31 20:08:04 +03:00
false,
2019-04-04 14:24:05 +03:00
);
2019-07-06 20:36:59 +03:00
for x in x..(MAX_COLS - 1) {
self.content[(x, 0)].set_bg(Color::White);
}
2019-02-21 15:31:01 +02:00
for (i, c) in book.values().enumerate() {
2019-02-21 15:44:26 +02:00
self.id_positions.push(*c.id());
2019-03-14 12:19:25 +02:00
2019-03-31 20:08:04 +03:00
write_string_to_grid(
c.name(),
2019-03-31 20:08:04 +03:00
&mut self.content,
Color::Default,
Color::Default,
Attr::Default,
2019-03-31 20:08:04 +03:00
((0, i + 1), (MAX_COLS - 1, self.length)),
false,
);
2019-02-21 15:31:01 +02:00
write_string_to_grid(
c.email(),
&mut self.content,
Color::Default,
Color::Default,
Attr::Default,
((maxima.0, i + 1), (MAX_COLS - 1, self.length)),
2019-03-31 20:08:04 +03:00
false,
);
write_string_to_grid(
c.url(),
2019-04-04 14:24:05 +03:00
&mut self.content,
Color::Default,
2019-03-31 20:08:04 +03:00
Color::Default,
Attr::Default,
((maxima.1, i + 1), (MAX_COLS - 1, self.length)),
2019-03-14 12:19:25 +02:00
false,
);
2019-02-21 15:31:01 +02:00
}
}
}
impl Component for ContactList {
fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
if let Some(mgr) = self.view.as_mut() {
mgr.draw(grid, area, context);
return;
}
if self.dirty {
self.initialize(context);
2019-03-14 12:19:25 +02:00
copy_area(
grid,
&self.content,
area,
(
(0, 0),
(MAX_COLS - 1, self.content.size().1.saturating_sub(1)),
),
);
2019-02-21 15:31:01 +02:00
context.dirty_areas.push_back(area);
self.dirty = false;
}
let upper_left = upper_left!(area);
let bottom_right = bottom_right!(area);
/* Reset previously highlighted line */
let fg_color = Color::Default;
let bg_color = Color::Default;
2019-03-14 12:19:25 +02:00
change_colors(
grid,
(
2019-03-31 20:08:04 +03:00
pos_inc(upper_left, (0, self.cursor_pos + 1)),
set_y(bottom_right, get_y(upper_left) + self.cursor_pos + 1),
2019-03-14 12:19:25 +02:00
),
fg_color,
bg_color,
);
/* Highlight current line */
let bg_color = Color::Byte(246);
2019-03-14 12:19:25 +02:00
change_colors(
grid,
(
2019-03-31 20:08:04 +03:00
pos_inc(upper_left, (0, self.new_cursor_pos + 1)),
set_y(bottom_right, get_y(upper_left) + self.new_cursor_pos + 1),
2019-03-14 12:19:25 +02:00
),
fg_color,
bg_color,
);
self.cursor_pos = self.new_cursor_pos;
2019-02-21 15:31:01 +02:00
}
2019-02-26 17:50:47 +02:00
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
2019-02-21 15:31:01 +02:00
if let Some(ref mut v) = self.view {
if v.process_event(event, context) {
return true;
}
}
let shortcuts = &self.get_shortcuts(context)[Self::DESCRIPTION];
2019-04-10 23:37:20 +03:00
match *event {
UIEvent::Input(ref key) if *key == shortcuts["create_contact"] => {
2019-02-26 17:50:47 +02:00
let mut manager = ContactManager::default();
manager.account_pos = self.account_pos;
2019-04-10 22:01:02 +03:00
let component = Box::new(manager);
2019-02-26 17:50:47 +02:00
2019-04-10 22:01:02 +03:00
self.mode = ViewMode::View(component.id());
self.view = Some(component);
2019-03-14 12:19:25 +02:00
2019-02-26 17:50:47 +02:00
return true;
2019-03-14 12:19:25 +02:00
}
2019-04-10 23:37:20 +03:00
UIEvent::Input(ref key) if *key == shortcuts["edit_contact"] && self.length > 0 => {
2019-02-21 15:31:01 +02:00
let account = &mut context.accounts[self.account_pos];
let book = &mut account.address_book;
2019-02-21 15:44:26 +02:00
let card = book[&self.id_positions[self.cursor_pos]].clone();
2019-02-21 15:31:01 +02:00
let mut manager = ContactManager::default();
manager.card = card;
2019-02-25 12:00:17 +02:00
manager.account_pos = self.account_pos;
2019-04-10 22:01:02 +03:00
let component = Box::new(manager);
2019-02-21 15:31:01 +02:00
2019-04-10 22:01:02 +03:00
self.mode = ViewMode::View(component.id());
self.view = Some(component);
2019-03-14 12:19:25 +02:00
2019-02-21 15:31:01 +02:00
return true;
2019-03-14 12:19:25 +02:00
}
2019-04-10 23:37:20 +03:00
UIEvent::Input(Key::Char('n')) => {
2019-02-25 12:14:44 +02:00
let card = Card::new();
let mut manager = ContactManager::default();
manager.card = card;
manager.account_pos = self.account_pos;
2019-04-10 22:01:02 +03:00
let component = Box::new(manager);
self.mode = ViewMode::View(component.id());
self.view = Some(component);
2019-03-14 12:19:25 +02:00
2019-02-25 12:14:44 +02:00
return true;
2019-03-14 12:19:25 +02:00
}
2019-04-10 23:37:20 +03:00
UIEvent::Input(Key::Up) => {
2019-02-25 12:14:44 +02:00
self.set_dirty();
self.new_cursor_pos = self.cursor_pos.saturating_sub(1);
return true;
2019-03-14 12:19:25 +02:00
}
2019-04-10 23:37:20 +03:00
UIEvent::Input(Key::Down) if self.cursor_pos < self.length.saturating_sub(1) => {
2019-02-25 12:14:44 +02:00
self.set_dirty();
self.new_cursor_pos += 1;
return true;
2019-03-14 12:19:25 +02:00
}
2019-04-10 23:37:20 +03:00
UIEvent::ComponentKill(ref kill_id) if self.mode == ViewMode::View(*kill_id) => {
2019-02-21 15:31:01 +02:00
self.mode = ViewMode::List;
self.view.take();
self.set_dirty();
return true;
2019-03-14 12:19:25 +02:00
}
_ => {}
2019-02-21 15:31:01 +02:00
}
false
}
2019-02-21 15:31:01 +02:00
fn is_dirty(&self) -> bool {
self.dirty || self.view.as_ref().map(|v| v.is_dirty()).unwrap_or(false)
2019-02-21 15:31:01 +02:00
}
2019-02-21 15:31:01 +02:00
fn set_dirty(&mut self) {
if let Some(p) = self.view.as_mut() {
p.set_dirty();
};
self.dirty = true;
}
2019-03-02 08:39:59 +02:00
fn kill(&mut self, uuid: Uuid, context: &mut Context) {
debug_assert!(uuid == self.id);
context.replies.push_back(UIEvent::Action(Tab(Kill(uuid))));
2019-03-02 08:39:59 +02:00
}
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
2019-03-14 12:19:25 +02:00
let mut map = self
.view
.as_ref()
.map(|p| p.get_shortcuts(context))
.unwrap_or_default();
let config_map = context.settings.shortcuts.contact_list.key_values();
map.insert(
self.to_string(),
[
("create_contact", (*config_map["create_contact"]).clone()),
("edit_contact", (*config_map["edit_contact"]).clone()),
]
.iter()
.cloned()
.collect(),
);
map
}
2019-04-10 22:01:02 +03:00
fn id(&self) -> ComponentId {
self.id
}
fn set_id(&mut self, id: ComponentId) {
self.id = id;
}
2019-02-21 15:31:01 +02:00
}