From cbbe76526c7462e4758b4d307b90d39c7935da28 Mon Sep 17 00:00:00 2001 From: nots1dd Date: Sun, 12 Jan 2025 22:35:58 +0530 Subject: [PATCH] [MED] ALPHA 1.7 --- CHANGELOG.md | 31 ++++++++ src/dbus/mpris-service.hpp | 29 +++---- src/main.cpp | 2 + src/parser/examples/config.toml | 41 ++++++++-- src/signal/signalHandler.hpp | 68 +++++++++++++++++ src/ui/colors.hpp | 28 +++++-- src/ui/misc.hpp | 41 ++++++++-- src/ui/thread_manager.hpp | 69 +++++++++++++++++ src/ui/ui_handler.hpp | 129 +++++++++++++++----------------- 9 files changed, 336 insertions(+), 102 deletions(-) create mode 100644 src/signal/signalHandler.hpp create mode 100644 src/ui/thread_manager.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c6cb8d..7ad8785 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -559,3 +559,34 @@ Weird commit that sets up for better and more transparent way of understanding t - Runtime errors with respect to `PlayCurrentSong()` that may be due to detaching the audio thread --- + +## [ALPHA 1.7] --- 13-01-2025 + +### Added +- `src/ui/thread_manager.hpp` -> To handle concurrency in UI with testing + doxygen docs setup + +- A LOT of new color fields to `config.toml` (Check it out) with subsequent integration in `src/ui/colors.hpp` and `src/ui/ui_handler.hpp` + +- Some object deletion and freeing when calling MPRISService destructor + +- `src/signal` -> To catch all signals and handle gracefully (**FULL INTEGRATION NOT DONE YET**) + +- Some changes to format lyrics function and added ComponentState in `src/ui/misc.hpp` to keep track of all components of UI together + +### Changed +- Added more functions in misc.hpp to refactor code in ui_handler + +### Fixed +- Finally fixed scrolling lyrics menu issue, now it completely works with testing + +- Weird issue with deletion of song from queue is fully fixed with testing + +### Removed +**NIL** + +Sizeable commit with refactoring and more configuration options as its priority, more such commits expected in future + +### Known Issues to fix in immediate commits +- Runtime errors with respect to `PlayCurrentSong()` that may be due to detaching the audio thread + +--- diff --git a/src/dbus/mpris-service.hpp b/src/dbus/mpris-service.hpp index 77e67cb..ec8a7d4 100644 --- a/src/dbus/mpris-service.hpp +++ b/src/dbus/mpris-service.hpp @@ -147,19 +147,22 @@ class MPRISService ~MPRISService() { - if (connection_) - { - g_object_unref(connection_); - } - if (introspection_data_) - { - g_dbus_node_info_unref(introspection_data_); - } - if (current_metadata_) - { - g_variant_unref(current_metadata_); - } - std::cout << "-- MPRISService cleaned up." << std::endl; + if (connection_) + { + g_object_unref(connection_); + connection_ = nullptr; + } + if (introspection_data_) + { + g_dbus_node_info_unref(introspection_data_); + introspection_data_ = nullptr; + } + if (current_metadata_) + { + g_variant_unref(current_metadata_); + current_metadata_ = nullptr; + } + std::cout << "-- MPRISService cleaned up." << std::endl; } /** diff --git a/src/main.cpp b/src/main.cpp index 42112cc..40486d6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,12 @@ #include "dirsort/inode_mapper.hpp" #include "ui/ui_handler.hpp" +#include "signal/signalHandler.hpp" #include #include int main(int argc, char* argv[]) { + SignalHandler::getInstance().setup(); string directoryPath = string(parseTOMLField(PARENT_LIB, PARENT_LIB_FIELD_DIR)); string libSyncPath = getConfigPath(LIB_SYNC_NAME); RedBlackTree rbt; diff --git a/src/parser/examples/config.toml b/src/parser/examples/config.toml index 1b6b668..00d1988 100644 --- a/src/parser/examples/config.toml +++ b/src/parser/examples/config.toml @@ -46,11 +46,36 @@ view_song_queue = "3" # Colors format: Solid Colors and Hexadecimal values of format `#RRGGBB` [colors] -active_win_color = "Blue" -inactive_win_color = "#282828" -album_name_bg = "LightPink" -menu_cursor_bg = "LightYellow" -artists_title_bg = "#458586" -artists_title_fg = "#E9DDB5" -songs_title_bg = "#D7981E" -songs_title_fg = "#E9DDB5" +# Window Border Colors +active_win_border_color = "#D65D0E" # Orange for active borders +inactive_win_border_color = "#3C3836" # Dark grey for inactive borders + +# Album Section +album_name_bg = "#83A598" # Muted cyan for background + +# Menu Cursor +menu_cursor_bg = "#8EC07C" # Soft green for cursor background + +# Artists Title Section +artists_title_bg = "#458588" # Deep teal for background +artists_title_fg = "#EBDBB2" # Gruvbox light for foreground + +# Songs Title Section +songs_title_bg = "#D79921" # Warm yellow for background +songs_title_fg = "#EBDBB2" # Gruvbox light for foreground + +# Song Queue Menu +song_queue_menu_bor_col = "#B16286" # Muted magenta for border +song_queue_menu_fg = "#D3869B" # Soft pink for foreground + +# Progress Bar +progress_bar_playing_col = "#83A598" # Cyan for playing state +progress_bar_not_playing_col = "#FABD2F" # Bright yellow for not playing state + +# Volume Bar +volume_bar_col = "#8EC07C" # Soft green for volume bar + +# Status Bar +status_bar_bg = "#504945" # Dark gray for background +status_bar_artist_col = "#FB4934" # Bright red for artist name +status_bar_song_col = "#FABD2F" # Bright yellow for song name diff --git a/src/signal/signalHandler.hpp b/src/signal/signalHandler.hpp new file mode 100644 index 0000000..0092f06 --- /dev/null +++ b/src/signal/signalHandler.hpp @@ -0,0 +1,68 @@ +#ifndef SIGNAL_HANDLER_HPP +#define SIGNAL_HANDLER_HPP + +#include +#include +#include +#include +#include +#include + +class SignalHandler { +public: + // Singleton instance getter + static SignalHandler& getInstance() { + static SignalHandler instance; + return instance; + } + + // Initialize the signal handler + void setup() { + struct sigaction sa; + sa.sa_sigaction = SignalHandler::handleSignal; // Use static member function + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; // Use siginfo_t for extended info + + sigaction(SIGABRT, &sa, nullptr); // Catch SIGABRT + sigaction(SIGSEGV, &sa, nullptr); // Catch SIGSEGV + } + +private: + SignalHandler() = default; // Private constructor for singleton + ~SignalHandler() = default; + + // Non-copyable and non-movable + SignalHandler(const SignalHandler&) = delete; + SignalHandler& operator=(const SignalHandler&) = delete; + + // Signal handling function + static void handleSignal(int signal, siginfo_t* info, void* context) { + const char* signalName = nullptr; + switch (signal) { + case SIGABRT: signalName = "SIGABRT"; break; + case SIGSEGV: signalName = "SIGSEGV"; break; + default: signalName = "Unknown"; break; + } + + std::cerr << "\n=== Signal Caught ===\n"; + std::cerr << "Signal: " << signalName << " (" << signal << ")\n"; + if (info) { + std::cerr << "Address causing signal: " << info->si_addr << "\n"; + } + + // Generate a backtrace + void* buffer[128]; + int size = backtrace(buffer, 128); + std::cerr << "Backtrace (" << size << " frames):\n"; + char** symbols = backtrace_symbols(buffer, size); + for (int i = 0; i < size; ++i) { + std::cerr << symbols[i] << '\n'; + } + free(symbols); + + // Clean termination + _Exit(EXIT_FAILURE); + } +}; + +#endif diff --git a/src/ui/colors.hpp b/src/ui/colors.hpp index 225ff1a..ba65560 100644 --- a/src/ui/colors.hpp +++ b/src/ui/colors.hpp @@ -182,14 +182,22 @@ ftxui::Color GetColor(Color color) struct InLimboColors { - ftxui::Color active_win_color; - ftxui::Color inactive_win_color; + ftxui::Color active_win_border_color; + ftxui::Color inactive_win_border_color; ftxui::Color album_name_bg; ftxui::Color menu_cursor_bg; ftxui::Color artists_title_bg; ftxui::Color artists_title_fg; ftxui::Color songs_title_bg; ftxui::Color songs_title_fg; + ftxui::Color song_queue_menu_bor_col; + ftxui::Color song_queue_menu_fg; + ftxui::Color progress_bar_playing_col; + ftxui::Color progress_bar_not_playing_col; + ftxui::Color volume_bar_col; + ftxui::Color status_bar_bg; + ftxui::Color status_bar_artist_col; + ftxui::Color status_bar_song_col; }; /** @@ -302,14 +310,24 @@ InLimboColors parseColors() // Mapping of fields in the InLimboColors struct const std::unordered_map field_map = { - {"active_win_color", &colors.active_win_color}, - {"inactive_win_color", &colors.inactive_win_color}, + {"active_win_border_color", &colors.active_win_border_color}, + {"inactive_win_border_color", &colors.inactive_win_border_color}, {"album_name_bg", &colors.album_name_bg}, {"menu_cursor_bg", &colors.menu_cursor_bg}, {"artists_title_bg", &colors.artists_title_bg}, {"artists_title_fg", &colors.artists_title_fg}, {"songs_title_bg", &colors.songs_title_bg}, - {"songs_title_fg", &colors.songs_title_fg}}; + {"songs_title_fg", &colors.songs_title_fg}, + {"song_queue_menu_bor_col", &colors.song_queue_menu_bor_col}, + {"song_queue_menu_fg", &colors.song_queue_menu_fg}, + {"progress_bar_playing_col", &colors.progress_bar_playing_col}, + {"progress_bar_not_playing_col", &colors.progress_bar_not_playing_col}, + {"volume_bar_col", &colors.volume_bar_col}, + {"status_bar_bg", &colors.status_bar_bg}, + {"status_bar_artist_col", &colors.status_bar_artist_col}, + {"status_bar_song_col", &colors.status_bar_song_col}, + + }; for (const auto& [field, member_color] : field_map) { diff --git a/src/ui/misc.hpp b/src/ui/misc.hpp index 82f8797..ac630d8 100644 --- a/src/ui/misc.hpp +++ b/src/ui/misc.hpp @@ -12,37 +12,55 @@ #include #include +struct ComponentState +{ + Component artists_list; + Component songs_list; + Component songs_queue_comp; + Component lyrics_scroller; + Component MainRenderer; +}; + std::vector formatLyrics(const std::string& lyrics) { std::vector lines; std::string currentLine; - bool insideBrackets = false; + bool insideSquareBrackets = false; + bool insideCurlBrackets = false; bool lastWasUppercase = false; bool lastWasSpecialChar = false; // Tracks special characters within words char previousChar = '\0'; for (char c : lyrics) { - if (c == '[') + if (c == '[' || c == '(') { if (!currentLine.empty()) { lines.push_back(currentLine); currentLine.clear(); } - insideBrackets = true; + if (c == '[') insideSquareBrackets = true; + else insideCurlBrackets = true; currentLine += c; continue; } - if (insideBrackets) + if (insideSquareBrackets || insideCurlBrackets) { currentLine += c; - if (c == ']') + if (c == ']' && insideSquareBrackets) + { + lines.push_back(currentLine); + currentLine.clear(); + insideSquareBrackets = false; + } + + else if (c == ')' && insideCurlBrackets) { lines.push_back(currentLine); currentLine.clear(); - insideBrackets = false; + insideCurlBrackets = false; } continue; } @@ -142,6 +160,15 @@ Element renderSongName(const std::string& disc_track_info, const std::string& so text(FormatTime(duration)) | align_right}); } +Component CreateMenu(const std::vector* vecLines, int *currLine) +{ + MenuOption menu_options; + menu_options.on_change = [&]() {}; + menu_options.focused_entry = currLine; + + return Menu(vecLines, currLine, menu_options); +} + // TODO: Make Song Menu dynamically scrollable auto RenderSongMenu(const std::vector& items, int* selected_index, ftxui::Color sel_color) { @@ -153,7 +180,7 @@ auto RenderSongMenu(const std::vector& items, int* selected_index, ftxu auto style = is_selected ? color(sel_color) : nothing; auto inverted_style = is_selected ? inverted : nothing; /*auto playing_style = is_playing ? getTrueColor(playing_color) : nothing;*/ - rendered_items.push_back(items[i] | style | inverted_style); + rendered_items.push_back(items[i] | style | inverted_style | frame); } return vbox(std::move(rendered_items)); diff --git a/src/ui/thread_manager.hpp b/src/ui/thread_manager.hpp new file mode 100644 index 0000000..dd11585 --- /dev/null +++ b/src/ui/thread_manager.hpp @@ -0,0 +1,69 @@ +/** + * @file ThreadManager.hpp + * @brief Declaration of the ThreadManager class for managing threads and their states. + */ + +#ifndef THREAD_MANAGER_HPP +#define THREAD_MANAGER_HPP + +#include +#include +#include +#include + +/** + * @class ThreadManager + * @brief A class that manages thread states and provides utilities for thread handling. + */ +class ThreadManager { +public: + /** + * @struct ThreadState + * @brief Represents the state of a thread managed by ThreadManager. + */ + struct ThreadState { + /** + * @brief A mutex to synchronize access to the play state. + */ + std::mutex play_mutex; + + /** + * @brief Indicates whether the thread is currently processing. + */ + std::atomic is_processing{false}; + + /** + * @brief Indicates whether the thread is currently playing. + */ + std::atomic is_playing{false}; + + /** + * @brief A future object associated with the play operation. + */ + std::future play_future; + }; + + /** + * @brief Retrieves the thread state managed by this ThreadManager. + * @return A reference to the thread state. + */ + ThreadState& getThreadState() { return thread_state; } + + /** + * @brief Locks the play mutex for the provided thread state. + * + * This function uses a unique lock to ensure that the play mutex + * is safely locked while performing operations on the thread state. + * + * @param thread_state A reference to the ThreadState object whose mutex is to be locked. + */ + void lockPlayMutex(ThreadState& thread_state) { std::unique_lock lock(thread_state.play_mutex); } + +private: + /** + * @brief The thread state managed by this instance of ThreadManager. + */ + ThreadState thread_state; +}; + +#endif // THREAD_MANAGER_HPP diff --git a/src/ui/ui_handler.hpp b/src/ui/ui_handler.hpp index f5a13de..d258a30 100644 --- a/src/ui/ui_handler.hpp +++ b/src/ui/ui_handler.hpp @@ -6,8 +6,8 @@ #include "keymaps.hpp" #include "misc.hpp" #include "../dbus/mpris-service.hpp" +#include "./thread_manager.hpp" #include -#include #include #include #include @@ -47,7 +47,9 @@ class MusicPlayer const std::map>>>& initial_library) - : library(initial_library) + : library(initial_library), + INL_Thread_Manager(std::make_unique()), + INL_Thread_State(INL_Thread_Manager->getThreadState()) { InitializeData(); CreateComponents(); @@ -82,7 +84,7 @@ class MusicPlayer std::this_thread::sleep_for(0.1s); - if (is_playing) + if (INL_Thread_State.is_playing) { current_position += 0.1; if (current_position >= GetCurrentSongDuration()) @@ -125,7 +127,7 @@ class MusicPlayer try { - screen.Loop(renderer); + screen.Loop(INL_Component_State.MainRenderer); } catch (const std::exception& e) { @@ -165,12 +167,8 @@ class MusicPlayer InLimboColors global_colors = parseColors(); std::unique_ptr audio_player; - std::mutex play_mutex; - std::atomic is_processing{false}; - std::atomic is_playing{false}; - std::future play_future; - std::atomic is_thread_running{false}; - std::thread audio_thread; + std::unique_ptr INL_Thread_Manager; // Smart pointer to ThreadManager + ThreadManager::ThreadState& INL_Thread_State; std::vector song_queue; int current_song_queue_index = 0; @@ -214,12 +212,7 @@ class MusicPlayer ScreenInteractive* screen_ = nullptr; // UI Components - Component artists_list; - Component songs_list; - Component songs_queue_comp; - Component scroller; - Component lyrics_scroller; - Component renderer; + ComponentState INL_Component_State; void InitializeData() { @@ -244,22 +237,22 @@ class MusicPlayer void PlayCurrentSong() { { - std::unique_lock lock(play_mutex); - if (is_processing) + INL_Thread_Manager->lockPlayMutex(INL_Thread_State); + if (INL_Thread_State.is_processing) { return; // Another invocation is already running } - is_processing = true; + INL_Thread_State.is_processing = true; } - play_future = + INL_Thread_State.play_future = std::async(std::launch::async, [this]() { try { { - std::unique_lock lock(play_mutex); + INL_Thread_Manager->lockPlayMutex(INL_Thread_State); if (!audio_player) { audio_player = std::make_unique(); @@ -279,11 +272,11 @@ class MusicPlayer } { - std::unique_lock lock(play_mutex); - if (is_playing) + INL_Thread_Manager->lockPlayMutex(INL_Thread_State); + if (INL_Thread_State.is_playing) { audio_player->stop(); // Stop the current song if playing - is_playing = false; + INL_Thread_State.is_playing = false; } } @@ -295,31 +288,31 @@ class MusicPlayer } { - std::unique_lock lock(play_mutex); - is_playing = true; + INL_Thread_Manager->lockPlayMutex(INL_Thread_State); + INL_Thread_State.is_playing = true; } audio_player->play(); // Play the song (it will play in a separate thread) current_playing_state.duration = audio_player->getDuration(); { - std::unique_lock lock(play_mutex); + INL_Thread_Manager->lockPlayMutex(INL_Thread_State); // Simulate setting duration or other playback state } } catch (const std::exception& e) { { - std::unique_lock lock(play_mutex); + INL_Thread_Manager->lockPlayMutex(INL_Thread_State); show_dialog = true; dialog_message = e.what(); - is_playing = false; + INL_Thread_State.is_playing = false; } } { - std::unique_lock lock(play_mutex); - is_processing = false; + INL_Thread_Manager->lockPlayMutex(INL_Thread_State); + INL_Thread_State.is_processing = false; } }); } @@ -329,10 +322,10 @@ class MusicPlayer if (!audio_player) return; - if (is_playing) + if (INL_Thread_State.is_playing) { audio_player->pause(); - is_playing = false; + INL_Thread_State.is_playing = false; } else { @@ -345,7 +338,7 @@ class MusicPlayer PlayCurrentSong(); UpdatePlayingState(); } - is_playing = true; + INL_Thread_State.is_playing = true; } } @@ -561,7 +554,7 @@ class MusicPlayer void RemoveSongFromQueue() { - if (selected_song_queue == current_song_queue_index) + if (selected_song_queue == 0) { dialog_message = "Unable to remove song... This is playing right now!"; show_dialog = true; @@ -627,6 +620,8 @@ class MusicPlayer const std::string& mprisSongGenre = current_playing_state.genre; mprisService->updateMetadata(mprisSongTitle, mprisSongArtist, mprisSongAlbum, static_cast(GetCurrentSongFromQueue()->metadata.duration), mprisSongComment, mprisSongGenre, current_playing_state.track, current_playing_state.discNumber); + + current_lyric_line = 0; } void CreateComponents() @@ -645,15 +640,15 @@ class MusicPlayer song_menu_options.on_change = [&]() {}; song_menu_options.focused_entry = &selected_inode; - artists_list = Menu(¤t_artist_names, &selected_artist, artist_menu_options); - songs_list = Renderer( + INL_Component_State.artists_list = Menu(¤t_artist_names, &selected_artist, artist_menu_options); + INL_Component_State.songs_list = Renderer( [&]() mutable { return RenderSongMenu(current_song_elements, &selected_inode, global_colors.menu_cursor_bg); // This should return an Element }); - auto main_container = Container::Horizontal({artists_list, songs_list}); + auto main_container = Container::Horizontal({INL_Component_State.artists_list, INL_Component_State.songs_list}); /* Adding DEBOUNCE TIME (Invoking PlayCurrentSong() too fast causes resources to not be freed) */ @@ -950,11 +945,11 @@ class MusicPlayer focus_on_artists = !focus_on_artists; if (focus_on_artists) { - artists_list->TakeFocus(); + INL_Component_State.artists_list->TakeFocus(); } else { - songs_list->TakeFocus(); + INL_Component_State.songs_list->TakeFocus(); } return true; } @@ -992,7 +987,7 @@ class MusicPlayer return false; }); - renderer = + INL_Component_State.MainRenderer = Renderer(main_container, [&] { @@ -1067,10 +1062,7 @@ class MusicPlayer } } - MenuOption lyrics_menu_options; - lyrics_menu_options.on_change = [&]() {}; - lyrics_menu_options.focused_entry = ¤t_lyric_line; - lyrics_scroller = Menu(&lyricLines, ¤t_lyric_line, lyrics_menu_options); + INL_Component_State.lyrics_scroller = CreateMenu(&lyricLines, ¤t_lyric_line); UpdateLyrics(); @@ -1079,7 +1071,7 @@ class MusicPlayer "' to go back home."; auto lyrics_pane = vbox({ - lyrics_scroller->Render() | flex, + INL_Component_State.lyrics_scroller->Render() | flex, }); auto info_pane = window(text(" Additional Info ") | bold | center | inverted, @@ -1087,9 +1079,9 @@ class MusicPlayer return hbox({ vbox({ - lyrics_pane | flex | border, + lyrics_pane | frame | flex | border, separator(), - text(end_text) | dim | center, + text(end_text) | dim | center | border, }) | flex, vbox({info_pane}) | flex }) | flex; @@ -1112,10 +1104,7 @@ class MusicPlayer Element RenderQueueScreen() { - MenuOption song_queue_comp_options; - song_queue_comp_options.on_change = [&]() {}; - song_queue_comp_options.focused_entry = &selected_song_queue; - songs_queue_comp = Menu(&song_queue_names, &selected_song_queue, song_queue_comp_options); + INL_Component_State.songs_queue_comp = CreateMenu(&song_queue_names, &selected_song_queue); UpdateSongQueueList(); auto title = text(" Song Queue ") | bold | getTrueColor(TrueColors::Color::LightBlue) | @@ -1124,17 +1113,17 @@ class MusicPlayer auto separator_line = separator() | dim | flex; std::string end_text = "Use '" + charToStr(global_keybinds.remove_song_from_queue) + "' to remove selected song from queue, Press '" + - std::string(1, static_cast(global_keybinds.goto_main_screen)) + + charToStr(global_keybinds.goto_main_screen) + "' to go back home."; auto queue_container = vbox({ - songs_queue_comp->Render() | border | flex | getTrueColor(TrueColors::Color::LightGray), - separator(), - }); + INL_Component_State.songs_queue_comp->Render() | color(global_colors.song_queue_menu_fg) | flex, + }) | border | color(global_colors.song_queue_menu_bor_col); return vbox({ title, queue_container | frame | flex, + separator(), text(end_text) | dim | center, }) | flex; } @@ -1340,6 +1329,8 @@ class MusicPlayer TrueColors::Color::Cyan), createRow(charToStr(global_keybinds.add_song_to_queue), "Add song to queue", TrueColors::Color::LightPink), + createRow(charToStr(global_keybinds.add_song_to_queue), "Remove song from queue", + TrueColors::Color::Teal), createRow(charToStr(global_keybinds.goto_main_screen), "Go to song tree view", TrueColors::Color::Teal), }) | @@ -1369,7 +1360,7 @@ class MusicPlayer Color GetCurrWinColor(bool focused) { - return focused ? global_colors.active_win_color : global_colors.inactive_win_color; + return focused ? global_colors.active_win_border_color : global_colors.inactive_win_border_color; } Element RenderMainInterface(float progress) @@ -1399,13 +1390,13 @@ class MusicPlayer additional_info += STATUS_BAR_DELIM; } - std::string status = std::string(" ") + (is_playing ? STATUS_PLAYING : STATUS_PAUSED) + " "; + std::string status = std::string(" ") + (INL_Thread_State.is_playing ? STATUS_PLAYING : STATUS_PAUSED) + " "; auto left_pane = vbox({ text(" Artists") | bold | color(global_colors.artists_title_bg) | inverted, separator(), - artists_list->Render() | frame | flex | getTrueColor(TrueColors::Color::White), + INL_Component_State.artists_list->Render() | frame | flex | getTrueColor(TrueColors::Color::White), }) | borderHeavy | color(GetCurrWinColor(focus_on_artists)); @@ -1413,7 +1404,7 @@ class MusicPlayer vbox({ text(" Songs") | bold | color(global_colors.songs_title_bg) | inverted, separator(), - songs_list->Render() | frame | flex | getTrueColor(TrueColors::Color::White), + INL_Component_State.songs_list->Render() | frame | flex | getTrueColor(TrueColors::Color::White), }) | borderHeavy | color(GetCurrWinColor(!focus_on_artists)); @@ -1424,8 +1415,8 @@ class MusicPlayer flex}) | flex; - auto progress_style = is_playing ? getTrueColor(TrueColors::Color::SlateBlue) - : getTrueColor(TrueColors::Color::Crimson); + auto progress_style = INL_Thread_State.is_playing ? color(global_colors.progress_bar_playing_col) + : color(global_colors.progress_bar_not_playing_col); auto progress_bar = hbox({ text(FormatTime((int)current_position)) | progress_style, gauge(progress) | flex | progress_style, @@ -1434,7 +1425,7 @@ class MusicPlayer auto volume_bar = hbox({ text(" Vol: ") | dim, - gauge(volume / 100.0) | size(WIDTH, EQUAL, 10) | getTrueColor(TrueColors::Color::LightYellow), + gauge(volume / 100.0) | size(WIDTH, EQUAL, 10) | color(global_colors.volume_bar_col), text(std::to_string(volume) + "%") | dim, }); @@ -1456,9 +1447,9 @@ class MusicPlayer auto status_bar = hbox({text(status) | getTrueColor(TrueColors::Color::Black), - text(current_playing_state.artist) | getTrueColor(TrueColors::Color::Gold) | bold | + text(current_playing_state.artist) | color(global_colors.status_bar_artist_col) | bold | size(WIDTH, LESS_THAN, MAX_LENGTH_ARTIST_NAME), - text(current_song_info) | bold | getTrueColor(TrueColors::Color::LightRed) | + text(current_song_info) | bold | color(global_colors.status_bar_song_col) | size(WIDTH, LESS_THAN, MAX_LENGTH_SONG_NAME), filler(), // Push the right-aligned content to the end hbox({text(additional_info) | getTrueColor(TrueColors::Color::Black) | flex, @@ -1466,7 +1457,7 @@ class MusicPlayer size(WIDTH, LESS_THAN, 15), text(" ")}) | align_right}) | - size(HEIGHT, EQUAL, 1) | getTrueBGColor(TrueColors::Color::White); + size(HEIGHT, EQUAL, 1) | bgcolor(global_colors.status_bar_bg); return vbox({ panes, @@ -1485,16 +1476,16 @@ class MusicPlayer should_quit = true; { - std::unique_lock lock(play_mutex); + std::unique_lock lock(INL_Thread_State.play_mutex); if (audio_player) { audio_player->stop(); } } - if (play_future.valid()) + if (INL_Thread_State.play_future.valid()) { - auto status = play_future.wait_for(std::chrono::seconds(1)); + auto status = INL_Thread_State.play_future.wait_for(std::chrono::seconds(1)); if (status != std::future_status::ready) { // Handle timeout - future didn't complete in time