diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 8d3bb59..a0a3225 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -42,7 +42,7 @@ pub struct UpdateState { uad_list: UadListState, } -#[derive(Default, Clone)] +#[derive(Default)] pub struct UadGui { view: View, apps_view: AppsView, diff --git a/src/gui/style.rs b/src/gui/style.rs index d5b4579..22f013c 100644 --- a/src/gui/style.rs +++ b/src/gui/style.rs @@ -1,5 +1,6 @@ use crate::core::theme::Theme; use iced::overlay::menu; +use iced::widget::text_editor; use iced::widget::{ button, checkbox, container, pick_list, radio, rule, scrollable, text, text_input, }; @@ -565,6 +566,50 @@ impl radio::StyleSheet for Theme { } } +impl text_editor::StyleSheet for Theme { + type Style = (); + + fn active(&self, _style: &Self::Style) -> text_editor::Appearance { + let p = self.palette(); + text_editor::Appearance { + background: Background::Color(p.base.foreground), + border: Border { + width: 0.0, + radius: 0.0.into(), + color: Color::TRANSPARENT, + }, + } + } + + fn focused(&self, style: &Self::Style) -> text_editor::Appearance { + self.active(style) + } + + fn placeholder_color(&self, _style: &Self::Style) -> Color { + self.palette().normal.surface + } + + fn value_color(&self, _style: &Self::Style) -> Color { + self.palette().bright.surface + } + + fn disabled_color(&self, _style: &Self::Style) -> Color { + self.palette().normal.surface + } + + fn selection_color(&self, _style: &Self::Style) -> Color { + let p = self.palette(); + Color { + a: 0.3, + ..p.normal.primary + } + } + + fn disabled(&self, style: &Self::Style) -> text_editor::Appearance { + self.active(style) + } +} + #[derive(Default, Clone, Copy)] pub enum Rule { #[default] diff --git a/src/gui/views/list.rs b/src/gui/views/list.rs index 986c764..5b00dfa 100644 --- a/src/gui/views/list.rs +++ b/src/gui/views/list.rs @@ -16,7 +16,7 @@ use crate::gui::widgets::package_row::{Message as RowMessage, PackageRow}; use crate::gui::widgets::text; use iced::widget::{ Column, Space, button, checkbox, column, container, horizontal_space, pick_list, radio, row, - scrollable, text_input, tooltip, vertical_rule, + scrollable, text_editor, text_input, tooltip, vertical_rule, }; use iced::{Alignment, Command, Element, Length, Renderer, alignment}; @@ -39,7 +39,7 @@ pub enum LoadingState { FailedToUpdate, } -#[derive(Default, Debug, Clone)] +#[derive(Default, Debug)] #[allow(clippy::struct_excessive_bools, reason = "Not a state-machine")] pub struct List { pub loading_state: LoadingState, @@ -57,6 +57,7 @@ pub struct List { all_selected: bool, pub input_value: String, description: String, + description_content: text_editor::Content, selection_modal: bool, error_modal: Option, export_modal: bool, @@ -89,6 +90,7 @@ pub enum Message { GoToUrl(PathBuf), ExportSelection, SelectionExported(Result), + DescriptionEdit(text_editor::Action), } pub struct SummaryEntry { @@ -280,6 +282,8 @@ impl List { } RowMessage::PackagePressed => { self.description = package.clone().description; + self.description_content = + text_editor::Content::with_text(&package.description); package.current = true; if self.current_package_index != i_package { self.phone_packages[i_user][self.current_package_index].current = false; @@ -352,6 +356,18 @@ impl List { Command::none() } Message::Nothing => Command::none(), + Message::DescriptionEdit(action) => { + match action { + text_editor::Action::Edit(_) => { + // Do nothing - ignore all editing operations + } + // Allow all other actions (movement, selection, clicking, scrolling, etc.) + _ => { + self.description_content.perform(action); + } + } + Command::none() + } } } @@ -487,8 +503,9 @@ impl List { .height(Length::FillPortion(6)) .style(style::Scrollable::Packages); - let description_scroll = scrollable(text(&self.description).width(Length::Fill)) - .style(style::Scrollable::Description); + let description_scroll = + scrollable(text_editor(&self.description_content).on_action(Message::DescriptionEdit)) + .style(style::Scrollable::Description); let description_panel = container(description_scroll) .padding(6)