Skip to content

Commit 65895b6

Browse files
Merge pull request #278 from unhappychoice/feature/fix-empty-repo-panic
fix: prevent panic when selecting difficulty with no challenges
2 parents d311bf6 + f3c95e0 commit 65895b6

File tree

2 files changed

+44
-11
lines changed

2 files changed

+44
-11
lines changed

src/presentation/game/screens/title_screen.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub struct TitleScreen {
3333
git_repository: Option<GitRepository>,
3434
action_result: Option<TitleAction>,
3535
needs_render: bool,
36+
error_message: Option<String>,
3637
}
3738

3839
impl Default for TitleScreen {
@@ -49,6 +50,7 @@ impl TitleScreen {
4950
git_repository: None,
5051
action_result: None,
5152
needs_render: true,
53+
error_message: None,
5254
}
5355
}
5456

@@ -77,6 +79,10 @@ impl TitleScreen {
7779
pub fn set_git_repository(&mut self, repo: Option<GitRepository>) {
7880
self.git_repository = repo;
7981
}
82+
83+
pub fn get_error_message(&self) -> Option<&String> {
84+
self.error_message.as_ref()
85+
}
8086
}
8187

8288
impl Screen for TitleScreen {
@@ -96,21 +102,33 @@ impl Screen for TitleScreen {
96102
fn handle_key_event(&mut self, key_event: KeyEvent) -> Result<ScreenTransition> {
97103
match key_event.code {
98104
KeyCode::Char(' ') => {
99-
self.action_result =
100-
Some(TitleAction::Start(DIFFICULTIES[self.selected_difficulty].1));
101-
Ok(ScreenTransition::Replace(ScreenType::Typing))
105+
// Check if challenges are available for the selected difficulty
106+
if self.challenge_counts[self.selected_difficulty] == 0 {
107+
self.error_message = Some(
108+
"No challenges available for this difficulty. Please try a different difficulty or repository.".to_string()
109+
);
110+
self.needs_render = true;
111+
Ok(ScreenTransition::None)
112+
} else {
113+
self.error_message = None;
114+
self.action_result =
115+
Some(TitleAction::Start(DIFFICULTIES[self.selected_difficulty].1));
116+
Ok(ScreenTransition::Replace(ScreenType::Typing))
117+
}
102118
}
103119
KeyCode::Left | KeyCode::Char('h') => {
104120
self.selected_difficulty = if self.selected_difficulty == 0 {
105121
DIFFICULTIES.len() - 1
106122
} else {
107123
self.selected_difficulty - 1
108124
};
125+
self.error_message = None;
109126
self.needs_render = true;
110127
Ok(ScreenTransition::None)
111128
}
112129
KeyCode::Right | KeyCode::Char('l') => {
113130
self.selected_difficulty = (self.selected_difficulty + 1) % DIFFICULTIES.len();
131+
self.error_message = None;
114132
self.needs_render = true;
115133
Ok(ScreenTransition::None)
116134
}
@@ -163,6 +181,7 @@ impl Screen for TitleScreen {
163181
difficulties_array,
164182
self.selected_difficulty,
165183
&self.challenge_counts,
184+
self.error_message.as_ref(),
166185
)?;
167186

168187
Ok(())

src/presentation/game/views/title/difficulty_selection_view.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ impl DifficultySelectionView {
1818
difficulties: &[(&str, DifficultyLevel); 5],
1919
selected_difficulty: usize,
2020
challenge_counts: &[usize; 5],
21+
error_message: Option<&String>,
2122
) -> Result<()> {
2223
let start_row = center_row + 1;
2324
let (name, difficulty_level) = &difficulties[selected_difficulty];
@@ -75,18 +76,31 @@ impl DifficultySelectionView {
7576
execute!(stdout, Print(count_text))?;
7677
execute!(stdout, ResetColor)?;
7778

78-
// Line 3 & 4: Description lines
79-
let descriptions = [difficulty_level.description(), difficulty_level.subtitle()];
80-
for (i, description) in descriptions.iter().enumerate() {
81-
let desc_col = center_col.saturating_sub(description.chars().count() as u16 / 2);
82-
execute!(stdout, MoveTo(desc_col, start_row + 2 + i as u16))?;
79+
// Line 3 & 4: Description lines or error message
80+
if let Some(error) = error_message {
81+
// Display error message in red
82+
let error_col = center_col.saturating_sub(error.chars().count() as u16 / 2);
83+
execute!(stdout, MoveTo(error_col, start_row + 2))?;
8384
execute!(
8485
stdout,
85-
SetForegroundColor(Colors::to_crossterm(Colors::text())),
86-
SetAttribute(Attribute::Dim)
86+
SetForegroundColor(Colors::to_crossterm(Colors::error())),
87+
SetAttribute(Attribute::Bold)
8788
)?;
88-
execute!(stdout, Print(description))?;
89+
execute!(stdout, Print(error))?;
8990
execute!(stdout, ResetColor)?;
91+
} else {
92+
let descriptions = [difficulty_level.description(), difficulty_level.subtitle()];
93+
for (i, description) in descriptions.iter().enumerate() {
94+
let desc_col = center_col.saturating_sub(description.chars().count() as u16 / 2);
95+
execute!(stdout, MoveTo(desc_col, start_row + 2 + i as u16))?;
96+
execute!(
97+
stdout,
98+
SetForegroundColor(Colors::to_crossterm(Colors::text())),
99+
SetAttribute(Attribute::Dim)
100+
)?;
101+
execute!(stdout, Print(description))?;
102+
execute!(stdout, ResetColor)?;
103+
}
90104
}
91105

92106
Ok(())

0 commit comments

Comments
 (0)