bin: Use theme settings in issue selection

This commit is contained in:
Erik Kundt
2024-07-15 14:12:51 +02:00
parent 0e3c9ab2c1
commit ba1ef1cc00
8 changed files with 178 additions and 14 deletions
+2
View File
@@ -7,6 +7,8 @@
**Binary features:**
- Issue preview widgets in `issue select`
- Basic theming support with light and dark theme bundles
- Support for application settings
**Library features:**
Generated
+89 -4
View File
@@ -364,6 +364,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cfg_aliases"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "chacha20"
version = "0.9.1"
@@ -435,6 +441,12 @@ version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "coolor"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e93977247fb916abeee1ff8c6594c9b421fd9c26c9b720a3944acb2a7de27b"
[[package]]
name = "core-foundation-sys"
version = "0.8.4"
@@ -478,6 +490,31 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "crossterm"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
dependencies = [
"bitflags 2.4.1",
"crossterm_winapi",
"libc",
"mio",
"parking_lot",
"signal-hook",
"signal-hook-mio",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
dependencies = [
"winapi",
]
[[package]]
name = "crypto-bigint"
version = "0.5.5"
@@ -1040,9 +1077,9 @@ dependencies = [
[[package]]
name = "lazy_static"
version = "1.4.0"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
dependencies = [
"spin",
]
@@ -1168,6 +1205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
dependencies = [
"libc",
"log",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.48.0",
]
@@ -1192,6 +1230,18 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "nix"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
dependencies = [
"bitflags 2.4.1",
"cfg-if",
"cfg_aliases",
"libc",
]
[[package]]
name = "nom"
version = "7.1.3"
@@ -1819,6 +1869,7 @@ dependencies = [
"anyhow",
"fuzzy-matcher",
"inquire",
"lazy_static",
"lexopt",
"libc",
"log",
@@ -1832,6 +1883,7 @@ dependencies = [
"serde_json",
"signal-hook",
"simple-logging",
"terminal-light",
"termion 3.0.0",
"textwrap",
"thiserror",
@@ -2111,6 +2163,17 @@ dependencies = [
"signal-hook-registry",
]
[[package]]
name = "signal-hook-mio"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
dependencies = [
"libc",
"mio",
"signal-hook",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
@@ -2221,9 +2284,9 @@ dependencies = [
[[package]]
name = "spin"
version = "0.5.2"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]]
name = "spki"
@@ -2404,6 +2467,18 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "terminal-light"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2ecb7b6ab8a3eeff2b61770d313d1e971f184e29321785c62ef523b132437b7"
dependencies = [
"coolor",
"crossterm",
"thiserror",
"xterm-query",
]
[[package]]
name = "termion"
version = "2.0.3"
@@ -3071,6 +3146,16 @@ dependencies = [
"libc",
]
[[package]]
name = "xterm-query"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f29504d0a2ca8c1714781c1395a8a660d2557b2cf9c9669433153fc903e9bfc"
dependencies = [
"nix",
"thiserror",
]
[[package]]
name = "yansi"
version = "0.5.1"
+2
View File
@@ -26,6 +26,7 @@ anyhow = { version = "1" }
inquire = { version = "0.7.4", default-features = false, features = ["termion", "editor"] }
lexopt = { version = "0.3.0" }
fuzzy-matcher = "0.3.7"
lazy_static = { version = "1.5.0" }
libc = { version = "^0.2" }
log = { version = "0.4.19" }
nom = { version = "^7.1.0" }
@@ -40,6 +41,7 @@ serde_json = { version = "1.0" }
signal-hook = { version = "0.3.17" }
timeago = { version = "0.4.1" }
termion = { version = "3" }
terminal-light = { version = "1.4.0" }
textwrap = { version = "0.16.0" }
thiserror = { version = "1" }
tokio = { version = "1.32.0", features = ["full"] }
+13 -1
View File
@@ -7,6 +7,8 @@ use std::ffi::OsString;
use anyhow::anyhow;
use lazy_static::lazy_static;
use radicle::identity::RepoId;
use radicle::issue;
@@ -18,6 +20,13 @@ use radicle_tui as tui;
use tui::log;
use crate::cob;
use crate::ui::TerminalInfo;
lazy_static! {
static ref TERMINAL_INFO: TerminalInfo = TerminalInfo {
luma: Some(terminal_light::luma().unwrap_or_default())
};
}
pub const HELP: Help = Help {
name: "issue",
@@ -143,6 +152,8 @@ pub async fn run(options: Options, ctx: impl terminal::Context) -> anyhow::Resul
let (_, rid) = radicle::rad::cwd()
.map_err(|_| anyhow!("this command must be run in the context of a project"))?;
let terminal_info = TERMINAL_INFO.clone();
match options.op {
Operation::Select { opts } => {
let profile = ctx.profile()?;
@@ -157,7 +168,8 @@ pub async fn run(options: Options, ctx: impl terminal::Context) -> anyhow::Resul
mode: opts.mode,
filter: opts.filter.clone(),
};
let output = select::App::new(context).run().await?;
let output = select::App::new(context, terminal_info).run().await?;
let output = output
.map(|o| serde_json::to_string(&o).unwrap_or_default())
+53 -9
View File
@@ -23,9 +23,10 @@ use radicle_tui as tui;
use tui::store;
use tui::store::StateValue;
use tui::ui::span;
use tui::ui::theme::Theme;
use tui::ui::widget::container::{
Column, Container, Footer, FooterProps, Header, HeaderProps, SectionGroup, SectionGroupProps,
SplitContainer, SplitContainerFocus, SplitContainerProps,
Column, Container, ContainerProps, Footer, FooterProps, Header, HeaderProps, SectionGroup,
SectionGroupProps, SplitContainer, SplitContainerFocus, SplitContainerProps,
};
use tui::ui::widget::input::{TextView, TextViewProps};
use tui::ui::widget::list::{Tree, TreeProps};
@@ -34,8 +35,10 @@ use tui::ui::widget::{PredefinedLayout, ToWidget, Widget};
use tui::{BoxedAny, Channel, Exit, PageStack};
use crate::cob::issue;
use crate::settings::{self, ThemeBundle, ThemeMode};
use crate::ui::items::{CommentItem, Filter, IssueItem, IssueItemFilter};
use crate::ui::widget::{IssueDetails, IssueDetailsProps};
use crate::ui::TerminalInfo;
use self::ui::{Browser, BrowserProps};
@@ -52,6 +55,7 @@ pub struct Context {
pub struct App {
context: Context,
terminal_info: TerminalInfo,
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
@@ -230,16 +234,34 @@ pub struct State {
preview: PreviewState,
section: Option<Section>,
help: HelpState,
theme: Theme,
}
impl TryFrom<&Context> for State {
impl TryFrom<(&Context, &TerminalInfo)> for State {
type Error = anyhow::Error;
fn try_from(context: &Context) -> Result<Self, Self::Error> {
fn try_from(value: (&Context, &TerminalInfo)) -> Result<Self, Self::Error> {
let (context, terminal_info) = value;
let settings = settings::Settings::default();
let issues = issue::all(&context.profile, &context.repository)?;
let search = StateValue::new(context.filter.to_string());
let filter = IssueItemFilter::from_str(&search.read()).unwrap_or_default();
let default_bundle = ThemeBundle::default();
let theme_bundle = settings.theme.active_bundle().unwrap_or(&default_bundle);
let theme = match settings.theme.mode() {
ThemeMode::Auto => {
if terminal_info.is_dark() {
theme_bundle.dark.clone()
} else {
theme_bundle.light.clone()
}
}
ThemeMode::Light => theme_bundle.light.clone(),
ThemeMode::Dark => theme_bundle.dark.clone(),
};
// Convert into UI items
let mut items = vec![];
for issue in issues {
@@ -282,6 +304,7 @@ impl TryFrom<&Context> for State {
scroll: 0,
cursor: (0, 0),
},
theme,
})
}
}
@@ -426,13 +449,16 @@ impl store::State<Selection> for State {
}
impl App {
pub fn new(context: Context) -> Self {
Self { context }
pub fn new(context: Context, terminal_info: TerminalInfo) -> Self {
Self {
context,
terminal_info,
}
}
pub async fn run(&self) -> Result<Option<Selection>> {
let channel = Channel::default();
let state = State::try_from(&self.context)?;
let state = State::try_from((&self.context, &self.terminal_info))?;
let tx = channel.tx.clone();
let window = Window::default()
@@ -471,6 +497,8 @@ fn browser_page(channel: &Channel<Message>) -> Widget<State, Message> {
ShortcutsProps::default()
.shortcuts(&shortcuts)
.shortcuts_keys_style(state.theme.shortcuts_keys_style)
.shortcuts_action_style(state.theme.shortcuts_action_style)
.to_boxed_any()
.into()
});
@@ -548,9 +576,11 @@ fn issue(channel: &Channel<Message>) -> Widget<State, Message> {
.top(issue_details(channel))
.bottom(comment_tree(channel))
.to_widget(tx.clone())
.on_update(|_| {
.on_update(|state| {
SplitContainerProps::default()
.heights([Constraint::Length(5), Constraint::Min(1)])
.border_color(state.theme.border_color)
.focus_border_color(state.theme.focus_border_color)
.split_focus(SplitContainerFocus::Bottom)
.to_boxed_any()
.into()
@@ -641,6 +671,13 @@ fn comment(channel: &Channel<Message>) -> Widget<State, Message> {
}),
)
.to_widget(tx.clone())
.on_update(|state| {
ContainerProps::default()
.border_color(state.theme.border_color)
.focus_border_color(state.theme.focus_border_color)
.to_boxed_any()
.into()
})
}
fn help_page(channel: &Channel<Message>) -> Widget<State, Message> {
@@ -691,7 +728,14 @@ fn help_page(channel: &Channel<Message>) -> Widget<State, Message> {
.into()
}),
)
.to_widget(tx.clone());
.to_widget(tx.clone())
.on_update(|state| {
ContainerProps::default()
.border_color(state.theme.border_color)
.focus_border_color(state.theme.focus_border_color)
.to_boxed_any()
.into()
});
let shortcuts = Shortcuts::default().to_widget(tx.clone()).on_update(|_| {
ShortcutsProps::default()
+7
View File
@@ -124,8 +124,11 @@ impl Browser {
.header(Header::default().to_widget(tx.clone()).on_update(|state| {
// TODO: remove and use state directly
let props = BrowserProps::from(state);
HeaderProps::default()
.columns(props.header.clone())
.border_color(state.theme.border_color)
.focus_border_color(state.theme.focus_border_color)
.to_boxed_any()
.into()
}))
@@ -155,12 +158,16 @@ impl Browser {
FooterProps::default()
.columns(browse_footer(&props))
.border_color(state.theme.border_color)
.focus_border_color(state.theme.focus_border_color)
.to_boxed_any()
.into()
}))
.to_widget(tx.clone())
.on_update(|state| {
ContainerProps::default()
.border_color(state.theme.border_color)
.focus_border_color(state.theme.focus_border_color)
.hide_footer(BrowserProps::from(state).show_search)
.to_boxed_any()
.into()
+1
View File
@@ -2,6 +2,7 @@ mod cob;
mod commands;
mod git;
mod ui;
mod settings;
use std::ffi::OsString;
use std::io;
+11
View File
@@ -1,3 +1,14 @@
pub mod format;
pub mod items;
pub mod widget;
#[derive(Clone, Debug)]
pub struct TerminalInfo {
pub luma: Option<f32>,
}
impl TerminalInfo {
pub fn is_dark(&self) -> bool {
self.luma.unwrap_or_default() <= 0.6
}
}