Files
NeilClack c3b3d6774a Warning screen, smarter license re-validation, version reporting
Warning screen
- New reusable WarningPage (word-wrapped message, ENTER acknowledges and
  continues to the screen you were about to enter).
- First use: pressing Play while the selected audio is still downloading.
  Dynamic Audio requires every file; a fixed track requires its own file.

License re-validation
- No longer re-verifies on every Home render. Checks now run only when the
  email/license key is entered or changed, on the manual option, at startup
  when already due, and hourly while valid.
- Invalid + unchanged credentials are never re-checked (persisted pair).
- Valid re-checks at most once per hour, anchored on a DB timestamp so an
  overdue check runs immediately after a power cycle.
- New system_kv keys track the checked pair, outcome, and last-check time.
- Added a System Settings row "Manually Validate License Key OK|Invalid"
  (OK green, Invalid red, label white) that runs a check immediately.

Portal / local integration
- License validation request now sends the app version as `appVersion`.
- The entered license key is mirrored to ~/.local/radiantwave/license.txt.

Misc
- "Please connect to WiFi" only shows when no WiFi is joined AND the internet
  is unreachable (fixes the NetworkManager-missing and Ethernet cases).
- Added unit tests for the audio-download warning, license scheduling policy,
  license request shape, and the new settings-menu entry.
2026-10-14 10:58:40 -05:00

348 lines
11 KiB
CMake

cmake_minimum_required(VERSION 3.20)
project(RadiantWave VERSION 0.1.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# App version string shown at the top of the Home footer. Defaults to the
# project version; override at configure time with:
# cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DAPP_VERSION="1.2.3"
# or by exporting APP_VERSION in the environment (the `nix develop` shell does
# this; the env var only seeds a fresh configure, -D wins on reconfigure).
if(DEFINED ENV{APP_VERSION})
set(APP_VERSION "$ENV{APP_VERSION}" CACHE STRING
"Version string shown in the Home footer (override at configure time)")
else()
set(APP_VERSION "${PROJECT_VERSION}" CACHE STRING
"Version string shown in the Home footer (override at configure time)")
endif()
find_package(SDL3 REQUIRED)
find_package(SDL3_ttf REQUIRED)
find_package(SDL3_image REQUIRED)
find_package(SDL3_mixer REQUIRED)
find_package(SDL3_net REQUIRED)
find_package(SQLite3 REQUIRED)
find_package(CURL REQUIRED)
find_package(OpenSSL REQUIRED)
find_package(GTest REQUIRED)
include(GoogleTest)
# Network manager dependencies (Linux only)
if(UNIX AND NOT APPLE)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDBUS REQUIRED libsystemd)
endif()
add_executable(radiantwave
src/main.cpp
src/page_manager.cpp
src/home.cpp
src/settings.cpp
src/settings_menu.cpp
src/system_settings_page.cpp
src/system_name_page.cpp
src/schedule_toggle_page.cpp
src/wifi_setup_page.cpp
src/audio_settings_page.cpp
src/audio/audio_manager.cpp
src/audio/audio_downloader.cpp
src/timezone_page.cpp
src/timezone_helper.cpp
src/log_viewer_page.cpp
src/logger/logger.cpp
src/keybind_manager.cpp
src/provisioning.cpp
src/network/nm_connection.cpp
src/network/nm_device.cpp
src/network/network_manager.cpp
src/network/json.cpp
src/network/api_client.cpp
src/network/license_service.cpp
src/network/license_status.cpp
src/network/system_name.cpp
src/network/system_name_sync.cpp
src/network/schedule_cache.cpp
src/schedule/schedule_engine.cpp
src/schedule/schedule_manager.cpp
src/config/yaml_parser.cpp
src/config/config_manager.cpp
src/db/database_manager.cpp
src/network/proclamation_sync.cpp
src/proclamation_options_page.cpp
src/email_address_page.cpp
src/license_key_page.cpp
src/license_blocked_page.cpp
src/warning_page.cpp
src/validation.cpp
src/date_format.cpp
src/date_format_page.cpp
src/fibonacci_line_pattern.cpp
src/scroller_streams.cpp
src/scroller_page.cpp
src/scramble/fibonacci_scrambler.cpp
)
target_compile_definitions(radiantwave PRIVATE
APP_VERSION="${APP_VERSION}"
)
target_include_directories(radiantwave PRIVATE src)
target_link_libraries(radiantwave PRIVATE
SDL3::SDL3
SDL3_ttf::SDL3_ttf
SDL3_image::SDL3_image
SDL3_mixer::SDL3_mixer
SDL3_net::SDL3_net
SQLite3::SQLite3
CURL::libcurl
OpenSSL::Crypto
)
if(UNIX AND NOT APPLE)
target_link_libraries(radiantwave PRIVATE ${SDBUS_LIBRARIES} resolv)
target_include_directories(radiantwave PRIVATE ${SDBUS_INCLUDE_DIRS})
target_compile_definitions(radiantwave PRIVATE HAS_DBUS=1)
endif()
install(TARGETS radiantwave RUNTIME DESTINATION bin)
add_executable(tests
tests/test_page_manager.cpp
tests/test_keybind_manager.cpp
src/page_manager.cpp
src/keybind_manager.cpp
)
target_include_directories(tests PRIVATE src)
target_link_libraries(tests PRIVATE SDL3::SDL3)
# Provisioning walkthrough logic tests (pure functions, no app linkage)
add_executable(test_provisioning
tests/test_provisioning.cpp
)
target_include_directories(test_provisioning PRIVATE src)
# provisioning.h pulls in app_state.h, so the test compiles against the SDL3,
# SDL3_mixer, and SQLite headers transitively (app_state.h -> audio_manager.h ->
# SDL3_mixer; app_state.h -> database_manager.h -> sqlite3.h).
target_link_libraries(test_provisioning PRIVATE
SDL3::SDL3
SDL3_mixer::SDL3_mixer
SQLite3::SQLite3
)
add_executable(test_assets
tests/test_assets.cpp
)
target_include_directories(test_assets PRIVATE src)
# Network manager unit tests
add_executable(test_network_unit
tests/network/test_nm_connection.cpp
src/network/nm_connection.cpp
)
target_include_directories(test_network_unit PRIVATE src)
target_link_libraries(test_network_unit PRIVATE GTest::gtest_main)
# Access point parsing unit tests (pure mapping; the sd-bus reads are Linux-only)
add_executable(test_nm_device
tests/network/test_nm_device.cpp
src/network/nm_device.cpp
src/network/nm_connection.cpp
src/logger/logger.cpp
)
target_include_directories(test_nm_device PRIVATE src)
target_link_libraries(test_nm_device PRIVATE GTest::gtest_main)
if(UNIX AND NOT APPLE)
target_link_libraries(test_nm_device PRIVATE ${SDBUS_LIBRARIES})
target_include_directories(test_nm_device PRIVATE ${SDBUS_INCLUDE_DIRS})
endif()
# Config unit tests
add_executable(test_config
tests/test_config.cpp
src/config/yaml_parser.cpp
src/config/config_manager.cpp
)
target_include_directories(test_config PRIVATE src)
target_link_libraries(test_config PRIVATE GTest::gtest_main)
# Database unit tests
add_executable(test_db
tests/test_db.cpp
src/db/database_manager.cpp
)
target_include_directories(test_db PRIVATE src)
target_link_libraries(test_db PRIVATE GTest::gtest_main SQLite3::SQLite3)
# Proclamation sync unit tests
add_executable(test_proclamation_sync
tests/test_proclamation_sync.cpp
src/db/database_manager.cpp
src/network/proclamation_sync.cpp
src/network/json.cpp
src/network/api_client.cpp
)
target_include_directories(test_proclamation_sync PRIVATE src)
target_link_libraries(test_proclamation_sync PRIVATE GTest::gtest_main SQLite3::SQLite3 CURL::libcurl)
# Portal API client unit tests (offline parse tests + live-API tests)
add_executable(test_api_client
tests/test_api_client.cpp
src/network/api_client.cpp
src/network/json.cpp
src/network/proclamation_sync.cpp
src/db/database_manager.cpp
)
target_include_directories(test_api_client PRIVATE src)
target_link_libraries(test_api_client PRIVATE GTest::gtest_main CURL::libcurl SQLite3::SQLite3)
# License validation service unit tests (offline + live-API tests)
add_executable(test_license_service
tests/test_license_service.cpp
src/network/license_service.cpp
src/network/system_name.cpp
src/network/api_client.cpp
src/network/json.cpp
src/db/database_manager.cpp
src/validation.cpp
)
target_include_directories(test_license_service PRIVATE src)
target_link_libraries(test_license_service PRIVATE GTest::gtest_main CURL::libcurl SQLite3::SQLite3)
# License status tracker unit tests (offline mapping + worker lifecycle)
add_executable(test_license_status
tests/test_license_status.cpp
src/network/license_status.cpp
src/network/license_service.cpp
src/network/system_name.cpp
src/network/api_client.cpp
src/network/json.cpp
src/db/database_manager.cpp
src/validation.cpp
)
target_include_directories(test_license_status PRIVATE src)
target_link_libraries(test_license_status PRIVATE GTest::gtest_main CURL::libcurl SQLite3::SQLite3)
# Validation/format unit tests
add_executable(test_validation
tests/test_validation.cpp
src/validation.cpp
)
target_include_directories(test_validation PRIVATE src)
target_link_libraries(test_validation PRIVATE GTest::gtest_main)
# Date/time format unit tests
add_executable(test_date_format
tests/test_date_format.cpp
src/date_format.cpp
)
target_include_directories(test_date_format PRIVATE src)
target_link_libraries(test_date_format PRIVATE GTest::gtest_main)
# System Settings menu entry list (pure data, no SDL linkage)
add_executable(test_settings_menu
tests/test_settings_menu.cpp
src/settings_menu.cpp
)
target_include_directories(test_settings_menu PRIVATE src)
target_link_libraries(test_settings_menu PRIVATE GTest::gtest_main)
# System Name local state + sync logic (HTTP layer is injected/faked)
add_executable(test_system_name
tests/test_system_name.cpp
src/network/system_name.cpp
src/validation.cpp
src/db/database_manager.cpp
)
target_include_directories(test_system_name PRIVATE src)
target_link_libraries(test_system_name PRIVATE GTest::gtest_main SQLite3::SQLite3)
# Schedule engine + cache tests (payload parsing, evaluation, offline cache)
add_executable(test_schedule_engine
tests/test_schedule_engine.cpp
src/schedule/schedule_engine.cpp
src/schedule/schedule_manager.cpp
src/network/schedule_cache.cpp
src/network/api_client.cpp
src/network/json.cpp
src/db/database_manager.cpp
)
target_include_directories(test_schedule_engine PRIVATE src)
target_link_libraries(test_schedule_engine PRIVATE GTest::gtest_main CURL::libcurl SQLite3::SQLite3)
target_compile_definitions(test_schedule_engine PRIVATE
RWT_FIXTURES_DIR="${CMAKE_CURRENT_SOURCE_DIR}/docs/fixtures")
# TimeZone unit tests
add_executable(test_timezone
tests/test_timezone.cpp
src/timezone_helper.cpp
)
target_include_directories(test_timezone PRIVATE src)
target_link_libraries(test_timezone PRIVATE GTest::gtest_main)
# Logger unit tests
add_executable(test_logger
tests/test_logger.cpp
src/logger/logger.cpp
)
target_include_directories(test_logger PRIVATE src)
target_link_libraries(test_logger PRIVATE GTest::gtest_main)
# Audio unit tests
add_executable(test_audio
tests/test_audio.cpp
src/audio/audio_manager.cpp
src/db/database_manager.cpp
src/config/yaml_parser.cpp
src/config/config_manager.cpp
src/logger/logger.cpp
)
target_include_directories(test_audio PRIVATE src)
target_link_libraries(test_audio PRIVATE GTest::gtest_main SDL3_mixer::SDL3_mixer SDL3::SDL3 SQLite3::SQLite3)
# Audio downloader unit tests
add_executable(test_audio_downloader
tests/test_audio_downloader.cpp
src/audio/audio_downloader.cpp
src/db/database_manager.cpp
src/logger/logger.cpp
)
target_include_directories(test_audio_downloader PRIVATE src)
target_link_libraries(test_audio_downloader PRIVATE GTest::gtest_main CURL::libcurl OpenSSL::Crypto SQLite3::SQLite3)
# Scroller Fibonacci pattern unit tests
add_executable(test_fibonacci_pattern
tests/test_fibonacci_pattern.cpp
src/fibonacci_line_pattern.cpp
)
target_include_directories(test_fibonacci_pattern PRIVATE src)
target_link_libraries(test_fibonacci_pattern PRIVATE GTest::gtest_main)
# Scroller streams unit tests
add_executable(test_scroller_streams
tests/test_scroller_streams.cpp
src/scroller_streams.cpp
)
target_include_directories(test_scroller_streams PRIVATE src)
target_link_libraries(test_scroller_streams PRIVATE GTest::gtest_main SQLite3::SQLite3)
# Fibonacci affine image scrambler unit tests
add_executable(test_fibonacci_scrambler
tests/test_fibonacci_scrambler.cpp
src/scramble/fibonacci_scrambler.cpp
)
target_include_directories(test_fibonacci_scrambler PRIVATE src)
target_link_libraries(test_fibonacci_scrambler PRIVATE GTest::gtest_main)
# Color palette API + storage unit tests (readiness: not wired into the app yet)
add_executable(test_color_palettes
tests/test_color_palettes.cpp
src/network/api_client.cpp
src/network/json.cpp
src/network/proclamation_sync.cpp
src/db/database_manager.cpp
)
target_include_directories(test_color_palettes PRIVATE src)
target_link_libraries(test_color_palettes PRIVATE GTest::gtest_main CURL::libcurl SQLite3::SQLite3)