use super::{AppState, Model};
use crate::components::common::ComponentId;
use crate::components::confirmation_popup::ConfirmationPopup;
use crate::components::error_popup::ErrorPopup;
use crate::components::global_key_watcher::GlobalKeyWatcher;
use crate::components::loading_indicator::LoadingIndicator;
use crate::components::number_input_popup::NumberInputPopup;
use crate::components::page_size_popup::PageSizePopup;
use crate::components::password_popup::PasswordPopup;
use crate::components::state::ComponentStateMount;
use crate::components::success_popup::SuccessPopup;
use crate::components::theme_picker::ThemePicker;
use crate::error::{AppError, AppResult};
use tuirealm::terminal::TerminalAdapter;
use tuirealm::{Sub, SubClause, SubEventClause};
impl<T> Model<T>
where
T: TerminalAdapter,
{
pub fn mount_loading_indicator(&mut self, message: &str) -> AppResult<()> {
log::debug!("Mounting loading indicator with message: {message}");
if self.app.mounted(&ComponentId::LoadingIndicator) {
if let Err(e) = self.app.umount(&ComponentId::LoadingIndicator) {
log::error!("Failed to unmount loading indicator: {e}");
}
}
self.app.mount_with_state(
ComponentId::LoadingIndicator,
LoadingIndicator::new(message, true),
vec![
Sub::new(SubEventClause::Tick, SubClause::Always),
Sub::new(SubEventClause::Any, SubClause::Always),
],
)?;
self.app
.active(&ComponentId::LoadingIndicator)
.map_err(|e| AppError::Component(e.to_string()))?;
self.set_redraw(true);
log::debug!("Loading indicator mounted successfully");
Ok(())
}
pub fn mount_error_popup(&mut self, error: &AppError) -> AppResult<()> {
log::error!("Displaying error popup: {error}");
self.app.remount_with_state(
ComponentId::ErrorPopup,
ErrorPopup::new(error),
Vec::default(),
)?;
self.app
.active(&ComponentId::ErrorPopup)
.map_err(|e| AppError::Component(e.to_string()))?;
self.set_redraw(true);
Ok(())
}
pub fn unmount_error_popup(&mut self) -> AppResult<()> {
self.app
.umount(&ComponentId::ErrorPopup)
.map_err(|e| AppError::Component(e.to_string()))?;
self.activate_component_for_current_state()?;
self.set_redraw(true);
Ok(())
}
pub fn mount_success_popup(&mut self, message: &str) -> AppResult<()> {
log::info!("Displaying success popup: {message}");
self.app.remount_with_state(
ComponentId::SuccessPopup,
SuccessPopup::new(message),
Vec::default(),
)?;
if !self.app.mounted(&ComponentId::AuthPopup) {
self.app
.active(&ComponentId::SuccessPopup)
.map_err(|e| AppError::Component(e.to_string()))?;
}
self.set_redraw(true);
Ok(())
}
pub fn unmount_success_popup(&mut self) -> AppResult<()> {
self.app
.umount(&ComponentId::SuccessPopup)
.map_err(|e| AppError::Component(e.to_string()))?;
self.activate_component_for_current_state()?;
self.set_redraw(true);
Ok(())
}
pub fn mount_confirmation_popup(&mut self, title: &str, message: &str) -> AppResult<()> {
self.app.remount_with_state(
ComponentId::ConfirmationPopup,
ConfirmationPopup::new(title, message),
Vec::default(),
)?;
self.app
.active(&ComponentId::ConfirmationPopup)
.map_err(|e| AppError::Component(e.to_string()))?;
Ok(())
}
pub fn mount_number_input_popup(
&mut self,
title: String,
message: String,
min_value: usize,
max_value: usize,
) -> AppResult<()> {
self.app.remount_with_state(
ComponentId::NumberInputPopup,
NumberInputPopup::new(title, message, min_value, max_value),
Vec::default(),
)?;
self.app
.active(&ComponentId::NumberInputPopup)
.map_err(|e| AppError::Component(e.to_string()))?;
Ok(())
}
pub fn mount_page_size_popup(&mut self) -> AppResult<()> {
self.app.remount_with_state(
ComponentId::PageSizePopup,
PageSizePopup::new(),
Vec::default(),
)?;
self.app
.active(&ComponentId::PageSizePopup)
.map_err(|e| AppError::Component(e.to_string()))?;
Ok(())
}
pub fn unmount_confirmation_popup(&mut self) -> AppResult<()> {
self.app
.umount(&ComponentId::ConfirmationPopup)
.map_err(|e| AppError::Component(e.to_string()))?;
self.activate_component_for_current_state()?;
self.set_redraw(true);
Ok(())
}
pub fn unmount_number_input_popup(&mut self) -> AppResult<()> {
self.app
.umount(&ComponentId::NumberInputPopup)
.map_err(|e| AppError::Component(e.to_string()))?;
self.activate_component_for_current_state()?;
self.set_redraw(true);
Ok(())
}
pub fn unmount_page_size_popup(&mut self) -> AppResult<()> {
self.app
.umount(&ComponentId::PageSizePopup)
.map_err(|e| AppError::Component(e.to_string()))?;
self.activate_component_for_current_state()?;
self.set_redraw(true);
Ok(())
}
pub fn mount_theme_picker(&mut self) -> AppResult<()> {
self.state_manager.previous_state = Some(self.state_manager.app_state.clone());
self.app.remount_with_state(
ComponentId::ThemePicker,
ThemePicker::new(),
Vec::default(),
)?;
self.app
.active(&ComponentId::ThemePicker)
.map_err(|e| AppError::Component(e.to_string()))?;
self.state_manager.app_state = AppState::ThemePicker;
self.set_redraw(true);
Ok(())
}
pub fn unmount_theme_picker(&mut self) -> AppResult<()> {
self.app
.umount(&ComponentId::ThemePicker)
.map_err(|e| AppError::Component(e.to_string()))?;
if let Some(prev_state) = self.state_manager.previous_state.take() {
self.state_manager.app_state = prev_state;
} else {
self.state_manager.app_state = AppState::NamespacePicker;
}
self.activate_component_for_current_state()?;
self.set_redraw(true);
Ok(())
}
pub fn mount_config_screen(&mut self) -> AppResult<()> {
use crate::components::config_screen::ConfigScreen;
if self.app.mounted(&ComponentId::ConfigScreen)
&& self.state_manager.app_state == AppState::ConfigScreen
{
log::debug!("ConfigScreen already mounted and active, skipping");
return Ok(());
}
self.state_manager.previous_state = Some(self.state_manager.app_state.clone());
self.app.remount_with_state(
ComponentId::ConfigScreen,
ConfigScreen::new(),
vec![Sub::new(SubEventClause::Any, SubClause::Always)],
)?;
self.app
.active(&ComponentId::ConfigScreen)
.map_err(|e| AppError::Component(e.to_string()))?;
self.state_manager.app_state = AppState::ConfigScreen;
self.set_redraw(true);
Ok(())
}
pub fn unmount_config_screen(&mut self) -> AppResult<()> {
if !self.app.mounted(&ComponentId::ConfigScreen) {
log::debug!("ConfigScreen not mounted, skipping unmount");
} else {
self.app
.umount(&ComponentId::ConfigScreen)
.map_err(|e| AppError::Component(e.to_string()))?;
}
if let Some(prev_state) = self.state_manager.previous_state.take() {
self.state_manager.app_state = prev_state;
} else {
self.state_manager.app_state = AppState::NamespacePicker;
}
self.activate_component_for_current_state()?;
self.set_redraw(true);
Ok(())
}
pub fn mount_password_popup(&mut self, error_message: Option<String>) -> AppResult<()> {
self.mount_password_popup_with_methods(error_message, None)
}
pub fn mount_password_popup_with_methods(
&mut self,
error_message: Option<String>,
encrypted_methods: Option<Vec<String>>,
) -> AppResult<()> {
use crate::config;
self.state_manager.previous_state = Some(self.state_manager.app_state.clone());
let methods = encrypted_methods.unwrap_or_else(|| {
let config = config::get_config_or_panic();
config.get_encrypted_auth_methods()
});
let popup = match (error_message, methods.is_empty()) {
(Some(error), false) => PasswordPopup::with_error_and_methods(error, methods),
(Some(error), true) => PasswordPopup::with_error(error),
(None, false) => PasswordPopup::with_encrypted_methods(methods),
(None, true) => PasswordPopup::new(),
};
self.app.remount_with_state(
ComponentId::PasswordPopup,
popup,
vec![Sub::new(SubEventClause::Any, SubClause::Always)],
)?;
self.app
.active(&ComponentId::PasswordPopup)
.map_err(|e| AppError::Component(e.to_string()))?;
self.state_manager.app_state = AppState::PasswordPopup;
self.set_redraw(true);
self.set_editing_message(true);
if let Err(e) = self.update_global_key_watcher_editing_state() {
self.error_reporter.report_key_watcher_error(e);
}
Ok(())
}
pub fn unmount_password_popup(&mut self) -> AppResult<()> {
if !self.app.mounted(&ComponentId::PasswordPopup) {
log::debug!("PasswordPopup not mounted, skipping unmount");
} else {
self.app
.umount(&ComponentId::PasswordPopup)
.map_err(|e| AppError::Component(e.to_string()))?;
}
if let Some(prev_state) = self.state_manager.previous_state.take() {
self.state_manager.app_state = prev_state;
} else {
self.state_manager.app_state = AppState::NamespacePicker;
}
self.activate_component_for_current_state()?;
self.set_redraw(true);
self.set_editing_message(false);
if let Err(e) = self.update_global_key_watcher_editing_state() {
self.error_reporter.report_key_watcher_error(e);
}
Ok(())
}
pub fn update_global_key_watcher_editing_state(&mut self) -> AppResult<()> {
self.app
.remount(
ComponentId::GlobalKeyWatcher,
Box::new(GlobalKeyWatcher::new(self.state_manager.is_editing_message)),
vec![Sub::new(SubEventClause::Any, SubClause::Always)],
)
.map_err(|e| AppError::Component(e.to_string()))?;
Ok(())
}
fn activate_component_for_current_state(&mut self) -> AppResult<()> {
if self.app.mounted(&ComponentId::AuthPopup) {
self.app
.active(&ComponentId::AuthPopup)
.map_err(|e| AppError::Component(e.to_string()))?;
return Ok(());
}
match self.state_manager.app_state {
AppState::NamespacePicker => {
self.app
.active(&ComponentId::NamespacePicker)
.map_err(|e| AppError::Component(e.to_string()))?;
}
AppState::QueuePicker => {
self.app
.active(&ComponentId::QueuePicker)
.map_err(|e| AppError::Component(e.to_string()))?;
}
AppState::MessagePicker => {
self.app
.active(&ComponentId::Messages)
.map_err(|e| AppError::Component(e.to_string()))?;
}
AppState::MessageDetails => {
self.app
.active(&ComponentId::MessageDetails)
.map_err(|e| AppError::Component(e.to_string()))?;
}
AppState::Loading => {
}
AppState::HelpScreen => {
self.app
.active(&ComponentId::HelpScreen)
.map_err(|e| AppError::Component(e.to_string()))?;
}
AppState::ThemePicker => {
self.state_manager.app_state = AppState::NamespacePicker;
self.app
.active(&ComponentId::NamespacePicker)
.map_err(|e| AppError::Component(e.to_string()))?;
}
AppState::ConfigScreen => {
self.app
.active(&ComponentId::ConfigScreen)
.map_err(|e| AppError::Component(e.to_string()))?;
}
AppState::PasswordPopup => {
self.app
.active(&ComponentId::PasswordPopup)
.map_err(|e| AppError::Component(e.to_string()))?;
}
AppState::AzureDiscovery => {
}
}
Ok(())
}
}