Implement Phase 1: Foundation and cache system
- Add Cargo project with TUI and async dependencies - Implement cache-only architecture for low bandwidth operation - Add file scanner with media type detection - Create two-panel TUI layout (file tree and status) - Add config file support for scan path management - Implement XDG-compliant cache and config directories - Add Gitea CI/CD workflow for automated releases
This commit is contained in:
92
src/state/mod.rs
Normal file
92
src/state/mod.rs
Normal file
@@ -0,0 +1,92 @@
|
||||
use crate::cache::{Cache, FileTreeNode};
|
||||
use crate::config::Config;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PlayerState {
|
||||
Stopped,
|
||||
Playing,
|
||||
Paused,
|
||||
}
|
||||
|
||||
pub struct AppState {
|
||||
pub cache: Cache,
|
||||
pub config: Config,
|
||||
pub selected_index: usize,
|
||||
pub scroll_offset: usize,
|
||||
pub player_state: PlayerState,
|
||||
pub current_file: Option<PathBuf>,
|
||||
pub current_position: f64,
|
||||
pub current_duration: f64,
|
||||
pub volume: i64,
|
||||
pub should_quit: bool,
|
||||
pub flattened_items: Vec<FlattenedItem>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FlattenedItem {
|
||||
pub node: FileTreeNode,
|
||||
pub depth: usize,
|
||||
pub is_expanded: bool,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub fn new(cache: Cache, config: Config) -> Self {
|
||||
let flattened_items = flatten_tree(&cache.file_tree, 0);
|
||||
|
||||
Self {
|
||||
cache,
|
||||
config,
|
||||
selected_index: 0,
|
||||
scroll_offset: 0,
|
||||
player_state: PlayerState::Stopped,
|
||||
current_file: None,
|
||||
current_position: 0.0,
|
||||
current_duration: 0.0,
|
||||
volume: 100,
|
||||
should_quit: false,
|
||||
flattened_items,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn move_selection_up(&mut self) {
|
||||
if self.selected_index > 0 {
|
||||
self.selected_index -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn move_selection_down(&mut self) {
|
||||
if self.selected_index < self.flattened_items.len().saturating_sub(1) {
|
||||
self.selected_index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_selected_item(&self) -> Option<&FlattenedItem> {
|
||||
self.flattened_items.get(self.selected_index)
|
||||
}
|
||||
|
||||
pub fn refresh_flattened_items(&mut self) {
|
||||
self.flattened_items = flatten_tree(&self.cache.file_tree, 0);
|
||||
if self.selected_index >= self.flattened_items.len() {
|
||||
self.selected_index = self.flattened_items.len().saturating_sub(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flatten_tree(nodes: &[FileTreeNode], depth: usize) -> Vec<FlattenedItem> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
for node in nodes {
|
||||
result.push(FlattenedItem {
|
||||
node: node.clone(),
|
||||
depth,
|
||||
is_expanded: true, // For now, all directories are expanded
|
||||
});
|
||||
|
||||
if node.is_dir && !node.children.is_empty() {
|
||||
result.extend(flatten_tree(&node.children, depth + 1));
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
Reference in New Issue
Block a user