Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::collections::HashMap;

use crate::app::apps::{App, AppCommand, ICNS_ICON};
use crate::commands::Function;
use crate::config::{Config, Shelly};
use crate::config::{Config, MainPage, Shelly};
use crate::debounce::DebouncePolicy;
use crate::utils::icns_data_to_handle;
use crate::{app::tile::ExtSender, clipboard::ClipBoardContentType};
Expand Down Expand Up @@ -82,6 +82,7 @@ pub enum Message {
WriteConfig(bool),
SaveRanking,
LoadRanking,
ToggleFavouriteApp(String),
UpdateAvailable,
ResizeWindow(Id, f32),
OpenWindow,
Expand Down Expand Up @@ -125,7 +126,7 @@ pub enum SetConfigFields {
SearchUrl(String),
HapticFeedback(bool),
ShowMenubarIcon(bool),
AutoSuggest(bool),
SetPage(MainPage),
Modes(Editable<(String, String)>),
Aliases(Editable<(String, String)>),
SearchDirs(Editable<String>),
Expand Down
8 changes: 8 additions & 0 deletions src/app/apps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,14 @@ impl App {
}
row = row.push(container(text_block).width(Fill));

let name = self.search_name.clone();
let theme_clone = theme.clone();
row = row.push(
Button::new("♥️")
.on_press_with(move || Message::ToggleFavouriteApp(name.clone()))
.style(move |_, _| result_button_style(&theme_clone)),
);

let msg = on_press.or(match self.open_command.clone() {
AppCommand::Function(func) => Some(Message::RunFunction(func)),
AppCommand::Message(msg) => Some(msg),
Expand Down
43 changes: 35 additions & 8 deletions src/app/pages/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ use iced::widget::Slider;
use iced::widget::Space;
use iced::widget::TextInput;
use iced::widget::checkbox;
use iced::widget::radio;
use iced::widget::text_input;

use crate::app::Editable;
use crate::app::SetConfigBufferFields;
use crate::app::SetConfigThemeFields;
use crate::commands::Function;
use crate::config::MainPage;
use crate::config::Shelly;
use crate::styles::delete_button_style;
use crate::styles::settings_add_button_style;
use crate::styles::settings_checkbox_style;
use crate::styles::settings_radio_button_style;
use crate::styles::settings_save_button_style;
use crate::styles::settings_slider_style;
use crate::styles::settings_text_input_item_style;
Expand Down Expand Up @@ -130,16 +133,40 @@ pub fn settings_page(config: Config) -> Element<'static, Message> {
]);

let theme_clone = theme.clone();
let auto_suggest = settings_item_row([
let auto_suggest = settings_item_column([
settings_hint_text(theme.clone(), "Suggestions on open"),
checkbox(config.auto_suggest)
.style(move |_, _| settings_checkbox_style(&theme_clone))
.on_toggle(|input| Message::SetConfig(SetConfigFields::AutoSuggest(input)))
settings_item_row([
radio(
"Favourites",
MainPage::Favourites,
Some(config.main_page),
|page| Message::SetConfig(SetConfigFields::SetPage(page)),
)
.style({
let theme_clone = theme_clone.clone();
move |_, _| settings_radio_button_style(&theme_clone.clone())
})
.into(),
notice_item(
theme.clone(),
"If an empty query should give you your most used actions",
),
radio(
"Frequently Used",
MainPage::FrequentlyUsed,
Some(config.main_page),
|page| Message::SetConfig(SetConfigFields::SetPage(page)),
)
.style({
let theme_clone = theme_clone.clone();
move |_, _| settings_radio_button_style(&theme_clone.clone())
})
.into(),
radio("Nothing", MainPage::Blank, Some(config.main_page), |page| {
Message::SetConfig(SetConfigFields::SetPage(page))
})
.style(move |_, _| settings_radio_button_style(&theme_clone.clone()))
.into(),
])
.spacing(30)
.into(),
notice_item(theme.clone(), "What an empty query should show"),
]);

let theme_clone = theme.clone();
Expand Down
13 changes: 13 additions & 0 deletions src/app/tile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,19 @@ impl AppIndex {
ranked
}

fn get_favourites(&self) -> Vec<App> {
self.by_name
.values()
.filter_map(|x| {
if x.ranking == -1 {
Some(x.to_owned())
} else {
None
}
})
.collect()
}

fn empty() -> AppIndex {
AppIndex {
by_name: HashMap::new(),
Expand Down
7 changes: 3 additions & 4 deletions src/app/tile/elm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,9 @@ pub fn view(tile: &Tile, wid: window::Id) -> Element<'_, Message> {
.height(height as u32);

let text = if tile.query_lc.is_empty() {
if tile.config.auto_suggest && tile.page == Page::Main {
"Frequently used".to_string()
} else {
tile.page.to_string()
match &tile.page {
Page::Main => tile.config.main_page.to_string(),
page => page.to_string(),
}
} else {
match results_count {
Expand Down
28 changes: 24 additions & 4 deletions src/app/tile/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use crate::app::{Message, Page, tile::Tile};
use crate::calculator::Expr;
use crate::commands::Function;
use crate::config::Config;
use crate::config::MainPage;
use crate::debounce::DebouncePolicy;
use crate::quit::get_open_apps;
use crate::unit_conversion;
Expand All @@ -50,7 +51,7 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task<Message> {
tile.focused = true;
tile.visible = true;

if tile.page == Page::Main && tile.query_lc.is_empty() && tile.config.auto_suggest {
if tile.page == Page::Main && tile.query_lc.is_empty() {
window::latest()
.map(|x| x.unwrap())
.map(|id| Message::SearchQueryChanged(String::new(), id))
Expand Down Expand Up @@ -436,6 +437,21 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task<Message> {
])
}

Message::ToggleFavouriteApp(app_name) => {
let ranking = match tile.options.by_name.get(&app_name) {
None => return Task::none(),
Some(app) => {
if app.ranking == -1 {
0
} else {
-1
}
}
};
tile.options.set_ranking(&app_name, ranking);
Task::none()
}

Message::UpdateApps => {
let mut new_options = get_installed_apps(tile.config.theme.show_icons);
new_options.extend(tile.config.shells.iter().map(|x| x.to_app()));
Expand Down Expand Up @@ -678,7 +694,7 @@ pub fn handle_update(tile: &mut Tile, message: Message) -> Task<Message> {

SetConfigFields::SearchUrl(url) => final_config.search_url = url,
SetConfigFields::PlaceHolder(placeholder) => final_config.placeholder = placeholder,
SetConfigFields::AutoSuggest(status) => final_config.auto_suggest = status,
SetConfigFields::SetPage(page) => final_config.main_page = page,
SetConfigFields::DebounceDelay(delay) => final_config.debounce_delay = delay,
SetConfigFields::HapticFeedback(haptic_feedback) => {
final_config.haptic_feedback = haptic_feedback
Expand Down Expand Up @@ -860,8 +876,12 @@ fn execute_query(tile: &mut Tile, id: Id) -> Task<Message> {
_ => {}
}

if tile.page == Page::Main && tile.query_lc.is_empty() && tile.config.auto_suggest {
tile.results = tile.frequent_results();
if tile.page == Page::Main && tile.query_lc.is_empty() {
tile.results = match tile.config.main_page {
MainPage::FrequentlyUsed => tile.frequent_results(),
MainPage::Blank => vec![],
MainPage::Favourites => tile.options.get_favourites(),
};
return resize_for_results_count(id, tile.results.len());
}

Expand Down
23 changes: 21 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub struct Config {
pub toggle_hotkey: String,
pub clipboard_hotkey: String,
pub buffer_rules: Buffer,
pub main_page: MainPage,
pub theme: Theme,
pub placeholder: String,
pub search_url: String,
Expand All @@ -29,7 +30,6 @@ pub struct Config {
pub modes: HashMap<String, String>,
pub aliases: HashMap<String, String>,
pub search_dirs: Vec<String>,
pub auto_suggest: bool,
pub log_path: String,
pub debounce_delay: u64,
}
Expand All @@ -46,7 +46,7 @@ impl Default for Config {
search_url: "https://duckduckgo.com/search?q=%s".to_string(),
haptic_feedback: false,
show_trayicon: true,
auto_suggest: true,
main_page: MainPage::default(),
search_dirs: vec!["~".to_string()],
log_path: "/tmp/rustcast.log".to_string(),
modes: HashMap::new(),
Expand All @@ -57,6 +57,25 @@ impl Default for Config {
}
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default, Eq, Copy)]
#[serde(rename_all = "lowercase")]
pub enum MainPage {
Favourites,
FrequentlyUsed,
#[default]
Blank,
}

impl std::fmt::Display for MainPage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
MainPage::Blank => "♥️ Rustcast",
MainPage::Favourites => "Favourites",
MainPage::FrequentlyUsed => "Frequently Used",
})
}
}

/// The settings you can set for the theme
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(default)]
Expand Down
13 changes: 12 additions & 1 deletion src/styles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use crate::config::Theme as ConfigTheme;
use iced::Shadow;
use iced::border::Radius;
use iced::widget::{button, checkbox, container, scrollable, slider};
use iced::widget::{button, checkbox, container, radio, scrollable, slider};
use iced::{Background, Border, Color, widget::text_input};

/// Helper: mix base color with white (simple “tint”)
Expand All @@ -12,6 +12,7 @@ pub fn tint(mut c: Color, amount: f32) -> Color {
c.b = c.b + (1.0 - c.b) * amount;
c
}

/// Helper: apply alpha
pub fn with_alpha(mut c: Color, a: f32) -> Color {
c.a = a;
Expand Down Expand Up @@ -119,6 +120,16 @@ pub fn results_scrollbar_style(tile: &ConfigTheme) -> scrollable::Style {
}
}

pub fn settings_radio_button_style(theme: &ConfigTheme) -> radio::Style {
radio::Style {
background: Background::Color(Color::TRANSPARENT),
dot_color: theme.text_color(0.4),
border_width: 1.,
border_color: theme.text_color(0.7),
text_color: Some(theme.text_color(1.)),
}
}

/// Each rustcast results rows style
pub fn result_row_container_style(tile: &ConfigTheme, focused: bool) -> container::Style {
container::Style {
Expand Down
Loading