Skip to content

Commit d3fd499

Browse files
committed
nicklist in sidebar
1 parent 79160f4 commit d3fd499

File tree

7 files changed

+190
-28
lines changed

7 files changed

+190
-28
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Added:
77
- Setting to style unread query buffers as highlights in the sidebar (`sidebar.unread_indicator.query_as_highlight`)
88
- Settings to configure card and imagge preview dimensions
99
- Support for transparent background.
10+
- Settings to show nicklist in the sidebar together with the buflist (`sidebar.show_nicklist`, `sidebar.split`, `sidebar.buflist_space`, `sidebar.nicklist_space`)
1011

1112
Fixed:
1213

book/src/configuration/sidebar/README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ Sidebar settings for Halloy.
77
- [server\_icon](#server_icon)
88
- [position](#position)
99
- [max\_width](#max_width)
10+
- [show\_nicklist](#show_nicklist)
11+
- [split](#split)
12+
- [buflist\_space](#buflist_space)
13+
- [nicklist\_space](#nicklist_space)
1014
- [show\_menu\_button](#show_menu_button)
1115
- [order\_by](#order_by)
1216
- [Scrollbar](#scrollbar)
@@ -62,6 +66,61 @@ Specify sidebar max width in pixels. Only used if `position` is `"left"` or `"ri
6266
max_width = 200
6367
```
6468

69+
### show_nicklist
70+
71+
Show the nicklist for the focused channel in the sidebar (rendered below the buffer list). Only used if `position` is `"left"` or `"right"`.
72+
73+
```toml
74+
# Type: bool
75+
# Values: true, false
76+
# Default: false
77+
78+
[sidebar]
79+
show_nicklist = true
80+
```
81+
82+
### split
83+
84+
When `show_nicklist` is enabled, controls how the vertical space is split between the buffer list and the nicklist.
85+
86+
- `false`: buffer list shrinks; nicklist takes the remaining space.
87+
- `true`: buffer list and nicklist use proportional space controlled by `buflist_space` and `nicklist_space`.
88+
89+
```toml
90+
# Type: bool
91+
# Values: true, false
92+
# Default: false
93+
94+
[sidebar]
95+
split = true
96+
```
97+
98+
### buflist_space
99+
100+
Relative space for the buffer list when `split = true`.
101+
102+
```toml
103+
# Type: integer
104+
# Values: any positive integer
105+
# Default: 2
106+
107+
[sidebar]
108+
buflist_space = 2
109+
```
110+
111+
### nicklist_space
112+
113+
Relative space for the nicklist when `split = true`.
114+
115+
```toml
116+
# Type: integer
117+
# Values: any positive integer
118+
# Default: 1
119+
120+
[sidebar]
121+
nicklist_space = 1
122+
```
123+
65124
### show_menu_button
66125

67126
Show or hide the user menu button in the sidebar.

data/src/config/sidebar.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,19 @@ use crate::serde::deserialize_positive_integer;
77
use crate::server::Server;
88
use crate::{isupport, target};
99

10-
#[derive(Debug, Clone, Default, Deserialize)]
10+
#[derive(Debug, Clone, Deserialize)]
1111
#[serde(default)]
1212
pub struct Sidebar {
1313
pub max_width: Option<u16>,
1414
#[serde(deserialize_with = "deserialize_unread_indicator")]
1515
pub unread_indicator: UnreadIndicator,
1616
pub position: Position,
17+
pub show_nicklist: bool,
18+
pub split: bool,
19+
#[serde(deserialize_with = "deserialize_positive_integer")]
20+
pub buflist_space: u16,
21+
#[serde(deserialize_with = "deserialize_positive_integer")]
22+
pub nicklist_space: u16,
1723
pub order_by: OrderBy,
1824
pub scrollbar: Scrollbar,
1925
#[serde(
@@ -26,6 +32,26 @@ pub struct Sidebar {
2632
pub spacing: Spacing,
2733
}
2834

35+
impl Default for Sidebar {
36+
fn default() -> Self {
37+
Self {
38+
max_width: None,
39+
unread_indicator: UnreadIndicator::default(),
40+
position: Position::default(),
41+
show_nicklist: false,
42+
split: false,
43+
buflist_space: 2,
44+
nicklist_space: 1,
45+
order_by: OrderBy::default(),
46+
scrollbar: Scrollbar::default(),
47+
server_icon: ServerIcon::default(),
48+
user_menu: UserMenu::default(),
49+
padding: Padding::default(),
50+
spacing: Spacing::default(),
51+
}
52+
}
53+
}
54+
2955
#[derive(Debug, Clone, Deserialize)]
3056
#[serde(rename_all = "kebab-case")]
3157
pub enum ServerIcon {

data/src/serde.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,21 +133,22 @@ where
133133
}
134134
}
135135

136-
pub fn deserialize_positive_integer<'de, D>(
136+
pub fn deserialize_positive_integer<'de, D, T>(
137137
deserializer: D,
138-
) -> Result<u32, D::Error>
138+
) -> Result<T, D::Error>
139139
where
140140
D: Deserializer<'de>,
141+
T: Deserialize<'de> + PartialEq + Default,
141142
{
142-
let integer: u32 = Deserialize::deserialize(deserializer)?;
143+
let value: T = T::deserialize(deserializer)?;
143144

144-
if integer == 0 {
145+
if value == T::default() {
145146
Err(serde::de::Error::invalid_value(
146-
serde::de::Unexpected::Unsigned(integer.into()),
147+
serde::de::Unexpected::Unsigned(0),
147148
&"any positive integer",
148149
))
149150
} else {
150-
Ok(integer)
151+
Ok(value)
151152
}
152153
}
153154

src/buffer/channel.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ fn topic<'a>(
412412
)
413413
}
414414

415-
mod nick_list {
415+
pub(crate) mod nick_list {
416416
use context_menu::Message;
417417
use data::user::ChannelUsers;
418418
use data::{Config, Server, User, config, isupport, target};

src/screen/dashboard.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,18 @@ impl Dashboard {
543543

544544
(Task::none(), None)
545545
}
546+
sidebar::Event::NicklistEvent(message) => {
547+
let Focus { window, pane } = self.focus;
548+
let event = buffer::context_menu::update(message);
549+
550+
self.handle_buffer_event(
551+
window,
552+
pane,
553+
buffer::Event::ContextMenu(event),
554+
clients,
555+
config,
556+
)
557+
}
546558
sidebar::Event::OpenConfigFile => {
547559
let _ = open::that_detached(Config::path());
548560
(Task::none(), None)

src/screen/dashboard/sidebar.rs

Lines changed: 83 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use iced::{Alignment, Length, Padding, Task, padding};
1111
use tokio::time;
1212

1313
use super::{Focus, Panes, Server};
14+
use crate::buffer::context_menu as buffer_context_menu;
1415
use crate::widget::{Element, Text, context_menu, double_pass};
1516
use crate::{Theme, font, icon, platform_specific, theme, window};
1617

@@ -38,6 +39,7 @@ pub enum Message {
3839
ReloadComplete,
3940
MarkAsRead(buffer::Upstream),
4041
MarkServerAsRead(Server),
42+
NicklistEvent(buffer_context_menu::Message),
4143
QuitApplication,
4244
}
4345

@@ -61,6 +63,7 @@ pub enum Event {
6163
ConfigReloaded(Result<Config, config::Error>),
6264
MarkAsRead(buffer::Upstream),
6365
MarkServerAsRead(Server),
66+
NicklistEvent(buffer_context_menu::Message),
6467
QuitApplication,
6568
}
6669

@@ -156,6 +159,9 @@ impl Sidebar {
156159
Message::MarkServerAsRead(server) => {
157160
(Task::none(), Some(Event::MarkServerAsRead(server)))
158161
}
162+
Message::NicklistEvent(message) => {
163+
(Task::none(), Some(Event::NicklistEvent(message)))
164+
}
159165
Message::OpenConfigFile => {
160166
(Task::none(), Some(Event::OpenConfigFile))
161167
}
@@ -393,7 +399,7 @@ impl Sidebar {
393399
pub fn view<'a>(
394400
&'a self,
395401
servers: &server::Map,
396-
clients: &data::client::Map,
402+
clients: &'a data::client::Map,
397403
history: &'a history::Manager,
398404
panes: &'a Panes,
399405
focus: Focus,
@@ -564,27 +570,49 @@ impl Sidebar {
564570

565571
match config.sidebar.position {
566572
sidebar::Position::Left | sidebar::Position::Right => {
567-
// Add buffers to a column.
568-
let buffers = column![
569-
Scrollable::new(
570-
Column::with_children(buffers).spacing(1)
571-
)
572-
.direction(
573-
scrollable::Direction::Vertical(
574-
scrollable::Scrollbar::default()
575-
.width(config.sidebar.scrollbar.width)
576-
.scroller_width(
577-
config.sidebar.scrollbar.scroller_width
578-
)
573+
let nicklist: Option<Element<'a, Message>> =
574+
if config.sidebar.show_nicklist {
575+
focused_channel_nicklist(
576+
panes, focus, clients, config, theme, width,
579577
)
580-
)
581-
];
578+
.map(|list| {
579+
container(list)
580+
.padding([0, 2])
581+
.height(if config.sidebar.split {
582+
Length::FillPortion(
583+
config.sidebar.nicklist_space,
584+
)
585+
} else {
586+
Length::Fill
587+
})
588+
.into()
589+
})
590+
} else {
591+
None
592+
};
582593

583-
// Wrap buffers in a column with user_menu_button
584-
let content = column![
585-
container(buffers).height(Length::Fill),
586-
user_menu_button,
587-
];
594+
let buflist_height =
595+
if config.sidebar.split && nicklist.is_some() {
596+
Length::FillPortion(config.sidebar.buflist_space)
597+
} else if nicklist.is_some() {
598+
Length::Shrink
599+
} else {
600+
Length::Fill
601+
};
602+
603+
let buflist = Scrollable::new(
604+
Column::with_children(buffers).spacing(0),
605+
)
606+
.direction(scrollable::Direction::Vertical(
607+
scrollable::Scrollbar::default()
608+
.width(config.sidebar.scrollbar.width)
609+
.scroller_width(
610+
config.sidebar.scrollbar.scroller_width,
611+
),
612+
))
613+
.height(buflist_height);
614+
615+
let content = column![buflist, nicklist, user_menu_button,];
588616

589617
container(content)
590618
}
@@ -656,6 +684,41 @@ impl Sidebar {
656684
}
657685
}
658686

687+
fn focused_channel_nicklist<'a>(
688+
panes: &'a Panes,
689+
focus: Focus,
690+
clients: &'a data::client::Map,
691+
config: &'a Config,
692+
theme: &'a Theme,
693+
width: Length,
694+
) -> Option<Element<'a, Message>> {
695+
if !matches!(width, Length::Fill) {
696+
return None;
697+
}
698+
699+
let (server, channel) =
700+
panes.iter().find_map(|(window, pane, state)| {
701+
if (Focus { window, pane }) != focus {
702+
return None;
703+
}
704+
match state.buffer.upstream() {
705+
Some(buffer::Upstream::Channel(server, channel)) => {
706+
Some((server, channel))
707+
}
708+
_ => None,
709+
}
710+
})?;
711+
712+
let users = clients.get_channel_users(server, channel);
713+
let prefix = clients.get_prefix(server);
714+
let list = crate::buffer::channel::nick_list::view(
715+
server, prefix, channel, users, None, config, theme,
716+
)
717+
.map(Message::NicklistEvent);
718+
719+
Some(list)
720+
}
721+
659722
#[derive(Debug, Clone, Copy)]
660723
enum Menu {
661724
RefreshConfig,

0 commit comments

Comments
 (0)