Skip to content

Commit

Permalink
wip - profile selection minor ui improvements I
Browse files Browse the repository at this point in the history
  • Loading branch information
aprxi committed Aug 18, 2024
1 parent 6e159ee commit 60a5cc3
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 58 deletions.
155 changes: 106 additions & 49 deletions lumni/src/apps/builtin/llm/prompt/src/tui/modals/profiles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,41 +73,46 @@ impl ProfileEditModal {
) -> Result<WindowEvent, ApplicationError> {
match (self.ui_state.edit_mode, key_code) {
(EditMode::NotEditing, KeyCode::Up) => {
self.profile_list.move_selection_up()
self.profile_list.move_selection_up();
self.load_profile_or_clear().await?;
}
(EditMode::NotEditing, KeyCode::Down) => {
self.profile_list.move_selection_down()
self.profile_list.move_selection_down();
self.load_profile_or_clear().await?;
}
(EditMode::NotEditing, KeyCode::Enter) => {
if self.profile_list.is_new_profile_selected() {
self.ui_state.set_edit_mode(EditMode::CreatingNewProfile);
self.ui_state.set_focus(Focus::NewProfileType);
self.new_profile_creator.selected_type = 0;
self.start_new_profile_creation();
} else {
self.ui_state.set_focus(Focus::SettingsList);
self.load_profile().await?;
}
}
(EditMode::NotEditing, KeyCode::Tab) => {
if !self.profile_list.is_new_profile_selected() {
self.ui_state.set_focus(Focus::SettingsList);
}
}
(EditMode::NotEditing, KeyCode::Char('r') | KeyCode::Char('R')) => {
if !self.profile_list.is_new_profile_selected() {
self.ui_state.set_edit_mode(EditMode::RenamingProfile);
self.ui_state.set_focus(Focus::RenamingProfile);
// Use a temporary buffer for renaming
self.new_profile_name =
Some(self.profile_list.start_renaming());
}
}
(EditMode::NotEditing, KeyCode::Char('D')) => {
if !self.profile_list.is_new_profile_selected() {
self.set_default_profile().await?;
}
}
(EditMode::NotEditing, KeyCode::Char('X')) => {
if !self.profile_list.is_new_profile_selected() {
self.profile_list
.delete_profile(&mut self.db_handler)
.await?;
self.load_profile().await?;
self.load_profile_or_clear().await?;
}
}
(EditMode::NotEditing, KeyCode::Tab) => {
self.ui_state.set_focus(Focus::SettingsList);
}
(EditMode::RenamingProfile, KeyCode::Enter) => {
if let Some(new_name) = self.new_profile_name.take() {
self.profile_list
Expand All @@ -132,6 +137,10 @@ impl ProfileEditModal {
self.ui_state.set_edit_mode(EditMode::NotEditing);
self.ui_state.set_focus(Focus::ProfileList);
}
(EditMode::CreatingNewProfile, KeyCode::Esc) => {
self.cancel_new_profile_creation();
self.load_profile_or_clear().await?;
}
(EditMode::NotEditing, KeyCode::Char('q') | KeyCode::Esc) => {
return Ok(WindowEvent::PromptWindow(None));
}
Expand All @@ -141,58 +150,23 @@ impl ProfileEditModal {
Ok(WindowEvent::Modal(ModalAction::WaitForKeyEvent))
}

fn render_activity_indicator(&mut self, frame: &mut Frame, area: Rect) {
const SPINNER: &[char] =
&['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];

let spinner_char = SPINNER[self.new_profile_creator.spinner_state];
self.new_profile_creator.spinner_state =
(self.new_profile_creator.spinner_state + 1) % SPINNER.len();

let elapsed = self
.new_profile_creator
.task_start_time
.map(|start| start.elapsed().as_secs())
.unwrap_or(0);
let content = format!(
"{} Creating profile... ({} seconds)",
spinner_char, elapsed
);

let paragraph = Paragraph::new(content)
.style(Style::default().fg(Color::Cyan))
.alignment(Alignment::Center)
.block(Block::default().borders(Borders::ALL));

frame.render_widget(paragraph, area);
}

async fn load_profile(&mut self) -> Result<(), ApplicationError> {
if let Some(profile) = self.profile_list.get_selected_profile() {
self.settings_editor
.load_settings(profile, &mut self.db_handler)
.await?;
}
Ok(())
}

async fn handle_settings_list_input(
&mut self,
key_code: KeyCode,
) -> Result<WindowEvent, ApplicationError> {
match (self.ui_state.edit_mode, key_code) {
(EditMode::NotEditing, KeyCode::Up) => {
self.settings_editor.move_selection_up()
self.settings_editor.move_selection_up();
}
(EditMode::NotEditing, KeyCode::Down) => {
self.settings_editor.move_selection_down()
self.settings_editor.move_selection_down();
}
(EditMode::NotEditing, KeyCode::Enter) => {
if self.settings_editor.start_editing().is_some() {
self.ui_state.set_edit_mode(EditMode::EditingValue);
}
}
(EditMode::NotEditing, KeyCode::Tab) => {
(EditMode::NotEditing, KeyCode::Tab | KeyCode::Left) => {
self.ui_state.set_focus(Focus::ProfileList);
}
(EditMode::NotEditing, KeyCode::Char('s') | KeyCode::Char('S')) => {
Expand Down Expand Up @@ -296,6 +270,89 @@ impl ProfileEditModal {
Ok(WindowEvent::Modal(ModalAction::WaitForKeyEvent))
}

async fn update_selected_profile(
&mut self,
) -> Result<(), ApplicationError> {
if self.profile_list.is_new_profile_selected() {
self.ui_state.set_edit_mode(EditMode::CreatingNewProfile);
self.ui_state.set_focus(Focus::NewProfileType);
self.new_profile_creator.selected_type = 0;
self.settings_editor.clear();
} else {
self.ui_state.set_focus(Focus::SettingsList);
self.load_profile().await?;
}
Ok(())
}

async fn set_default_profile(&mut self) -> Result<(), ApplicationError> {
let selected_profile =
self.profile_list.get_selected_profile().map(String::from);
if let Some(profile) = selected_profile {
self.db_handler.set_default_profile(&profile).await?;
self.profile_list.mark_as_default(&profile);
}
Ok(())
}

fn start_new_profile_creation(&mut self) {
self.ui_state.set_edit_mode(EditMode::CreatingNewProfile);
self.ui_state.set_focus(Focus::NewProfileType);
self.new_profile_creator.selected_type = 0;
self.settings_editor.clear();
}

fn cancel_new_profile_creation(&mut self) {
self.ui_state.set_edit_mode(EditMode::NotEditing);
self.ui_state.set_focus(Focus::ProfileList);
self.profile_list.reset_selection();
self.settings_editor.clear();
}

async fn load_profile_or_clear(&mut self) -> Result<(), ApplicationError> {
if self.profile_list.is_new_profile_selected() {
self.settings_editor.clear();
Ok(())
} else {
self.load_profile().await
}
}

fn render_activity_indicator(&mut self, frame: &mut Frame, area: Rect) {
const SPINNER: &[char] =
&['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];

let spinner_char = SPINNER[self.new_profile_creator.spinner_state];
self.new_profile_creator.spinner_state =
(self.new_profile_creator.spinner_state + 1) % SPINNER.len();

let elapsed = self
.new_profile_creator
.task_start_time
.map(|start| start.elapsed().as_secs())
.unwrap_or(0);
let content = format!(
"{} Creating profile... ({} seconds)",
spinner_char, elapsed
);

let paragraph = Paragraph::new(content)
.style(Style::default().fg(Color::Cyan))
.alignment(Alignment::Center)
.block(Block::default().borders(Borders::ALL));

frame.render_widget(paragraph, area);
}

async fn load_profile(&mut self) -> Result<(), ApplicationError> {
if let Some(profile) = self.profile_list.get_selected_profile() {
self.settings_editor
.load_settings(profile, &mut self.db_handler)
.await?;
}
Ok(())
}

async fn handle_new_profile_type_input(
&mut self,
key_code: KeyCode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ use super::*;
pub struct ProfileList {
profiles: Vec<String>,
selected_index: usize,
default_profile: Option<String>,
}

impl ProfileList {
pub fn new(profiles: Vec<String>) -> Self {
ProfileList {
profiles,
selected_index: 0,
default_profile: None,
}
}

Expand All @@ -21,6 +23,18 @@ impl ProfileList {
self.profiles.get(self.selected_index).map(|s| s.as_str())
}

pub fn reset_selection(&mut self) {
if !self.profiles.is_empty() {
self.selected_index = self.profiles.len() - 1;
} else {
self.selected_index = 0;
}
}

pub fn is_new_profile_selected(&self) -> bool {
self.selected_index == self.profiles.len()
}

pub fn move_selection_up(&mut self) {
if self.selected_index > 0 {
self.selected_index -= 1;
Expand Down Expand Up @@ -68,10 +82,6 @@ impl ProfileList {
.unwrap_or_default()
}

pub fn get_profiles(&self) -> &[String] {
&self.profiles
}

pub fn add_profile(&mut self, name: String) {
self.profiles.push(name);
self.selected_index = self.profiles.len() - 1;
Expand All @@ -81,11 +91,24 @@ impl ProfileList {
self.selected_index
}

pub fn is_new_profile_selected(&self) -> bool {
self.selected_index == self.profiles.len()
}

pub fn total_items(&self) -> usize {
self.profiles.len() + 1 // +1 for "New Profile" option
}

pub fn mark_as_default(&mut self, profile: &str) {
self.default_profile = Some(profile.to_string());
}

pub fn get_profiles(&self) -> Vec<String> {
self.profiles
.iter()
.map(|p| {
if Some(p) == self.default_profile.as_ref() {
format!("* {}", p) // Prepend an asterisk to mark the default profile
} else {
p.clone()
}
})
.collect()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ impl SettingsEditor {
}
}

pub fn clear(&mut self) {
self.settings = JsonValue::Object(serde_json::Map::new());
self.current_field = 0;
self.edit_buffer.clear();
self.new_key_buffer.clear();
self.is_new_value_secure = false;
self.show_secure = false;
}

pub fn get_settings(&self) -> &JsonValue {
&self.settings
}
Expand All @@ -32,7 +41,8 @@ impl SettingsEditor {
}

pub fn move_selection_down(&mut self) {
if self.current_field < self.settings.as_object().unwrap().len() - 1 {
let settings_len = self.settings.as_object().map_or(0, |obj| obj.len());
if settings_len > 0 && self.current_field < settings_len - 1 {
self.current_field += 1;
}
}
Expand Down

0 comments on commit 60a5cc3

Please sign in to comment.