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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
> search bar that people can use to do many things, like opening apps,
> calculators, quick-notes, etc.

![RustCast Demo PreRelease V1](./docs/rustcast-v0-3-4.png)
![RustCast Demo PreRelease V1](./docs/rustcast-v0-4-5.png)

## Installation:

Expand Down
7 changes: 5 additions & 2 deletions docs/default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ clear_on_enter = true

[theme]
text_color = [0.95, 0.95, 0.96]
background_color = [0.0, 0.0, 0.0]
background_opacity = 0.25
background_color = [0.09, 0.09, 0.09]
# Background opacity should / can be omitted from 0.4.5 onwards,
# as rustcast doesn't support custom opacity's anymore,
# this field will have no effect on rustcast
background_opacity = 0.0
blur = false
show_icons = true
show_scroll_bar = true
2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ <h1>
<div class="preview-frame">
<div class="preview-glow"></div>
<div class="preview-inner">
<img src="rustcast-v0-3-4.png" alt="RustCast Demo" />
<img src="rustcast-v0-4-5.png" alt="RustCast Demo" />
</div>
<div class="ferris-tag">
<img
Expand Down
Binary file added docs/rustcast-v0.4.5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use iced::window::{self, Id, Settings};
pub const WINDOW_WIDTH: f32 = 500.;

/// The default window height
pub const DEFAULT_WINDOW_HEIGHT: f32 = 65.;
pub const DEFAULT_WINDOW_HEIGHT: f32 = 80.;

/// The rustcast descriptor name to be put for all rustcast commands
pub const RUSTCAST_DESC_NAME: &str = "RustCast";
Expand Down
135 changes: 66 additions & 69 deletions src/app/apps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@
use std::path::Path;

use iced::{
Alignment, Background,
Alignment,
Length::Fill,
alignment::Vertical,
border::Radius,
widget::{Button, Row, Text, container, image::Viewer},
};

use crate::{
app::{Message, Page, RUSTCAST_DESC_NAME},
commands::Function,
styles::{result_button_style, result_row_container_style},
utils::handle_from_icns,
};

Expand Down Expand Up @@ -58,35 +57,45 @@ impl App {
App {
open_command: AppCommand::Function(Function::Quit),
desc: RUSTCAST_DESC_NAME.to_string(),
icons: None,
icons: handle_from_icns(Path::new(
"/Applications/Rustcast.app/Contents/Resources/icon.icns",
)),
name: "Quit RustCast".to_string(),
name_lc: "quit".to_string(),
},
App {
open_command: AppCommand::Function(Function::OpenPrefPane),
desc: RUSTCAST_DESC_NAME.to_string(),
icons: None,
icons: handle_from_icns(Path::new(
"/Applications/Rustcast.app/Contents/Resources/icon.icns",
)),
name: "Open RustCast Preferences".to_string(),
name_lc: "settings".to_string(),
},
App {
open_command: AppCommand::Message(Message::SwitchToPage(Page::ClipboardHistory)),
desc: RUSTCAST_DESC_NAME.to_string(),
icons: None,
icons: handle_from_icns(Path::new(
"/Applications/Rustcast.app/Contents/Resources/icon.icns",
)),
name: "Clipboard History".to_string(),
name_lc: "clipboard".to_string(),
},
App {
open_command: AppCommand::Message(Message::ReloadConfig),
desc: RUSTCAST_DESC_NAME.to_string(),
icons: None,
icons: handle_from_icns(Path::new(
"/Applications/Rustcast.app/Contents/Resources/icon.icns",
)),
name: "Reload RustCast".to_string(),
name_lc: "refresh".to_string(),
},
App {
open_command: AppCommand::Display,
desc: RUSTCAST_DESC_NAME.to_string(),
icons: None,
icons: handle_from_icns(Path::new(
"/Applications/Rustcast.app/Contents/Resources/icon.icns",
)),
name: format!("Current RustCast Version: {app_version}"),
name_lc: "version".to_string(),
},
Expand All @@ -105,79 +114,67 @@ impl App {
}

/// This renders the app into an iced element, allowing it to be displayed in the search results
pub fn render<'a>(
&'a self,
theme: &'a crate::config::Theme,
pub fn render(
self,
theme: crate::config::Theme,
id_num: u32,
focussed_id: u32,
) -> impl Into<iced::Element<'a, Message>> {
let mut tile = Row::new().width(Fill).height(55);
) -> iced::Element<'static, Message> {
let focused = focussed_id == id_num;

// Title + subtitle (Raycast style)
let text_block = iced::widget::Column::new()
.spacing(2)
.push(
Text::new(self.name)
.font(theme.font())
.size(16)
.color(theme.text_color(1.0)),
)
.push(
Text::new(self.desc)
.font(theme.font())
.size(13)
.color(theme.text_color(0.55)),
);

let mut row = Row::new()
.align_y(Alignment::Center)
.width(Fill)
.spacing(10)
.height(50);

if theme.show_icons
&& let Some(icon) = &self.icons
{
tile = tile
.push(container(Viewer::new(icon).height(35).width(35)))
.align_y(Alignment::Center);
row = row.push(
container(Viewer::new(icon).height(40).width(40))
.width(40)
.height(40),
);
}
row = row.push(container(text_block).width(Fill));

tile = tile.push(
Button::new(
Text::new(&self.name)
.font(theme.font())
.height(Fill)
.width(Fill)
.color(theme.text_color(1.))
.align_y(Vertical::Center),
)
.on_press_maybe({
match self.open_command.clone() {
AppCommand::Function(func) => Some(Message::RunFunction(func)),
AppCommand::Message(msg) => Some(msg),
AppCommand::Display => None,
}
})
.style(|_, _| iced::widget::button::Style {
background: None,
text_color: theme.text_color(1.),
..Default::default()
})
.width(Fill)
.height(55),
);
let msg = match self.open_command.clone() {
AppCommand::Function(func) => Some(Message::RunFunction(func)),
AppCommand::Message(msg) => Some(msg),
AppCommand::Display => None,
};

tile = tile
.push(
container(
Text::new(&self.desc)
.font(theme.font())
.color(theme.text_color(0.4)),
)
.padding(12),
)
.width(Fill);
let theme_clone = theme.clone();

let (highlight_opacity, border_width) = if focussed_id == id_num {
(0.7, 0.55)
} else {
(0.5, 0.1)
};
let content = Button::new(row)
.on_press_maybe(msg)
.style(move |_, _| result_button_style(&theme_clone))
.width(Fill)
.padding(0)
.height(50);

container(tile)
container(content)
.id(format!("result-{}", id_num))
.style(move |_| iced::widget::container::Style {
text_color: Some(theme.text_color(1.)),
background: Some(Background::Color(theme.bg_color())),
border: iced::Border {
color: theme.text_color(highlight_opacity),
width: border_width,
radius: Radius::new(0),
},
..Default::default()
})
.max_height(55)
.padding(5)
.style(move |_| result_row_container_style(&theme, focused))
.padding(8)
.width(Fill)
.height(Fill)
.into()
}
}
18 changes: 8 additions & 10 deletions src/app/tile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,16 @@ impl AppIndex {
/// - Page ([`Page`]) the current page of the window (main or clipboard history)
#[derive(Clone)]
pub struct Tile {
theme: iced::Theme,
focus_id: u32,
query: String,
pub theme: iced::Theme,
pub focus_id: u32,
pub query: String,
query_lc: String,
results: Vec<App>,
options: AppIndex,
visible: bool,
focused: bool,
frontmost: Option<Retained<NSRunningApplication>>,
config: Config,
pub config: Config,
/// The opening hotkey
hotkey: HotKey,
clipboard_content: Vec<ClipBoardContentType>,
Expand Down Expand Up @@ -137,12 +137,10 @@ impl Tile {
/// - Window focus changes
pub fn subscription(&self) -> Subscription<Message> {
let keyboard = event::listen_with(|event, _, id| match event {
event::Event::Keyboard(keyboard::Event::KeyPressed { key, .. }) => match key {
keyboard::Key::Named(keyboard::key::Named::Escape) => {
Some(Message::EscKeyPressed(id))
}
_ => None,
},
event::Event::Keyboard(keyboard::Event::KeyPressed {
key: keyboard::Key::Named(keyboard::key::Named::Escape),
..
}) => Some(Message::EscKeyPressed(id)),
_ => None,
});
Subscription::batch([
Expand Down
89 changes: 30 additions & 59 deletions src/app/tile/elm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ use rayon::{
slice::ParallelSliceMut,
};

use crate::app::apps::AppCommand;
use crate::app::tile::AppIndex;
use crate::config::Theme;
use crate::styles::{contents_style, rustcast_text_input_style};
use crate::{
app::{Message, Page, apps::App, default_settings, tile::Tile},
config::Config,
Expand Down Expand Up @@ -93,8 +92,8 @@ pub fn view(tile: &Tile, wid: window::Id) -> Element<'_, Message> {
.on_submit(Message::OpenFocused)
.id("query")
.width(Fill)
.line_height(LineHeight::Relative(1.5))
.style(|_, _| text_input_style(&tile.config.theme))
.line_height(LineHeight::Relative(1.75))
.style(|_, status| rustcast_text_input_style(&tile.config.theme, status))
.padding(20);

let scrollbar_direction = if tile.config.theme.show_scroll_bar {
Expand All @@ -107,70 +106,42 @@ pub fn view(tile: &Tile, wid: window::Id) -> Element<'_, Message> {
} else {
Direction::Vertical(Scrollbar::hidden())
};
let results = match tile.page {
Page::Main => {
let mut search_results = Column::new();
for (i, result) in tile.results.iter().enumerate() {
search_results = search_results.push(result.render(
&tile.config.theme,
i as u32,
tile.focus_id,
));
}
search_results
}
Page::ClipboardHistory => {
let mut clipboard_history = Column::new();
for result in &tile.clipboard_content {
clipboard_history = clipboard_history
.push(result.render_clipboard_item(tile.config.theme.clone()));
}
clipboard_history
}

let results = if tile.page == Page::ClipboardHistory {
Column::from_iter(
tile.clipboard_content
.iter()
.enumerate()
.map(|(i, content)| {
content
.to_app()
.render(tile.config.theme.clone(), i as u32, tile.focus_id)
}),
)
} else {
Column::from_iter(tile.results.iter().enumerate().map(|(i, app)| {
app.clone()
.render(tile.config.theme.clone(), i as u32, tile.focus_id)
}))
};
let scrollable = Scrollable::with_direction(results, scrollbar_direction).id("results");
let contents = Column::new().push(title_input).push(scrollable);

container(contents)
.style(|_| iced::widget::container::Style {
background: None,
let scrollable = Scrollable::with_direction(results, scrollbar_direction).id("results");
let contents = container(Column::new().push(title_input).push(scrollable).spacing(0))
.style(|_| container::Style {
text_color: None,
background: None,
border: iced::Border {
color: tile.config.theme.text_color(1.),
color: Color::WHITE,
width: 1.,
radius: Radius::new(0),
radius: Radius::new(5),
},
..Default::default()
})
.padding(0)
.clip(true)
});

container(contents.clip(true))
.style(|_| contents_style(&tile.config.theme))
.into()
} else {
space().into()
}
}

fn text_input_style(theme: &Theme) -> iced::widget::text_input::Style {
text_input::Style {
background: iced::Background::Color(Color::TRANSPARENT),
border: iced::Border {
color: iced::Color {
r: 0.95,
g: 0.95,
b: 0.95,
a: 0.7,
},
width: 0.5,
radius: iced::border::Radius {
top_left: 0.,
top_right: 0.,
bottom_right: 0.,
bottom_left: 0.,
},
},
icon: theme.text_color(0.),
placeholder: theme.text_color(0.7),
value: theme.text_color(1.),
selection: theme.text_color(0.2),
}
}
Loading