Public Access
Launcher: a grid of icons, with badges; the list stays as a Setting
The Launcher shows the Apps as a 4 x 3 grid of 32 x 32 icons, the selected one's name under it (issue #9). The icons are the website's own, doubled, and two drawn the same way for SSH and the Shell; they are PNGs in assets/icons, turned into arrays by scripts/make_icons.py, which CI checks. The selected tile is the website's: dark blue on cyan, with notched corners. - GridModel (lib/ui, host-tested) holds the selection and the scrolling. - App::badge(): a dot on the tile for unread IRC messages, a Track recording, a Capture running, an SSH session open. - Settings > Launcher: Grid or List. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0162FokPdvY2KsS4NBfwyWPk
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
#include <unity.h>
|
||||
|
||||
#include "grid_model.h"
|
||||
|
||||
using namespace roro;
|
||||
|
||||
void setUp() {}
|
||||
void tearDown() {}
|
||||
|
||||
void test_empty_grid_has_no_selection() {
|
||||
GridModel g(4, 3);
|
||||
TEST_ASSERT_EQUAL(-1, g.selected());
|
||||
g.right();
|
||||
g.down();
|
||||
TEST_ASSERT_EQUAL(-1, g.selected());
|
||||
TEST_ASSERT_EQUAL(0, g.rows());
|
||||
}
|
||||
|
||||
void test_left_and_right_go_through_every_item() {
|
||||
GridModel g(4, 3);
|
||||
g.setCount(11);
|
||||
TEST_ASSERT_EQUAL(0, g.selected());
|
||||
g.right();
|
||||
TEST_ASSERT_EQUAL(1, g.selected());
|
||||
g.select(3);
|
||||
g.right(); // onto the next row
|
||||
TEST_ASSERT_EQUAL(4, g.selected());
|
||||
g.left();
|
||||
TEST_ASSERT_EQUAL(3, g.selected());
|
||||
g.select(10);
|
||||
g.right(); // around
|
||||
TEST_ASSERT_EQUAL(0, g.selected());
|
||||
g.left();
|
||||
TEST_ASSERT_EQUAL(10, g.selected());
|
||||
}
|
||||
|
||||
void test_up_and_down_stay_in_the_column() {
|
||||
GridModel g(4, 3);
|
||||
g.setCount(11); // rows of 4, 4 and 3
|
||||
g.select(1);
|
||||
g.down();
|
||||
TEST_ASSERT_EQUAL(5, g.selected());
|
||||
g.down();
|
||||
TEST_ASSERT_EQUAL(9, g.selected());
|
||||
g.down(); // around
|
||||
TEST_ASSERT_EQUAL(1, g.selected());
|
||||
g.up();
|
||||
TEST_ASSERT_EQUAL(9, g.selected());
|
||||
}
|
||||
|
||||
void test_a_short_last_row_gives_its_last_item() {
|
||||
GridModel g(4, 3);
|
||||
g.setCount(11);
|
||||
g.select(7); // the fourth column, which the last row doesn't have
|
||||
g.down();
|
||||
TEST_ASSERT_EQUAL(10, g.selected());
|
||||
g.select(3);
|
||||
g.up();
|
||||
TEST_ASSERT_EQUAL(10, g.selected());
|
||||
}
|
||||
|
||||
void test_rows_scroll_to_keep_the_selection_in_view() {
|
||||
GridModel g(4, 3);
|
||||
g.setCount(18); // 5 rows
|
||||
TEST_ASSERT_EQUAL(5, g.rows());
|
||||
TEST_ASSERT_EQUAL(0, g.firstVisibleRow());
|
||||
g.select(12); // the fourth row
|
||||
TEST_ASSERT_EQUAL(1, g.firstVisibleRow());
|
||||
g.select(17);
|
||||
TEST_ASSERT_EQUAL(2, g.firstVisibleRow());
|
||||
g.select(5);
|
||||
TEST_ASSERT_EQUAL(1, g.firstVisibleRow());
|
||||
g.select(0);
|
||||
TEST_ASSERT_EQUAL(0, g.firstVisibleRow());
|
||||
}
|
||||
|
||||
void test_a_smaller_count_keeps_the_selection_inside() {
|
||||
GridModel g(4, 3);
|
||||
g.setCount(18);
|
||||
g.select(17);
|
||||
g.setCount(6);
|
||||
TEST_ASSERT_EQUAL(5, g.selected());
|
||||
TEST_ASSERT_EQUAL(0, g.firstVisibleRow());
|
||||
g.setCount(0);
|
||||
TEST_ASSERT_EQUAL(-1, g.selected());
|
||||
}
|
||||
|
||||
int main() {
|
||||
UNITY_BEGIN();
|
||||
RUN_TEST(test_empty_grid_has_no_selection);
|
||||
RUN_TEST(test_left_and_right_go_through_every_item);
|
||||
RUN_TEST(test_up_and_down_stay_in_the_column);
|
||||
RUN_TEST(test_a_short_last_row_gives_its_last_item);
|
||||
RUN_TEST(test_rows_scroll_to_keep_the_selection_in_view);
|
||||
RUN_TEST(test_a_smaller_count_keeps_the_selection_inside);
|
||||
return UNITY_END();
|
||||
}
|
||||
@@ -46,6 +46,15 @@ void test_toggle_rows_flip_on_select() {
|
||||
TEST_ASSERT_FALSE(f.settings.getBool(Setting::Sound));
|
||||
}
|
||||
|
||||
void test_the_launcher_is_a_grid_or_a_list() {
|
||||
Fixture f;
|
||||
int launcher = f.row(SettingsMenu::Row::Launcher);
|
||||
TEST_ASSERT_EQUAL_STRING("Grid", f.menu.value(launcher).c_str());
|
||||
f.menu.toggle(launcher);
|
||||
TEST_ASSERT_TRUE(f.settings.getBool(Setting::LauncherList));
|
||||
TEST_ASSERT_EQUAL_STRING("List", f.menu.value(launcher).c_str());
|
||||
}
|
||||
|
||||
void test_choice_rows_list_options_and_mark_the_current_one() {
|
||||
Fixture f;
|
||||
int tz = f.row(SettingsMenu::Row::Timezone);
|
||||
@@ -161,6 +170,7 @@ int main() {
|
||||
RUN_TEST(test_every_row_has_a_label);
|
||||
RUN_TEST(test_values_are_human_readable);
|
||||
RUN_TEST(test_toggle_rows_flip_on_select);
|
||||
RUN_TEST(test_the_launcher_is_a_grid_or_a_list);
|
||||
RUN_TEST(test_choice_rows_list_options_and_mark_the_current_one);
|
||||
RUN_TEST(test_choosing_applies_the_setting);
|
||||
RUN_TEST(test_choice_that_breaks_a_rule_is_refused_with_a_reason);
|
||||
|
||||
Reference in New Issue
Block a user