use std::sync::Arc;
use tokio::sync::Mutex;
use crate::config::{AppConfig, ColorScheme};
use crate::core::RepoInfo;
pub struct AppState {
pub repos: Arc<Mutex<Vec<RepoInfo>>>, pub selected_index: Arc<Mutex<usize>>, pub detail_view: Arc<Mutex<bool>>, pub config: Arc<AppConfig>, pub colors: ColorScheme, }
#[derive(Clone)]
pub struct RenderSnapshot {
pub repos: Vec<RepoInfo>,
pub selected_index: usize,
pub is_detail_view: bool,
}
impl AppState {
pub fn new(config: AppConfig) -> Self {
let colors = config.ui.theme.colors();
Self {
repos: Arc::new(Mutex::new(Vec::new())),
selected_index: Arc::new(Mutex::new(0)),
detail_view: Arc::new(Mutex::new(false)),
config: Arc::new(config),
colors,
}
}
pub async fn is_repos_empty(&self) -> bool {
let repos_lock = self.repos.lock().await;
repos_lock.is_empty()
}
pub async fn move_selection_up(&self) {
let mut selected = self.selected_index.lock().await;
if *selected > 0 {
*selected -= 1;
}
}
pub async fn move_selection_down(&self) {
let mut selected = self.selected_index.lock().await;
let repos = self.repos.lock().await;
*selected = (*selected + 1).min(repos.len().saturating_sub(1));
}
pub async fn is_detail_view(&self) -> bool {
*self.detail_view.lock().await
}
pub async fn set_detail_view(&self, enabled: bool) {
let mut detail = self.detail_view.lock().await;
*detail = enabled;
}
pub fn get_render_snapshot(&self) -> RenderSnapshot {
RenderSnapshot {
repos: self
.repos
.try_lock()
.ok()
.map(|r| r.clone())
.unwrap_or_default(),
selected_index: self
.selected_index
.try_lock()
.ok()
.map(|s| *s)
.unwrap_or_default(),
is_detail_view: self
.detail_view
.try_lock()
.ok()
.map(|d| *d)
.unwrap_or_default(),
}
}
pub async fn get_selected_repo_path(&self) -> Option<std::path::PathBuf> {
let repos = self.repos.lock().await;
let selected = self.selected_index.lock().await;
repos.get(*selected).map(|repo| repo.basic.path.clone())
}
}