2019-11-27 01:39:06 +02:00
|
|
|
|
/*
|
|
|
|
|
* meli
|
|
|
|
|
*
|
|
|
|
|
* Copyright 2019 Manos Pitsidianakis
|
|
|
|
|
*
|
|
|
|
|
* This file is part of meli.
|
|
|
|
|
*
|
|
|
|
|
* meli is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* meli is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
2023-06-04 20:42:06 +03:00
|
|
|
|
|
2023-04-30 19:39:41 +03:00
|
|
|
|
use std::cmp;
|
|
|
|
|
|
2023-10-23 13:56:13 +03:00
|
|
|
|
use melib::{backends::AccountHash, text_processing::TextProcessing, Card, CardId, Draft};
|
2023-04-30 19:39:41 +03:00
|
|
|
|
|
2023-08-30 01:12:45 +03:00
|
|
|
|
use crate::{
|
2023-10-23 13:56:13 +03:00
|
|
|
|
conf, /* contacts::editor::ContactManager, */ shortcut, terminal::*, Action::Tab,
|
|
|
|
|
Component, ComponentId, Composer, Context, DataColumns, PageMovement, ScrollContext,
|
|
|
|
|
ScrollUpdate, ShortcutMaps, Shortcuts, StatusEvent, TabAction, ThemeAttribute, UIEvent, UIMode,
|
2023-08-30 01:12:45 +03:00
|
|
|
|
};
|
2019-02-26 17:50:47 +02:00
|
|
|
|
|
2022-09-11 15:19:40 +03:00
|
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
2019-02-21 15:31:01 +02:00
|
|
|
|
enum ViewMode {
|
|
|
|
|
List,
|
2019-10-20 11:06:26 +03:00
|
|
|
|
View(ComponentId),
|
2019-02-21 15:31:01 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-26 15:58:56 +03:00
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct AccountMenuEntry {
|
|
|
|
|
name: String,
|
2022-08-25 15:17:18 +03:00
|
|
|
|
_hash: AccountHash,
|
2019-10-26 15:58:56 +03:00
|
|
|
|
// Index in the config account vector.
|
|
|
|
|
index: usize,
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-21 15:31:01 +02:00
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct ContactList {
|
2019-10-26 15:58:56 +03:00
|
|
|
|
accounts: Vec<AccountMenuEntry>,
|
2019-02-21 15:31:01 +02:00
|
|
|
|
cursor_pos: usize,
|
|
|
|
|
new_cursor_pos: usize,
|
|
|
|
|
account_pos: usize,
|
|
|
|
|
length: usize,
|
2022-11-24 16:43:53 +02:00
|
|
|
|
data_columns: DataColumns<4>,
|
2019-10-20 11:14:29 +03:00
|
|
|
|
initialized: bool,
|
2020-02-08 13:40:47 +02:00
|
|
|
|
theme_default: ThemeAttribute,
|
2022-03-22 21:00:21 +02:00
|
|
|
|
highlight_theme: ThemeAttribute,
|
2019-02-21 15:31:01 +02:00
|
|
|
|
|
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,
|
2020-11-24 23:39:02 +02:00
|
|
|
|
|
|
|
|
|
sidebar_divider: char,
|
|
|
|
|
sidebar_divider_theme: ThemeAttribute,
|
|
|
|
|
|
2019-10-26 15:58:56 +03:00
|
|
|
|
menu_visibility: bool,
|
2019-10-20 11:14:29 +03:00
|
|
|
|
movement: Option<PageMovement>,
|
2019-11-12 22:14:44 +02:00
|
|
|
|
cmd_buf: String,
|
2023-10-23 13:56:13 +03:00
|
|
|
|
//view: Option<ContactManager>,
|
2019-10-26 15:58:56 +03:00
|
|
|
|
ratio: usize, // right/(container width) * 100
|
2019-04-10 22:01:02 +03:00
|
|
|
|
id: ComponentId,
|
2019-02-21 15:31:01 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-11 12:49:06 +03:00
|
|
|
|
impl std::fmt::Display for ContactList {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
2023-08-30 01:12:45 +03:00
|
|
|
|
write!(f, "contacts")
|
2019-02-21 15:31:01 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ContactList {
|
2019-10-26 15:58:56 +03:00
|
|
|
|
pub fn new(context: &Context) -> Self {
|
|
|
|
|
let accounts = context
|
|
|
|
|
.accounts
|
|
|
|
|
.iter()
|
|
|
|
|
.enumerate()
|
2020-08-17 15:31:30 +03:00
|
|
|
|
.map(|(i, (h, a))| AccountMenuEntry {
|
2019-10-26 15:58:56 +03:00
|
|
|
|
name: a.name().to_string(),
|
2022-08-25 15:17:18 +03:00
|
|
|
|
_hash: *h,
|
2019-10-26 15:58:56 +03:00
|
|
|
|
index: i,
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
2019-02-21 15:31:01 +02:00
|
|
|
|
ContactList {
|
2019-10-26 15:58:56 +03:00
|
|
|
|
accounts,
|
2019-02-21 15:31:01 +02:00
|
|
|
|
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,
|
2019-10-20 11:14:29 +03:00
|
|
|
|
data_columns: DataColumns::default(),
|
2020-02-08 13:40:47 +02:00
|
|
|
|
theme_default: crate::conf::value(context, "theme_default"),
|
2022-03-22 21:00:21 +02:00
|
|
|
|
highlight_theme: crate::conf::value(context, "highlight"),
|
2019-10-20 11:14:29 +03:00
|
|
|
|
initialized: false,
|
2019-02-21 15:31:01 +02:00
|
|
|
|
dirty: true,
|
2019-10-20 11:14:29 +03:00
|
|
|
|
movement: None,
|
2019-11-12 22:14:44 +02:00
|
|
|
|
cmd_buf: String::with_capacity(8),
|
2023-10-23 13:56:13 +03:00
|
|
|
|
//view: None,
|
2019-10-26 15:58:56 +03:00
|
|
|
|
ratio: 90,
|
2020-11-24 23:39:02 +02:00
|
|
|
|
sidebar_divider: context.settings.listing.sidebar_divider,
|
|
|
|
|
sidebar_divider_theme: conf::value(context, "mail.sidebar_divider"),
|
2019-10-26 15:58:56 +03:00
|
|
|
|
menu_visibility: true,
|
2023-06-13 17:45:48 +03:00
|
|
|
|
id: ComponentId::default(),
|
2019-02-21 15:31:01 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-26 15:58:56 +03:00
|
|
|
|
pub fn for_account(pos: usize, context: &Context) -> Self {
|
2019-02-26 17:50:47 +02:00
|
|
|
|
ContactList {
|
|
|
|
|
account_pos: pos,
|
2019-10-26 15:58:56 +03:00
|
|
|
|
..Self::new(context)
|
2019-02-26 17:50:47 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-14 12:19:25 +02:00
|
|
|
|
|
2019-02-21 15:31:01 +02:00
|
|
|
|
fn initialize(&mut self, context: &mut Context) {
|
2023-10-23 13:56:13 +03:00
|
|
|
|
self.data_columns.clear();
|
2019-11-27 01:39:06 +02:00
|
|
|
|
let account = &context.accounts[self.account_pos];
|
|
|
|
|
let book = &account.address_book;
|
2019-02-25 12:14:44 +02:00
|
|
|
|
self.length = book.len();
|
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
|
|
|
|
}
|
2019-10-20 11:14:29 +03:00
|
|
|
|
self.dirty = true;
|
2019-11-27 01:39:06 +02:00
|
|
|
|
let mut min_width = ("Name".len(), "E-mail".len(), 0, "external".len(), 0, 0);
|
2019-02-21 15:31:01 +02:00
|
|
|
|
|
2019-03-31 20:08:04 +03:00
|
|
|
|
for c in book.values() {
|
2019-11-27 01:39:06 +02:00
|
|
|
|
/* name */
|
2023-10-23 13:56:13 +03:00
|
|
|
|
let name = c.name().split_graphemes().len();
|
|
|
|
|
if name > 0 {
|
|
|
|
|
min_width.0 = cmp::max(min_width.0, name + 1);
|
|
|
|
|
}
|
2019-11-27 01:39:06 +02:00
|
|
|
|
/* email */
|
2023-10-23 13:56:13 +03:00
|
|
|
|
let email = c.email().split_graphemes().len();
|
|
|
|
|
if email > 0 {
|
|
|
|
|
min_width.1 = cmp::max(min_width.1, email + 1);
|
|
|
|
|
}
|
2019-10-20 11:14:29 +03:00
|
|
|
|
/* url */
|
2023-10-23 13:56:13 +03:00
|
|
|
|
let url = c.url().split_graphemes().len();
|
|
|
|
|
if url > 0 {
|
|
|
|
|
min_width.2 = cmp::max(min_width.2, url + 1);
|
|
|
|
|
}
|
2019-03-31 20:08:04 +03:00
|
|
|
|
}
|
2019-10-20 11:14:29 +03:00
|
|
|
|
|
|
|
|
|
/* name column */
|
2023-10-23 13:56:13 +03:00
|
|
|
|
_ = self.data_columns.columns[0].resize_with_context(min_width.0, self.length, context);
|
2019-10-20 11:14:29 +03:00
|
|
|
|
/* email column */
|
2023-10-23 13:56:13 +03:00
|
|
|
|
_ = self.data_columns.columns[1].resize_with_context(min_width.1, self.length, context);
|
2019-10-20 11:14:29 +03:00
|
|
|
|
/* url column */
|
2023-10-23 13:56:13 +03:00
|
|
|
|
_ = self.data_columns.columns[2].resize_with_context(min_width.2, self.length, context);
|
2019-11-27 01:39:06 +02:00
|
|
|
|
/* source column */
|
2023-10-23 13:56:13 +03:00
|
|
|
|
_ = self.data_columns.columns[3].resize_with_context(
|
|
|
|
|
"external".len(),
|
|
|
|
|
self.length,
|
|
|
|
|
context,
|
|
|
|
|
);
|
2019-10-20 11:14:29 +03:00
|
|
|
|
|
2019-11-27 01:39:06 +02:00
|
|
|
|
let account = &context.accounts[self.account_pos];
|
|
|
|
|
let book = &account.address_book;
|
|
|
|
|
let mut book_values = book.values().collect::<Vec<&Card>>();
|
|
|
|
|
book_values.sort_unstable_by_key(|c| c.name());
|
|
|
|
|
for (idx, c) in book_values.iter().enumerate() {
|
2019-02-21 15:44:26 +02:00
|
|
|
|
self.id_positions.push(*c.id());
|
2019-03-14 12:19:25 +02:00
|
|
|
|
|
2023-10-23 13:56:13 +03:00
|
|
|
|
{
|
|
|
|
|
let area = self.data_columns.columns[0].area().nth_row(idx);
|
|
|
|
|
self.data_columns.columns[0].grid_mut().write_string(
|
|
|
|
|
c.name(),
|
|
|
|
|
self.theme_default.fg,
|
|
|
|
|
self.theme_default.bg,
|
|
|
|
|
self.theme_default.attrs,
|
|
|
|
|
area,
|
|
|
|
|
None,
|
|
|
|
|
)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
let area = self.data_columns.columns[1].area().nth_row(idx);
|
|
|
|
|
self.data_columns.columns[1].grid_mut().write_string(
|
|
|
|
|
c.email(),
|
|
|
|
|
self.theme_default.fg,
|
|
|
|
|
self.theme_default.bg,
|
|
|
|
|
self.theme_default.attrs,
|
|
|
|
|
area,
|
|
|
|
|
None,
|
|
|
|
|
)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
let area = self.data_columns.columns[2].area().nth_row(idx);
|
|
|
|
|
self.data_columns.columns[2].grid_mut().write_string(
|
|
|
|
|
c.url(),
|
|
|
|
|
self.theme_default.fg,
|
|
|
|
|
self.theme_default.bg,
|
|
|
|
|
self.theme_default.attrs,
|
|
|
|
|
area,
|
|
|
|
|
None,
|
|
|
|
|
)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
let area = self.data_columns.columns[3].area().nth_row(idx);
|
|
|
|
|
self.data_columns.columns[3].grid_mut().write_string(
|
|
|
|
|
if c.external_resource() {
|
|
|
|
|
"external"
|
|
|
|
|
} else {
|
|
|
|
|
"local"
|
|
|
|
|
},
|
|
|
|
|
self.theme_default.fg,
|
|
|
|
|
self.theme_default.bg,
|
|
|
|
|
self.theme_default.attrs,
|
|
|
|
|
area,
|
|
|
|
|
None,
|
|
|
|
|
)
|
|
|
|
|
};
|
2019-10-20 11:14:29 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if self.length == 0 {
|
|
|
|
|
let message = "Address book is empty.".to_string();
|
2023-10-23 13:56:13 +03:00
|
|
|
|
if self.data_columns.columns[0].resize_with_context(message.len(), self.length, context)
|
|
|
|
|
{
|
|
|
|
|
let area = self.data_columns.columns[0].area();
|
|
|
|
|
self.data_columns.columns[0].grid_mut().write_string(
|
|
|
|
|
&message,
|
|
|
|
|
self.theme_default.fg,
|
|
|
|
|
self.theme_default.bg,
|
|
|
|
|
self.theme_default.attrs,
|
|
|
|
|
area,
|
|
|
|
|
None,
|
|
|
|
|
);
|
|
|
|
|
}
|
2019-02-21 15:31:01 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-10-20 11:14:29 +03:00
|
|
|
|
|
|
|
|
|
fn highlight_line(&mut self, grid: &mut CellBuffer, area: Area, idx: usize) {
|
|
|
|
|
/* Reset previously highlighted line */
|
2023-08-21 12:45:15 +03:00
|
|
|
|
let mut theme = if idx == self.new_cursor_pos {
|
|
|
|
|
self.highlight_theme
|
2019-10-20 11:14:29 +03:00
|
|
|
|
} else {
|
2023-08-21 12:45:15 +03:00
|
|
|
|
self.theme_default
|
2019-10-20 11:14:29 +03:00
|
|
|
|
};
|
2023-08-21 12:45:15 +03:00
|
|
|
|
theme.fg = self.theme_default.fg;
|
|
|
|
|
if !grid.use_color {
|
|
|
|
|
theme.attrs |= Attr::REVERSE;
|
|
|
|
|
}
|
2023-10-27 12:05:36 +03:00
|
|
|
|
grid.change_theme(area, theme);
|
2019-10-20 11:14:29 +03:00
|
|
|
|
}
|
2019-02-21 15:31:01 +02:00
|
|
|
|
|
2020-11-24 23:39:02 +02:00
|
|
|
|
fn draw_menu(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
|
2019-10-26 15:58:56 +03:00
|
|
|
|
if !self.is_dirty() {
|
2019-02-21 15:31:01 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2023-10-27 12:05:36 +03:00
|
|
|
|
grid.clear_area(area, self.theme_default);
|
2019-10-26 15:58:56 +03:00
|
|
|
|
self.dirty = false;
|
2023-10-23 13:56:13 +03:00
|
|
|
|
for (y, a) in self.accounts.iter().enumerate() {
|
|
|
|
|
self.print_account(grid, area.nth_row(y), a, context);
|
2019-10-26 15:58:56 +03:00
|
|
|
|
}
|
2019-02-21 15:31:01 +02:00
|
|
|
|
|
2019-10-26 15:58:56 +03:00
|
|
|
|
context.dirty_areas.push_back(area);
|
|
|
|
|
}
|
2023-10-23 13:56:13 +03:00
|
|
|
|
|
2019-10-26 15:58:56 +03:00
|
|
|
|
/*
|
|
|
|
|
* Print a single account in the menu area.
|
|
|
|
|
*/
|
|
|
|
|
fn print_account(
|
|
|
|
|
&self,
|
|
|
|
|
grid: &mut CellBuffer,
|
|
|
|
|
area: Area,
|
|
|
|
|
a: &AccountMenuEntry,
|
|
|
|
|
context: &mut Context,
|
|
|
|
|
) {
|
2023-10-23 13:56:13 +03:00
|
|
|
|
let width = area.width();
|
2019-10-26 15:58:56 +03:00
|
|
|
|
let must_highlight_account: bool = self.account_pos == a.index;
|
2020-11-12 03:11:57 +02:00
|
|
|
|
let account_attrs = if must_highlight_account {
|
|
|
|
|
let mut v = crate::conf::value(context, "mail.sidebar_highlighted");
|
|
|
|
|
if !context.settings.terminal.use_color() {
|
|
|
|
|
v.attrs |= Attr::REVERSE;
|
2019-10-26 15:58:56 +03:00
|
|
|
|
}
|
2020-11-12 03:11:57 +02:00
|
|
|
|
v
|
2019-10-26 15:58:56 +03:00
|
|
|
|
} else {
|
2020-11-12 03:11:57 +02:00
|
|
|
|
crate::conf::value(context, "mail.sidebar_account_name")
|
2019-10-26 15:58:56 +03:00
|
|
|
|
};
|
|
|
|
|
|
2023-10-23 13:56:13 +03:00
|
|
|
|
grid.change_theme(area, account_attrs);
|
2019-10-26 15:58:56 +03:00
|
|
|
|
let s = format!(" [{}]", context.accounts[a.index].address_book.len());
|
2023-10-23 13:56:13 +03:00
|
|
|
|
/* Print account name */
|
|
|
|
|
grid.write_string(
|
|
|
|
|
&a.name,
|
|
|
|
|
account_attrs.fg,
|
|
|
|
|
account_attrs.bg,
|
|
|
|
|
account_attrs.attrs,
|
|
|
|
|
area,
|
|
|
|
|
None,
|
|
|
|
|
);
|
|
|
|
|
grid.write_string(
|
|
|
|
|
&s,
|
|
|
|
|
account_attrs.fg,
|
|
|
|
|
account_attrs.bg,
|
|
|
|
|
account_attrs.attrs,
|
|
|
|
|
area.skip_cols(area.width().saturating_sub(s.len())),
|
|
|
|
|
None,
|
|
|
|
|
);
|
2019-10-26 15:58:56 +03:00
|
|
|
|
|
|
|
|
|
if a.name.grapheme_len() + s.len() > width + 1 {
|
2023-10-27 12:11:45 +03:00
|
|
|
|
grid.write_string(
|
2019-10-26 15:58:56 +03:00
|
|
|
|
"…",
|
2020-11-12 03:11:57 +02:00
|
|
|
|
account_attrs.fg,
|
|
|
|
|
account_attrs.bg,
|
|
|
|
|
account_attrs.attrs,
|
2023-10-23 13:56:13 +03:00
|
|
|
|
area.skip_cols(area.width().saturating_sub(s.len() + 1)),
|
2019-11-18 13:06:30 +02:00
|
|
|
|
None,
|
2019-10-26 15:58:56 +03:00
|
|
|
|
);
|
2019-10-20 11:14:29 +03:00
|
|
|
|
}
|
2019-10-26 15:58:56 +03:00
|
|
|
|
}
|
2019-10-20 11:14:29 +03:00
|
|
|
|
|
2019-10-26 15:58:56 +03:00
|
|
|
|
fn draw_list(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
|
2019-10-20 11:14:29 +03:00
|
|
|
|
if self.length == 0 {
|
2023-10-23 13:56:13 +03:00
|
|
|
|
/* reserve top row for column headers */
|
|
|
|
|
let area = area.skip_rows(1);
|
2023-10-27 12:05:36 +03:00
|
|
|
|
grid.clear_area(area, self.theme_default);
|
|
|
|
|
|
|
|
|
|
grid.copy_area(
|
2023-10-23 13:56:13 +03:00
|
|
|
|
self.data_columns.columns[0].grid(),
|
2019-03-14 12:19:25 +02:00
|
|
|
|
area,
|
2023-10-23 13:56:13 +03:00
|
|
|
|
self.data_columns.columns[0].area(),
|
2019-03-14 12:19:25 +02:00
|
|
|
|
);
|
2019-02-21 15:31:01 +02:00
|
|
|
|
context.dirty_areas.push_back(area);
|
2019-10-20 11:14:29 +03:00
|
|
|
|
return;
|
|
|
|
|
}
|
2023-10-23 13:56:13 +03:00
|
|
|
|
let rows = area.height();
|
2019-10-20 11:14:29 +03:00
|
|
|
|
|
|
|
|
|
if let Some(mvm) = self.movement.take() {
|
|
|
|
|
match mvm {
|
2019-11-12 22:14:44 +02:00
|
|
|
|
PageMovement::Up(amount) => {
|
|
|
|
|
self.new_cursor_pos = self.new_cursor_pos.saturating_sub(amount);
|
2019-10-20 11:14:29 +03:00
|
|
|
|
}
|
2019-11-12 22:14:44 +02:00
|
|
|
|
PageMovement::PageUp(multiplier) => {
|
|
|
|
|
self.new_cursor_pos = self.new_cursor_pos.saturating_sub(rows * multiplier);
|
|
|
|
|
}
|
|
|
|
|
PageMovement::Down(amount) => {
|
2019-11-27 01:39:06 +02:00
|
|
|
|
if self.new_cursor_pos + amount < self.length {
|
2019-11-12 22:14:44 +02:00
|
|
|
|
self.new_cursor_pos += amount;
|
|
|
|
|
} else {
|
|
|
|
|
self.new_cursor_pos = self.length - 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PageMovement::PageDown(multiplier) => {
|
2022-08-25 15:17:18 +03:00
|
|
|
|
#[allow(clippy::comparison_chain)]
|
2019-11-27 01:39:06 +02:00
|
|
|
|
if self.new_cursor_pos + rows * multiplier < self.length {
|
2019-11-12 22:14:44 +02:00
|
|
|
|
self.new_cursor_pos += rows * multiplier;
|
|
|
|
|
} else if self.new_cursor_pos + rows * multiplier > self.length {
|
2019-10-20 11:14:29 +03:00
|
|
|
|
self.new_cursor_pos = self.length - 1;
|
|
|
|
|
} else {
|
|
|
|
|
self.new_cursor_pos = (self.length / rows) * rows;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-12 22:14:44 +02:00
|
|
|
|
PageMovement::Right(_) | PageMovement::Left(_) => {}
|
2019-10-20 11:14:29 +03:00
|
|
|
|
PageMovement::Home => {
|
|
|
|
|
self.new_cursor_pos = 0;
|
|
|
|
|
}
|
|
|
|
|
PageMovement::End => {
|
2019-11-27 01:39:06 +02:00
|
|
|
|
self.new_cursor_pos = self.length - 1;
|
2019-10-20 11:14:29 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-02-21 15:31:01 +02:00
|
|
|
|
}
|
2019-02-25 11:11:56 +02:00
|
|
|
|
|
2019-10-20 11:14:29 +03:00
|
|
|
|
let prev_page_no = (self.cursor_pos).wrapping_div(rows);
|
|
|
|
|
let page_no = (self.new_cursor_pos).wrapping_div(rows);
|
|
|
|
|
|
|
|
|
|
let top_idx = page_no * rows;
|
|
|
|
|
|
2021-01-07 20:26:17 +02:00
|
|
|
|
if self.length >= rows {
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::ScrollUpdate(
|
|
|
|
|
ScrollUpdate::Update {
|
|
|
|
|
id: self.id,
|
|
|
|
|
context: ScrollContext {
|
|
|
|
|
shown_lines: top_idx + rows,
|
|
|
|
|
total_lines: self.length,
|
|
|
|
|
has_more_lines: false,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
)));
|
|
|
|
|
} else {
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::ScrollUpdate(
|
|
|
|
|
ScrollUpdate::End(self.id),
|
|
|
|
|
)));
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-30 19:39:41 +03:00
|
|
|
|
/* If cursor position has changed, remove the highlight from the previous
|
|
|
|
|
* position and apply it in the new one. */
|
2019-10-20 11:14:29 +03:00
|
|
|
|
if self.cursor_pos != self.new_cursor_pos && prev_page_no == page_no {
|
|
|
|
|
let old_cursor_pos = self.cursor_pos;
|
|
|
|
|
self.cursor_pos = self.new_cursor_pos;
|
|
|
|
|
for idx in &[old_cursor_pos, self.new_cursor_pos] {
|
|
|
|
|
if *idx >= self.length {
|
2023-10-23 13:56:13 +03:00
|
|
|
|
continue;
|
2019-10-20 11:14:29 +03:00
|
|
|
|
}
|
2023-10-23 13:56:13 +03:00
|
|
|
|
let new_area = area.nth_row(1 + *idx % rows);
|
2019-10-20 11:14:29 +03:00
|
|
|
|
self.highlight_line(grid, new_area, *idx);
|
|
|
|
|
context.dirty_areas.push_back(new_area);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
} else if self.cursor_pos != self.new_cursor_pos {
|
|
|
|
|
self.cursor_pos = self.new_cursor_pos;
|
|
|
|
|
}
|
|
|
|
|
if self.new_cursor_pos >= self.length {
|
|
|
|
|
self.new_cursor_pos = self.length - 1;
|
|
|
|
|
self.cursor_pos = self.new_cursor_pos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Page_no has changed, so draw new page */
|
2023-10-23 13:56:13 +03:00
|
|
|
|
grid.clear_area(area, self.theme_default);
|
|
|
|
|
_ = self
|
|
|
|
|
.data_columns
|
|
|
|
|
.recalc_widths((area.width(), area.height().saturating_sub(1)), top_idx);
|
|
|
|
|
/* copy table columns */
|
|
|
|
|
self.data_columns.draw(
|
|
|
|
|
grid,
|
|
|
|
|
top_idx,
|
|
|
|
|
self.cursor_pos,
|
|
|
|
|
grid.bounds_iter(area.skip_rows(1)),
|
|
|
|
|
);
|
2020-02-09 00:30:50 +02:00
|
|
|
|
|
|
|
|
|
let header_attrs = crate::conf::value(context, "widgets.list.header");
|
2023-10-23 13:56:13 +03:00
|
|
|
|
let mut x = 0;
|
2019-10-20 11:14:29 +03:00
|
|
|
|
for i in 0..self.data_columns.columns.len() {
|
|
|
|
|
if self.data_columns.widths[i] == 0 {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2023-10-27 12:11:45 +03:00
|
|
|
|
grid.write_string(
|
2019-11-27 01:39:06 +02:00
|
|
|
|
match i {
|
|
|
|
|
0 => "NAME",
|
|
|
|
|
1 => "E-MAIL",
|
|
|
|
|
2 => "URL",
|
|
|
|
|
3 => "SOURCE",
|
|
|
|
|
_ => "",
|
|
|
|
|
},
|
2020-02-09 00:30:50 +02:00
|
|
|
|
header_attrs.fg,
|
|
|
|
|
header_attrs.bg,
|
|
|
|
|
header_attrs.attrs,
|
2023-10-23 13:56:13 +03:00
|
|
|
|
area.skip_cols(x)
|
|
|
|
|
.take_cols(x + (self.data_columns.widths[i])),
|
2019-11-27 01:39:06 +02:00
|
|
|
|
None,
|
|
|
|
|
);
|
2023-10-27 12:05:36 +03:00
|
|
|
|
|
2019-10-20 11:14:29 +03:00
|
|
|
|
x += self.data_columns.widths[i] + 2; // + SEPARATOR
|
2023-10-23 13:56:13 +03:00
|
|
|
|
if x > area.width() {
|
2019-10-20 11:14:29 +03:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-02-25 11:11:56 +02:00
|
|
|
|
|
2023-10-23 13:56:13 +03:00
|
|
|
|
grid.change_theme(area.nth_row(0), header_attrs);
|
2019-02-25 11:11:56 +02:00
|
|
|
|
|
2019-11-27 01:39:06 +02:00
|
|
|
|
if top_idx + rows > self.length {
|
2023-10-27 12:05:36 +03:00
|
|
|
|
grid.clear_area(
|
2023-10-23 13:56:13 +03:00
|
|
|
|
area.skip_rows(top_idx + rows - self.length.saturating_sub(1)),
|
2020-02-08 13:40:47 +02:00
|
|
|
|
self.theme_default,
|
2019-10-20 11:14:29 +03:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
self.highlight_line(
|
2019-03-14 12:19:25 +02:00
|
|
|
|
grid,
|
2023-10-23 13:56:13 +03:00
|
|
|
|
area.nth_row(1 + self.cursor_pos % rows),
|
2019-10-20 11:14:29 +03:00
|
|
|
|
self.cursor_pos,
|
2019-03-14 12:19:25 +02:00
|
|
|
|
);
|
2019-10-20 11:14:29 +03:00
|
|
|
|
context.dirty_areas.push_back(area);
|
2019-02-21 15:31:01 +02:00
|
|
|
|
}
|
2019-10-26 15:58:56 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Component for ContactList {
|
|
|
|
|
fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
|
2023-10-23 13:56:13 +03:00
|
|
|
|
//if let Some(mgr) = self.view.as_mut() {
|
|
|
|
|
// mgr.draw(grid, area, context);
|
|
|
|
|
// return;
|
|
|
|
|
//}
|
2019-10-26 15:58:56 +03:00
|
|
|
|
|
|
|
|
|
if !self.dirty {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if !self.initialized {
|
|
|
|
|
self.initialize(context);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-23 13:56:13 +03:00
|
|
|
|
let total_cols = area.width();
|
2019-10-26 15:58:56 +03:00
|
|
|
|
|
|
|
|
|
let right_component_width = if self.menu_visibility {
|
|
|
|
|
(self.ratio * total_cols) / 100
|
|
|
|
|
} else {
|
|
|
|
|
total_cols
|
|
|
|
|
};
|
2023-10-23 13:56:13 +03:00
|
|
|
|
let mid = area.width().saturating_sub(right_component_width);
|
|
|
|
|
if self.dirty && mid != 0 {
|
|
|
|
|
let divider_area = area.nth_col(mid);
|
|
|
|
|
for row in grid.bounds_iter(divider_area) {
|
|
|
|
|
for c in row {
|
|
|
|
|
grid[c]
|
|
|
|
|
.set_ch(self.sidebar_divider)
|
|
|
|
|
.set_fg(self.sidebar_divider_theme.fg)
|
|
|
|
|
.set_bg(self.sidebar_divider_theme.bg)
|
|
|
|
|
.set_attrs(self.sidebar_divider_theme.attrs);
|
|
|
|
|
}
|
2019-10-26 15:58:56 +03:00
|
|
|
|
}
|
2023-10-23 13:56:13 +03:00
|
|
|
|
context.dirty_areas.push_back(divider_area);
|
2019-10-26 15:58:56 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if right_component_width == total_cols {
|
|
|
|
|
self.draw_list(grid, area, context);
|
|
|
|
|
} else if right_component_width == 0 {
|
|
|
|
|
self.draw_menu(grid, area, context);
|
|
|
|
|
} else {
|
2023-10-23 13:56:13 +03:00
|
|
|
|
self.draw_menu(grid, area.take_cols(mid), context);
|
|
|
|
|
self.draw_list(grid, area.skip_cols(mid + 1), context);
|
2019-10-26 15:58:56 +03:00
|
|
|
|
}
|
|
|
|
|
self.dirty = false;
|
|
|
|
|
}
|
2019-02-25 11:11:56 +02:00
|
|
|
|
|
2019-02-26 17:50:47 +02:00
|
|
|
|
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
2023-08-23 17:27:48 +03:00
|
|
|
|
match event {
|
2023-10-23 13:56:13 +03:00
|
|
|
|
UIEvent::VisibilityChange(true) => {
|
|
|
|
|
self.initialized = false;
|
|
|
|
|
self.set_dirty(true);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-08-23 17:27:48 +03:00
|
|
|
|
UIEvent::ConfigReload { old_settings: _ } => {
|
|
|
|
|
self.theme_default = crate::conf::value(context, "theme_default");
|
|
|
|
|
self.initialized = false;
|
|
|
|
|
self.sidebar_divider = context.settings.listing.sidebar_divider;
|
|
|
|
|
self.sidebar_divider_theme = conf::value(context, "mail.sidebar_divider");
|
|
|
|
|
self.set_dirty(true);
|
|
|
|
|
}
|
|
|
|
|
UIEvent::AccountStatusChange(_, _) => {
|
|
|
|
|
self.initialized = false;
|
|
|
|
|
self.set_dirty(true);
|
|
|
|
|
}
|
|
|
|
|
UIEvent::ComponentUnrealize(ref kill_id) if self.mode == ViewMode::View(*kill_id) => {
|
|
|
|
|
self.mode = ViewMode::List;
|
2023-10-23 13:56:13 +03:00
|
|
|
|
//self.view.take();
|
2023-08-23 17:27:48 +03:00
|
|
|
|
self.set_dirty(true);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
UIEvent::ChangeMode(UIMode::Normal) => {
|
|
|
|
|
self.set_dirty(true);
|
|
|
|
|
}
|
|
|
|
|
UIEvent::Resize => {
|
|
|
|
|
self.set_dirty(true);
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
2020-12-02 20:47:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-10-23 13:56:13 +03:00
|
|
|
|
//if let Some(ref mut v) = self.view {
|
|
|
|
|
// if v.process_event(event, context) {
|
|
|
|
|
// return true;
|
|
|
|
|
// }
|
|
|
|
|
//}
|
2023-08-23 17:27:48 +03:00
|
|
|
|
|
2023-06-13 17:45:48 +03:00
|
|
|
|
let shortcuts = self.shortcuts(context);
|
2023-10-23 13:56:13 +03:00
|
|
|
|
//if self.view.is_none() {
|
|
|
|
|
match *event {
|
|
|
|
|
UIEvent::Input(ref key)
|
|
|
|
|
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["create_contact"]) =>
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
let mut manager = ContactManager::new(context);
|
|
|
|
|
manager.set_parent_id(self.id);
|
|
|
|
|
manager.account_pos = self.account_pos;
|
|
|
|
|
|
|
|
|
|
self.mode = ViewMode::View(manager.id());
|
|
|
|
|
self.view = Some(manager);
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::ScrollUpdate(
|
|
|
|
|
ScrollUpdate::End(self.id),
|
|
|
|
|
)));
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2019-03-14 12:19:25 +02:00
|
|
|
|
|
2023-10-23 13:56:13 +03:00
|
|
|
|
UIEvent::Input(ref key)
|
|
|
|
|
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["edit_contact"]) =>
|
|
|
|
|
{
|
|
|
|
|
if self.length == 0 {
|
2019-11-27 01:39:06 +02:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-10-23 13:56:13 +03:00
|
|
|
|
/*
|
|
|
|
|
let account = &mut context.accounts[self.account_pos];
|
|
|
|
|
let book = &mut account.address_book;
|
|
|
|
|
let card = book[&self.id_positions[self.cursor_pos]].clone();
|
|
|
|
|
let mut manager = ContactManager::new(context);
|
|
|
|
|
manager.set_parent_id(self.id);
|
|
|
|
|
manager.card = card;
|
|
|
|
|
manager.account_pos = self.account_pos;
|
|
|
|
|
|
|
|
|
|
self.mode = ViewMode::View(manager.id());
|
|
|
|
|
self.view = Some(manager);
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::ScrollUpdate(
|
|
|
|
|
ScrollUpdate::End(self.id),
|
|
|
|
|
)));
|
|
|
|
|
*/
|
2019-03-14 12:19:25 +02:00
|
|
|
|
|
2023-10-23 13:56:13 +03:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
UIEvent::Input(ref key)
|
|
|
|
|
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["mail_contact"]) =>
|
|
|
|
|
{
|
|
|
|
|
if self.length == 0 {
|
2019-11-27 01:39:06 +02:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-10-23 13:56:13 +03:00
|
|
|
|
let account = &context.accounts[self.account_pos];
|
|
|
|
|
let account_hash = account.hash();
|
|
|
|
|
let book = &account.address_book;
|
|
|
|
|
let card = &book[&self.id_positions[self.cursor_pos]];
|
|
|
|
|
let mut draft: Draft = Draft::default();
|
|
|
|
|
*draft.headers_mut().get_mut("To").unwrap() =
|
|
|
|
|
format!("{} <{}>", &card.name(), &card.email());
|
|
|
|
|
let mut composer = Composer::with_account(account_hash, context);
|
|
|
|
|
composer.set_draft(draft, context);
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::Action(Tab(TabAction::New(Some(Box::new(
|
|
|
|
|
composer,
|
|
|
|
|
))))));
|
2019-11-27 01:39:06 +02:00
|
|
|
|
|
2023-10-23 13:56:13 +03:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
UIEvent::Input(ref key)
|
|
|
|
|
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["delete_contact"]) =>
|
|
|
|
|
{
|
|
|
|
|
if self.length == 0 {
|
2019-11-27 01:39:06 +02:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-10-23 13:56:13 +03:00
|
|
|
|
// [ref:TODO]: add a confirmation dialog?
|
|
|
|
|
context.accounts[self.account_pos]
|
|
|
|
|
.address_book
|
|
|
|
|
.remove_card(self.id_positions[self.cursor_pos]);
|
|
|
|
|
self.initialized = false;
|
|
|
|
|
self.set_dirty(true);
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
UIEvent::Input(ref key)
|
|
|
|
|
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["next_account"]) =>
|
|
|
|
|
{
|
|
|
|
|
let amount = if self.cmd_buf.is_empty() {
|
|
|
|
|
1
|
|
|
|
|
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
|
|
|
|
|
self.cmd_buf.clear();
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
|
|
|
|
amount
|
|
|
|
|
} else {
|
|
|
|
|
self.cmd_buf.clear();
|
2023-08-23 17:27:48 +03:00
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
|
|
|
|
return true;
|
2023-10-23 13:56:13 +03:00
|
|
|
|
};
|
|
|
|
|
if self.account_pos + amount < self.accounts.len() {
|
|
|
|
|
self.account_pos += amount;
|
|
|
|
|
self.set_dirty(true);
|
|
|
|
|
self.initialized = false;
|
|
|
|
|
self.cursor_pos = 0;
|
|
|
|
|
self.new_cursor_pos = 0;
|
|
|
|
|
self.length = 0;
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
|
|
|
|
self.status(context),
|
|
|
|
|
)));
|
2023-08-23 17:27:48 +03:00
|
|
|
|
}
|
2019-03-14 12:19:25 +02:00
|
|
|
|
|
2023-10-23 13:56:13 +03:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
UIEvent::Input(ref key)
|
|
|
|
|
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["prev_account"]) =>
|
|
|
|
|
{
|
|
|
|
|
let amount = if self.cmd_buf.is_empty() {
|
|
|
|
|
1
|
|
|
|
|
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
|
|
|
|
|
self.cmd_buf.clear();
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
|
|
|
|
amount
|
|
|
|
|
} else {
|
|
|
|
|
self.cmd_buf.clear();
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
2019-11-12 22:14:44 +02:00
|
|
|
|
return true;
|
2023-10-23 13:56:13 +03:00
|
|
|
|
};
|
|
|
|
|
if self.accounts.is_empty() {
|
2019-10-26 15:58:56 +03:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-10-23 13:56:13 +03:00
|
|
|
|
if self.account_pos >= amount {
|
|
|
|
|
self.account_pos -= amount;
|
2019-12-14 18:50:05 +02:00
|
|
|
|
self.set_dirty(true);
|
2023-10-23 13:56:13 +03:00
|
|
|
|
self.cursor_pos = 0;
|
|
|
|
|
self.new_cursor_pos = 0;
|
|
|
|
|
self.length = 0;
|
|
|
|
|
self.initialized = false;
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
|
|
|
|
self.status(context),
|
|
|
|
|
)));
|
2019-10-26 15:58:56 +03:00
|
|
|
|
}
|
2023-10-23 13:56:13 +03:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
UIEvent::Input(ref k)
|
|
|
|
|
if shortcut!(k == shortcuts[Shortcuts::CONTACT_LIST]["toggle_menu_visibility"]) =>
|
|
|
|
|
{
|
|
|
|
|
self.menu_visibility = !self.menu_visibility;
|
|
|
|
|
self.set_dirty(true);
|
|
|
|
|
}
|
|
|
|
|
UIEvent::Input(Key::Esc) | UIEvent::Input(Key::Alt('')) if !self.cmd_buf.is_empty() => {
|
|
|
|
|
self.cmd_buf.clear();
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
UIEvent::Input(Key::Char(c)) if c.is_ascii_digit() => {
|
|
|
|
|
self.cmd_buf.push(c);
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::BufSet(
|
|
|
|
|
self.cmd_buf.clone(),
|
|
|
|
|
)));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
UIEvent::Input(ref key)
|
|
|
|
|
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["scroll_up"]) =>
|
|
|
|
|
{
|
|
|
|
|
let amount = if self.cmd_buf.is_empty() {
|
|
|
|
|
1
|
|
|
|
|
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
|
2019-11-12 22:14:44 +02:00
|
|
|
|
self.cmd_buf.clear();
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
2023-10-23 13:56:13 +03:00
|
|
|
|
amount
|
|
|
|
|
} else {
|
|
|
|
|
self.cmd_buf.clear();
|
2019-11-12 22:14:44 +02:00
|
|
|
|
context
|
|
|
|
|
.replies
|
2023-10-23 13:56:13 +03:00
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
2019-11-27 01:39:06 +02:00
|
|
|
|
return true;
|
2023-10-23 13:56:13 +03:00
|
|
|
|
};
|
|
|
|
|
self.movement = Some(PageMovement::Up(amount));
|
|
|
|
|
self.set_dirty(true);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
UIEvent::Input(ref key)
|
|
|
|
|
if shortcut!(key == shortcuts[Shortcuts::CONTACT_LIST]["scroll_down"]) =>
|
|
|
|
|
{
|
|
|
|
|
if self.cursor_pos >= self.length.saturating_sub(1) {
|
2019-11-12 22:14:44 +02:00
|
|
|
|
return true;
|
2019-11-27 01:39:06 +02:00
|
|
|
|
}
|
2023-10-23 13:56:13 +03:00
|
|
|
|
let amount = if self.cmd_buf.is_empty() {
|
|
|
|
|
1
|
|
|
|
|
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
|
|
|
|
|
self.cmd_buf.clear();
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
|
|
|
|
amount
|
|
|
|
|
} else {
|
|
|
|
|
self.cmd_buf.clear();
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
2019-11-12 22:14:44 +02:00
|
|
|
|
return true;
|
2023-10-23 13:56:13 +03:00
|
|
|
|
};
|
|
|
|
|
self.set_dirty(true);
|
|
|
|
|
self.movement = Some(PageMovement::Down(amount));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
UIEvent::Input(ref key)
|
|
|
|
|
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["prev_page"]) =>
|
|
|
|
|
{
|
|
|
|
|
let mult = if self.cmd_buf.is_empty() {
|
|
|
|
|
1
|
|
|
|
|
} else if let Ok(mult) = self.cmd_buf.parse::<usize>() {
|
|
|
|
|
self.cmd_buf.clear();
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
|
|
|
|
mult
|
|
|
|
|
} else {
|
|
|
|
|
self.cmd_buf.clear();
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
2019-11-27 01:39:06 +02:00
|
|
|
|
return true;
|
2023-10-23 13:56:13 +03:00
|
|
|
|
};
|
|
|
|
|
self.set_dirty(true);
|
|
|
|
|
self.movement = Some(PageMovement::PageUp(mult));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
UIEvent::Input(ref key)
|
|
|
|
|
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["next_page"]) =>
|
|
|
|
|
{
|
|
|
|
|
let mult = if self.cmd_buf.is_empty() {
|
|
|
|
|
1
|
|
|
|
|
} else if let Ok(mult) = self.cmd_buf.parse::<usize>() {
|
|
|
|
|
self.cmd_buf.clear();
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
|
|
|
|
mult
|
|
|
|
|
} else {
|
|
|
|
|
self.cmd_buf.clear();
|
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
2019-11-27 01:39:06 +02:00
|
|
|
|
return true;
|
2023-10-23 13:56:13 +03:00
|
|
|
|
};
|
|
|
|
|
self.set_dirty(true);
|
|
|
|
|
self.movement = Some(PageMovement::PageDown(mult));
|
|
|
|
|
return true;
|
2019-10-20 11:14:29 +03:00
|
|
|
|
}
|
2023-10-23 13:56:13 +03:00
|
|
|
|
UIEvent::Input(ref key)
|
|
|
|
|
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["home_page"]) =>
|
|
|
|
|
{
|
|
|
|
|
self.set_dirty(true);
|
|
|
|
|
self.movement = Some(PageMovement::Home);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
UIEvent::Input(ref key)
|
|
|
|
|
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["end_page"]) =>
|
|
|
|
|
{
|
|
|
|
|
self.set_dirty(true);
|
|
|
|
|
self.movement = Some(PageMovement::End);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
2019-02-21 15:31:01 +02:00
|
|
|
|
}
|
2023-10-23 13:56:13 +03:00
|
|
|
|
//}
|
2019-02-21 15:31:01 +02:00
|
|
|
|
false
|
|
|
|
|
}
|
2019-02-25 11:11:56 +02:00
|
|
|
|
|
2019-02-21 15:31:01 +02:00
|
|
|
|
fn is_dirty(&self) -> bool {
|
2023-10-23 13:56:13 +03:00
|
|
|
|
self.dirty //|| self.view.as_ref().map(|v|
|
|
|
|
|
//|| v.is_dirty()).unwrap_or(false)
|
2019-02-21 15:31:01 +02:00
|
|
|
|
}
|
2019-02-25 11:11:56 +02:00
|
|
|
|
|
2019-12-14 18:50:05 +02:00
|
|
|
|
fn set_dirty(&mut self, value: bool) {
|
2023-10-23 13:56:13 +03:00
|
|
|
|
//if let Some(p) = self.view.as_mut() {
|
|
|
|
|
// p.set_dirty(value);
|
|
|
|
|
//};
|
2019-12-14 18:50:05 +02:00
|
|
|
|
self.dirty = value;
|
2019-02-21 15:31:01 +02:00
|
|
|
|
}
|
2019-03-02 08:39:59 +02:00
|
|
|
|
|
2023-06-13 17:45:48 +03:00
|
|
|
|
fn kill(&mut self, uuid: ComponentId, context: &mut Context) {
|
2019-09-07 22:07:13 +03:00
|
|
|
|
debug_assert!(uuid == self.id);
|
2023-08-30 01:12:45 +03:00
|
|
|
|
context
|
|
|
|
|
.replies
|
|
|
|
|
.push_back(UIEvent::Action(Tab(TabAction::Kill(uuid))));
|
2019-03-02 08:39:59 +02:00
|
|
|
|
}
|
2023-06-13 17:45:48 +03:00
|
|
|
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
2023-10-23 13:56:13 +03:00
|
|
|
|
let mut map = ShortcutMaps::default(); //self
|
|
|
|
|
//.view
|
|
|
|
|
//.as_ref()
|
|
|
|
|
//.map(|p| p.shortcuts(context))
|
|
|
|
|
//.unwrap_or_default();
|
2019-03-04 10:15:11 +02:00
|
|
|
|
|
2022-11-28 16:18:49 +02:00
|
|
|
|
map.insert(
|
|
|
|
|
Shortcuts::CONTACT_LIST,
|
|
|
|
|
context.settings.shortcuts.contact_list.key_values(),
|
|
|
|
|
);
|
|
|
|
|
map.insert(
|
|
|
|
|
Shortcuts::GENERAL,
|
|
|
|
|
context.settings.shortcuts.general.key_values(),
|
|
|
|
|
);
|
2019-03-04 10:15:11 +02:00
|
|
|
|
|
|
|
|
|
map
|
|
|
|
|
}
|
2019-04-10 22:01:02 +03:00
|
|
|
|
|
|
|
|
|
fn id(&self) -> ComponentId {
|
|
|
|
|
self.id
|
|
|
|
|
}
|
2019-10-20 11:14:29 +03:00
|
|
|
|
|
2023-10-23 13:56:13 +03:00
|
|
|
|
fn can_quit_cleanly(&mut self, _context: &Context) -> bool {
|
|
|
|
|
true
|
|
|
|
|
//self.view .as_mut() .map(|p| p.can_quit_cleanly(context))
|
|
|
|
|
// .unwrap_or(true)
|
2019-10-20 11:14:29 +03:00
|
|
|
|
}
|
2019-10-26 15:58:56 +03:00
|
|
|
|
|
2023-06-13 17:45:48 +03:00
|
|
|
|
fn status(&self, context: &Context) -> String {
|
2020-02-08 23:18:02 +02:00
|
|
|
|
format!(
|
2019-10-26 15:58:56 +03:00
|
|
|
|
"{} entries",
|
|
|
|
|
context.accounts[self.account_pos].address_book.len()
|
2020-02-08 23:18:02 +02:00
|
|
|
|
)
|
2019-10-26 15:58:56 +03:00
|
|
|
|
}
|
2019-02-21 15:31:01 +02:00
|
|
|
|
}
|