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
Binary file added docs/lucide.ttf
Binary file not shown.
10 changes: 5 additions & 5 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Main logic for the app
use std::collections::HashMap;

use crate::app::apps::{App, AppCommand, ICNS_ICON};
use crate::app::apps::{App, AppCommand, AppIcon, ICNS_ICON};
use crate::commands::Function;
use crate::config::{Config, MainPage, Position, Shelly, ThemeMode};
use crate::debounce::DebouncePolicy;
Expand All @@ -17,10 +17,10 @@ pub mod tile;

use iced::window::{self, Id, Settings};
/// The default window width
pub const WINDOW_WIDTH: f32 = 500.;
pub const WINDOW_WIDTH: f32 = 550.;

/// The default window height
pub const DEFAULT_WINDOW_HEIGHT: f32 = 100.;
pub const DEFAULT_WINDOW_HEIGHT: f32 = 150.;

/// Maximum file search results returned by a single mdfind invocation.
pub const FILE_SEARCH_MAX_RESULTS: u32 = 400;
Expand Down Expand Up @@ -281,7 +281,7 @@ impl ToApps for HashMap<String, String> {
)),
search_name: key.to_owned(),
desc: "Switch Modes".to_string(),
icons: icons.clone(),
icons: AppIcon::from_handle(icons.clone()),
display_name,
}
})
Expand All @@ -292,7 +292,7 @@ impl ToApps for HashMap<String, String> {
ranking: 0,
open_command: AppCommand::Message(Message::SwitchMode("Default".to_string())),
desc: "Change mode".to_string(),
icons: icons.clone(),
icons: AppIcon::from_handle(icons.clone()),
display_name: "Default mode".to_string(),
search_name: "default".to_string(),
});
Expand Down
139 changes: 95 additions & 44 deletions src/app/apps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
use std::io::Cursor;

use iced::{
Alignment,
Alignment, Element,
Length::{self, Fill},
border::Radius,
widget::{
Button, Row, Text, container,
image::{Handle, Viewer},
space,
text::Wrapping,
},
};
Expand All @@ -18,7 +20,10 @@ use crate::{
app::{Message, Page, RUSTCAST_DESC_NAME},
clipboard::ClipBoardContentType,
commands::Function,
styles::{favourite_button_style, result_button_style, result_row_container_style},
styles::{
clipboard_icon, emoji_icon, favourite_button_style, filesearch_icon, info_icon, quit_icon,
refresh_icon, result_button_style, result_row_container_style, settings_icon,
},
utils::icns_data_to_handle,
};

Expand All @@ -44,11 +49,65 @@ pub struct App {
pub ranking: i32,
pub open_command: AppCommand,
pub desc: String,
pub icons: Option<iced::widget::image::Handle>,
pub icons: AppIcon,
pub display_name: String,
pub search_name: String,
}

#[derive(Debug, Clone)]
pub enum AppIcon {
IconFromFont(fn() -> Text<'static>),
ImageHandle(iced::widget::image::Handle),
None,
}

impl PartialEq for AppIcon {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::IconFromFont(_), Self::IconFromFont(_)) => true,
(Self::ImageHandle(l0), Self::ImageHandle(r0)) => l0 == r0,
(AppIcon::None, AppIcon::None) => true,
_ => false,
}
}
}

impl AppIcon {
pub fn render(&self) -> Element<'static, Message> {
match self {
Self::IconFromFont(icon_fn) => container(
icon_fn()
.center()
.size(20)
.height(Length::Fill)
.width(Length::Fill),
)
.style(|theme| container::Style {
background: None,
border: iced::Border {
color: theme.palette().text,
width: 0.,
radius: Radius::new(10),
},
..Default::default()
})
.height(30)
.width(30)
.into(),
Self::ImageHandle(handle) => Viewer::new(handle)
.height(30)
.width(30)
.scale_step(0.)
.into(),
Self::None => space().into(),
}
}

pub fn from_handle(handle: Option<Handle>) -> AppIcon {
handle.map(AppIcon::ImageHandle).unwrap_or(AppIcon::None)
}
}

impl PartialEq for App {
fn eq(&self, other: &Self) -> bool {
self.search_name == other.search_name
Expand All @@ -59,7 +118,7 @@ impl PartialEq for App {
}

impl App {
pub fn new(name: String, icon: Option<Handle>, desc: String, command: AppCommand) -> Self {
pub fn new(name: String, icon: AppIcon, desc: String, command: AppCommand) -> Self {
Self {
ranking: 0,
open_command: command,
Expand All @@ -75,7 +134,7 @@ impl App {
.filter(|x| x.unicode_version() < emojis::UnicodeVersion::new(17, 13))
.map(|x| App {
ranking: 0,
icons: None,
icons: AppIcon::None,
display_name: x.to_string(),
search_name: x.name().to_string(),
open_command: AppCommand::Function(Function::CopyToClipboard(
Expand All @@ -89,8 +148,6 @@ impl App {
pub fn basic_apps() -> Vec<App> {
let app_version = option_env!("APP_VERSION").unwrap_or("Unknown Version");

let icons = icns_data_to_handle(ICNS_ICON.to_vec());

let ferris_handle =
image::ImageReader::new(Cursor::new(include_bytes!("../../docs/ferris_rs.png")))
.with_guessed_format()
Expand All @@ -105,7 +162,7 @@ impl App {
open_command: AppCommand::Function(Function::OpenWebsite(
"https://ferris.rs".to_string(),
)),
icons: ferris_handle,
icons: AppIcon::from_handle(ferris_handle),
desc: "Easter Egg".to_string(),
display_name: "Ferris Plushies".to_string(),
search_name: "ferris.rs".to_string(),
Expand All @@ -114,63 +171,63 @@ impl App {
ranking: 0,
open_command: AppCommand::Function(Function::Quit),
desc: RUSTCAST_DESC_NAME.to_string(),
icons: icons.clone(),
icons: AppIcon::IconFromFont(quit_icon),
display_name: "Quit RustCast".to_string(),
search_name: "quit".to_string(),
},
App {
ranking: 0,
open_command: AppCommand::Function(Function::QuitAllApps),
desc: RUSTCAST_DESC_NAME.to_string(),
icons: icons.clone(),
icons: AppIcon::IconFromFont(quit_icon),
display_name: "Quit All Apps".to_string(),
search_name: "quit all apps".to_string(),
},
App {
ranking: 0,
open_command: AppCommand::Message(Message::OpenSettingsWindow),
desc: RUSTCAST_DESC_NAME.to_string(),
icons: icons.clone(),
icons: AppIcon::IconFromFont(settings_icon),
display_name: "Open RustCast Preferences".to_string(),
search_name: "settings".to_string(),
},
App {
ranking: 0,
open_command: AppCommand::Message(Message::SwitchToPage(Page::EmojiSearch)),
desc: RUSTCAST_DESC_NAME.to_string(),
icons: icons.clone(),
icons: AppIcon::IconFromFont(emoji_icon),
display_name: "Search for an Emoji".to_string(),
search_name: "emoji".to_string(),
},
App {
ranking: 0,
open_command: AppCommand::Message(Message::SwitchToPage(Page::ClipboardHistory)),
desc: RUSTCAST_DESC_NAME.to_string(),
icons: icons.clone(),
icons: AppIcon::IconFromFont(clipboard_icon),
display_name: "Clipboard History".to_string(),
search_name: "clipboard".to_string(),
},
App {
ranking: 0,
open_command: AppCommand::Message(Message::SwitchToPage(Page::FileSearch)),
desc: RUSTCAST_DESC_NAME.to_string(),
icons: icons.clone(),
icons: AppIcon::IconFromFont(filesearch_icon),
display_name: "Search for a file".to_string(),
search_name: "file search".to_string(),
},
App {
ranking: 0,
open_command: AppCommand::Message(Message::ReloadConfig),
desc: RUSTCAST_DESC_NAME.to_string(),
icons: icons.clone(),
icons: AppIcon::IconFromFont(refresh_icon),
display_name: "Reload RustCast".to_string(),
search_name: "refresh".to_string(),
},
App {
ranking: 0,
open_command: AppCommand::Display,
desc: RUSTCAST_DESC_NAME.to_string(),
icons: icons.clone(),
icons: AppIcon::IconFromFont(info_icon),
display_name: format!("Current RustCast Version: {app_version}"),
search_name: "version".to_string(),
},
Expand Down Expand Up @@ -204,7 +261,7 @@ impl App {
ranking: 0,
open_command: AppCommand::Function(Function::TileWindow(pos.clone())),
desc: "Window Tiling".to_string(),
icons: icons.clone(),
icons: AppIcon::from_handle(icons.clone()),
display_name: name.to_string(),
search_name: name.to_lowercase(),
})
Expand All @@ -222,46 +279,40 @@ impl App {
let focused = focussed_id == id_num;

// Title + subtitle (Raycast style)
let text_block = iced::widget::Column::new()
.spacing(2)
.push(
Text::new(self.display_name)
.font(theme.font())
.size(16)
.wrapping(Wrapping::None)
.color(theme.text_color(1.0)),
)
.push(
Text::new(self.desc)
.font(theme.font())
.size(13)
.color(theme.text_color(0.55)),
);
let text_block = Text::new(self.display_name)
.font(theme.font())
.size(16)
.wrapping(Wrapping::None)
.color(theme.text_color(1.0));
let subtitle_block = container(
Text::new(self.desc)
.font(theme.font())
.size(13)
.width(Length::Fill)
.align_x(Alignment::End)
.color(theme.text_color(0.55)),
);

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

if theme.show_icons
&& let Some(icon) = &self.icons
{
row = row.push(
container(Viewer::new(icon).height(40).width(40))
.width(40)
.height(40),
);
if theme.show_icons {
row = row.push(container(self.icons.render()).width(30).height(30));
}
row = row.push(container(text_block).width(Fill));
row = row
.push(container(text_block).width(Fill))
.push(subtitle_block);

let name = self.search_name.clone();
let theme_clone = theme.clone();
let is_favourite = self.ranking == -1;
row = row.push(
Button::new(Text::new("♥️").width(Length::Fill).align_x(Alignment::End))
.on_press_with(move || Message::ToggleFavouriteApp(name.clone()))
.width(Length::Fill)
.width(20)
.style(move |_, status| favourite_button_style(&theme_clone, status, is_favourite)),
);

Expand All @@ -278,7 +329,7 @@ impl App {
.style(move |_, _| result_button_style(&theme_clone))
.width(Fill)
.padding(0)
.height(50);
.height(40);

container(content)
.id(format!("result-{}", id_num))
Expand Down
10 changes: 5 additions & 5 deletions src/app/tile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use iced::futures::SinkExt;
use iced::futures::channel::mpsc::{Sender, channel};
use iced::keyboard::Modifiers;
use iced::{
Subscription, Theme, futures,
Subscription, futures,
keyboard::{self, key::Named},
stream,
};
Expand Down Expand Up @@ -232,8 +232,8 @@ impl Hotkeys {

impl Tile {
/// This returns the theme of the window
pub fn theme(&self, _: window::Id) -> Option<Theme> {
Some(self.theme.clone())
pub fn theme(&self, _: window::Id) -> Option<iced::Theme> {
Some(self.config.theme.clone().into())
}

/// This handles the subscriptions of the window
Expand Down Expand Up @@ -606,7 +606,7 @@ fn handle_file_search() -> impl futures::Stream<Item = Message> {
#[allow(clippy::items_after_test_module)]
mod tests {
use super::*;
use crate::app::apps::{App, AppCommand};
use crate::app::apps::{App, AppCommand, AppIcon};
use crate::commands::Function;
use iced::futures::StreamExt;
use tokio::io::{AsyncWriteExt, duplex};
Expand All @@ -618,7 +618,7 @@ mod tests {
"/Applications/{name}.app"
))),
desc: "Application".to_string(),
icons: None,
icons: AppIcon::None,
display_name: name.to_string(),
search_name: name.to_lowercase(),
}
Expand Down
5 changes: 3 additions & 2 deletions src/app/tile/elm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ pub fn view(tile: &Tile, wid: window::Id) -> Element<'_, Message> {
Page::ClipboardHistory => 385,
// Height of each emoji is EMOJI_HEIGHT + 20 for padding
Page::EmojiSearch => std::cmp::min(tile.results.len().div_ceil(6) * 90, 290),
_ => std::cmp::min(tile.results.len() * 60, 290),
_ => std::cmp::min(tile.results.len() * 56, 290),
};

let theme = tile.config.theme.clone();
Expand Down Expand Up @@ -216,14 +216,15 @@ pub fn view(tile: &Tile, wid: window::Id) -> Element<'_, Message> {
text_color: None,
background: None,
border: iced::Border {
color: Color::TRANSPARENT,
color: Color::WHITE,
width: 0.,
radius: Radius::new(15),
},
..Default::default()
});

container(contents)
.padding(10)
.style(|_| contents_style(&tile.config.theme))
.into()
} else {
Expand Down
Loading
Loading